]>
Commit | Line | Data |
---|---|---|
4fa4267d RC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2019 Andes Technology Corporation | |
4 | * Rick Chen, Andes Technology Corporation <rick@andestech.com> | |
5 | */ | |
6 | ||
4fa4267d RC |
7 | #include <command.h> |
8 | #include <cache.h> | |
9 | #include <dm.h> | |
db41d65a | 10 | #include <hang.h> |
401d1c4f | 11 | #include <asm/global_data.h> |
4fa4267d RC |
12 | #include <asm/io.h> |
13 | #include <dm/ofnode.h> | |
cd93d625 | 14 | #include <linux/bitops.h> |
4fa4267d RC |
15 | |
16 | struct l2cache { | |
17 | volatile u64 configure; | |
18 | volatile u64 control; | |
19 | volatile u64 hpm0; | |
20 | volatile u64 hpm1; | |
21 | volatile u64 hpm2; | |
22 | volatile u64 hpm3; | |
23 | volatile u64 error_status; | |
24 | volatile u64 ecc_error; | |
25 | volatile u64 cctl_command0; | |
26 | volatile u64 cctl_access_line0; | |
27 | volatile u64 cctl_command1; | |
28 | volatile u64 cctl_access_line1; | |
29 | volatile u64 cctl_command2; | |
30 | volatile u64 cctl_access_line2; | |
31 | volatile u64 cctl_command3; | |
32 | volatile u64 cctl_access_line4; | |
33 | volatile u64 cctl_status; | |
34 | }; | |
35 | ||
51415fa6 YCPL |
36 | /* Configuration register */ |
37 | #define MEM_MAP_OFF 20 | |
38 | #define MEM_MAP_MSK BIT(MEM_MAP_OFF) | |
39 | /* offset of v0 memory map (Gen1) */ | |
40 | static u32 cmd_stride = 0x10; | |
41 | static u32 status_stride = 0x0; | |
42 | static u32 status_bit_offset = 0x4; | |
43 | ||
4fa4267d RC |
44 | /* Control Register */ |
45 | #define L2_ENABLE 0x1 | |
46 | /* prefetch */ | |
47 | #define IPREPETCH_OFF 3 | |
48 | #define DPREPETCH_OFF 5 | |
49 | #define IPREPETCH_MSK (3 << IPREPETCH_OFF) | |
50 | #define DPREPETCH_MSK (3 << DPREPETCH_OFF) | |
51 | /* tag ram */ | |
52 | #define TRAMOCTL_OFF 8 | |
53 | #define TRAMICTL_OFF 10 | |
54 | #define TRAMOCTL_MSK (3 << TRAMOCTL_OFF) | |
55 | #define TRAMICTL_MSK BIT(TRAMICTL_OFF) | |
56 | /* data ram */ | |
57 | #define DRAMOCTL_OFF 11 | |
58 | #define DRAMICTL_OFF 13 | |
59 | #define DRAMOCTL_MSK (3 << DRAMOCTL_OFF) | |
60 | #define DRAMICTL_MSK BIT(DRAMICTL_OFF) | |
61 | ||
62 | /* CCTL Command Register */ | |
51415fa6 | 63 | #define CCTL_CMD_REG(base, hart) ((ulong)(base) + 0x40 + (hart) * (cmd_stride)) |
4fa4267d RC |
64 | #define L2_WBINVAL_ALL 0x12 |
65 | ||
66 | /* CCTL Status Register */ | |
51415fa6 YCPL |
67 | #define CCTL_STATUS_REG(base, hart) ((ulong)(base) + 0x80 + (hart) * (status_stride)) |
68 | #define CCTL_STATUS_MSK(hart) (0xf << ((hart) * (status_bit_offset))) | |
69 | #define CCTL_STATUS_IDLE(hart) (0 << ((hart) * (status_bit_offset))) | |
70 | #define CCTL_STATUS_PROCESS(hart) (1 << ((hart) * (status_bit_offset))) | |
71 | #define CCTL_STATUS_ILLEGAL(hart) (2 << ((hart) * (status_bit_offset))) | |
4fa4267d RC |
72 | |
73 | DECLARE_GLOBAL_DATA_PTR; | |
74 | ||
2b8dc36b | 75 | struct andes_l2_plat { |
4fa4267d RC |
76 | struct l2cache *regs; |
77 | u32 iprefetch; | |
78 | u32 dprefetch; | |
0cf207ec WD |
79 | u32 tram_ctl[2]; |
80 | u32 dram_ctl[2]; | |
4fa4267d RC |
81 | }; |
82 | ||
2b8dc36b | 83 | static int andes_l2_enable(struct udevice *dev) |
4fa4267d | 84 | { |
2b8dc36b | 85 | struct andes_l2_plat *plat = dev_get_plat(dev); |
4fa4267d RC |
86 | volatile struct l2cache *regs = plat->regs; |
87 | ||
88 | if (regs) | |
89 | setbits_le32(®s->control, L2_ENABLE); | |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
2b8dc36b | 94 | static int andes_l2_disable(struct udevice *dev) |
4fa4267d | 95 | { |
2b8dc36b | 96 | struct andes_l2_plat *plat = dev_get_plat(dev); |
4fa4267d RC |
97 | volatile struct l2cache *regs = plat->regs; |
98 | u8 hart = gd->arch.boot_hart; | |
99 | void __iomem *cctlcmd = (void __iomem *)CCTL_CMD_REG(regs, hart); | |
100 | ||
101 | if ((regs) && (readl(®s->control) & L2_ENABLE)) { | |
102 | writel(L2_WBINVAL_ALL, cctlcmd); | |
103 | ||
104 | while ((readl(®s->cctl_status) & CCTL_STATUS_MSK(hart))) { | |
105 | if ((readl(®s->cctl_status) & CCTL_STATUS_ILLEGAL(hart))) { | |
106 | printf("L2 flush illegal! hanging..."); | |
107 | hang(); | |
108 | } | |
109 | } | |
110 | clrbits_le32(®s->control, L2_ENABLE); | |
111 | } | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
2b8dc36b | 116 | static int andes_l2_of_to_plat(struct udevice *dev) |
4fa4267d | 117 | { |
2b8dc36b | 118 | struct andes_l2_plat *plat = dev_get_plat(dev); |
4fa4267d RC |
119 | struct l2cache *regs; |
120 | ||
a12a73b6 | 121 | regs = dev_read_addr_ptr(dev); |
4fa4267d RC |
122 | plat->regs = regs; |
123 | ||
124 | plat->iprefetch = -EINVAL; | |
125 | plat->dprefetch = -EINVAL; | |
126 | plat->tram_ctl[0] = -EINVAL; | |
127 | plat->dram_ctl[0] = -EINVAL; | |
128 | ||
129 | /* Instruction and data fetch prefetch depth */ | |
130 | dev_read_u32(dev, "andes,inst-prefetch", &plat->iprefetch); | |
131 | dev_read_u32(dev, "andes,data-prefetch", &plat->dprefetch); | |
132 | ||
133 | /* Set tag RAM and data RAM setup and output cycle */ | |
134 | dev_read_u32_array(dev, "andes,tag-ram-ctl", plat->tram_ctl, 2); | |
135 | dev_read_u32_array(dev, "andes,data-ram-ctl", plat->dram_ctl, 2); | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
2b8dc36b | 140 | static int andes_l2_probe(struct udevice *dev) |
4fa4267d | 141 | { |
2b8dc36b | 142 | struct andes_l2_plat *plat = dev_get_plat(dev); |
4fa4267d | 143 | struct l2cache *regs = plat->regs; |
51415fa6 | 144 | u32 cfg_val, ctl_val; |
4fa4267d | 145 | |
51415fa6 | 146 | cfg_val = readl(®s->configure); |
4fa4267d RC |
147 | ctl_val = readl(®s->control); |
148 | ||
51415fa6 YCPL |
149 | /* If true, v1 memory map (Gen2) */ |
150 | if (cfg_val & MEM_MAP_MSK) { | |
151 | cmd_stride = 0x1000; | |
152 | status_stride = 0x1000; | |
153 | status_bit_offset = 0x0; | |
154 | } | |
155 | ||
156 | ctl_val |= L2_ENABLE; | |
4fa4267d RC |
157 | |
158 | if (plat->iprefetch != -EINVAL) { | |
159 | ctl_val &= ~(IPREPETCH_MSK); | |
160 | ctl_val |= (plat->iprefetch << IPREPETCH_OFF); | |
161 | } | |
162 | ||
163 | if (plat->dprefetch != -EINVAL) { | |
164 | ctl_val &= ~(DPREPETCH_MSK); | |
165 | ctl_val |= (plat->dprefetch << DPREPETCH_OFF); | |
166 | } | |
167 | ||
168 | if (plat->tram_ctl[0] != -EINVAL) { | |
169 | ctl_val &= ~(TRAMOCTL_MSK | TRAMICTL_MSK); | |
170 | ctl_val |= plat->tram_ctl[0] << TRAMOCTL_OFF; | |
171 | ctl_val |= plat->tram_ctl[1] << TRAMICTL_OFF; | |
172 | } | |
173 | ||
174 | if (plat->dram_ctl[0] != -EINVAL) { | |
175 | ctl_val &= ~(DRAMOCTL_MSK | DRAMICTL_MSK); | |
176 | ctl_val |= plat->dram_ctl[0] << DRAMOCTL_OFF; | |
177 | ctl_val |= plat->dram_ctl[1] << DRAMICTL_OFF; | |
178 | } | |
179 | ||
180 | writel(ctl_val, ®s->control); | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
2b8dc36b | 185 | static const struct udevice_id andes_l2_cache_ids[] = { |
c1b88196 | 186 | { .compatible = "cache" }, |
4fa4267d RC |
187 | {} |
188 | }; | |
189 | ||
2b8dc36b LYCL |
190 | static const struct cache_ops andes_l2_cache_ops = { |
191 | .enable = andes_l2_enable, | |
192 | .disable = andes_l2_disable, | |
4fa4267d RC |
193 | }; |
194 | ||
2b8dc36b LYCL |
195 | U_BOOT_DRIVER(andes_l2_cache) = { |
196 | .name = "andes_l2_cache", | |
4fa4267d | 197 | .id = UCLASS_CACHE, |
2b8dc36b LYCL |
198 | .of_match = andes_l2_cache_ids, |
199 | .of_to_plat = andes_l2_of_to_plat, | |
200 | .probe = andes_l2_probe, | |
201 | .plat_auto = sizeof(struct andes_l2_plat), | |
202 | .ops = &andes_l2_cache_ops, | |
4fa4267d RC |
203 | .flags = DM_FLAG_PRE_RELOC, |
204 | }; |