xref: /openbsd/sys/arch/arm/cortex/arml2cc.c (revision e3ee5e84)
1 /* $OpenBSD: arml2cc.c,v 1.8 2022/03/12 14:40:41 mpi Exp $ */
2 /*
3  * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <machine/intr.h>
22 #include <machine/bus.h>
23 #include <arm/cpufunc.h>
24 #include <arm/cortex/cortex.h>
25 #include <arm/cortex/smc.h>
26 
27 #define PL310_ERRATA_727915
28 
29 /* offset from periphbase */
30 #define L2C_ADDR			0x2000
31 #define L2C_SIZE			0x1000
32 
33 /* registers */
34 #define L2C_CACHE_ID			0x000
35 #define L2C_CACHE_TYPE			0x004
36 #define L2C_CTL				0x100
37 #define L2C_AUXCTL			0x104
38 #define L2C_TAG_RAM_CTL			0x108
39 #define L2C_DATA_RAM_CTL		0x10c
40 #define L2C_EVC_CTR_CTL			0x200
41 #define L2C_EVC_CTR0_CTL		0x204
42 #define L2C_EVC_CTR1_CTL		0x208
43 #define L2C_EVC_CTR0_VAL		0x20c
44 #define L2C_EVC_CTR1_VAL		0x210
45 #define L2C_INT_MASK			0x214
46 #define L2C_INT_MASK_STS		0x218
47 #define L2C_INT_RAW_STS			0x21c
48 #define L2C_INT_CLR			0x220
49 #define L2C_CACHE_SYNC			0x730
50 #define L2C_INV_PA			0x770
51 #define L2C_INV_WAY			0x77c
52 #define L2C_CLEAN_PA			0x7b0
53 #define L2C_CLEAN_INDEX			0x7b8
54 #define L2C_CLEAN_WAY			0x7bc
55 #define L2C_CLEAN_INV_PA		0x7f0
56 #define L2C_CLEAN_INV_INDEX		0x7f8
57 #define L2C_CLEAN_INV_WAY		0x7fc
58 #define L2C_D_LOCKDOWN0			0x900
59 #define L2C_I_LOCKDOWN0			0x904
60 #define L2C_D_LOCKDOWN1			0x908
61 #define L2C_I_LOCKDOWN1			0x90c
62 #define L2C_D_LOCKDOWN2			0x910
63 #define L2C_I_LOCKDOWN2			0x914
64 #define L2C_D_LOCKDOWN3			0x918
65 #define L2C_I_LOCKDOWN3			0x91c
66 #define L2C_D_LOCKDOWN4			0x920
67 #define L2C_I_LOCKDOWN4			0x924
68 #define L2C_D_LOCKDOWN5			0x928
69 #define L2C_I_LOCKDOWN5			0x92c
70 #define L2C_D_LOCKDOWN6			0x930
71 #define L2C_I_LOCKDOWN6			0x934
72 #define L2C_D_LOCKDOWN7			0x938
73 #define L2C_I_LOCKDOWN7			0x93c
74 #define L2C_LOCKDOWN_LINE_EN		0x950
75 #define L2C_UNLOCK_WAY			0x954
76 #define L2C_ADDR_FILTER_START		0xc00
77 #define L2C_ADDR_FILTER_END		0xc04
78 #define L2C_DEBUG_CTL			0xf40
79 #define L2C_PREFETCH_CTL		0xf60
80 #define L2C_POWER_CTL			0xf80
81 
82 #define L2C_CACHE_ID_RELEASE_MASK	0x3f
83 #define L2C_CACHE_TYPE_LINESIZE		0x3
84 #define L2C_AUXCTL_ASSOC_SHIFT		16
85 #define L2C_AUXCTL_ASSOC_MASK		0x1
86 
87 #define roundup2(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
88 
89 struct arml2cc_softc {
90 	struct device		sc_dev;
91 	bus_space_tag_t		sc_iot;
92 	bus_space_handle_t	sc_ioh;
93 	uint32_t		sc_enabled;
94 	uint32_t		sc_waymask;
95 	uint32_t		sc_dcache_line_size;
96 };
97 
98 struct arml2cc_softc *arml2cc_sc;
99 
100 int arml2cc_match(struct device *, void *, void *);
101 void arml2cc_attach(struct device *parent, struct device *self, void *args);
102 void arml2cc_enable(struct arml2cc_softc *);
103 void arml2cc_disable(struct arml2cc_softc *);
104 void arml2cc_sdcache_wbinv_all(void);
105 void arml2cc_sdcache_wbinv_range(vaddr_t, paddr_t, psize_t);
106 void arml2cc_sdcache_inv_range(vaddr_t, paddr_t, psize_t);
107 void arml2cc_sdcache_wb_range(vaddr_t, paddr_t, psize_t);
108 void arml2cc_cache_range_op(paddr_t, psize_t, bus_size_t);
109 void arml2cc_cache_way_op(struct arml2cc_softc *, bus_size_t, uint32_t);
110 void arml2cc_cache_op(struct arml2cc_softc *, bus_size_t, uint32_t);
111 void arml2cc_cache_sync(struct arml2cc_softc *);
112 void arml2cc_sdcache_drain_writebuf(void);
113 
114 const struct cfattach armliicc_ca = {
115 	sizeof (struct arml2cc_softc), arml2cc_match, arml2cc_attach
116 };
117 
118 struct cfdriver armliicc_cd = {
119 	NULL, "armliicc", DV_DULL
120 };
121 
122 int
arml2cc_match(struct device * parent,void * cfdata,void * aux)123 arml2cc_match(struct device *parent, void *cfdata, void *aux)
124 {
125 	if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9)
126 		return (1);
127 
128 	return (0);
129 }
130 
131 void
arml2cc_attach(struct device * parent,struct device * self,void * args)132 arml2cc_attach(struct device *parent, struct device *self, void *args)
133 {
134 	struct cortex_attach_args *ia = args;
135 	struct arml2cc_softc *sc = (struct arml2cc_softc *) self;
136 
137 	sc->sc_iot = ia->ca_iot;
138 	if (bus_space_map(sc->sc_iot, ia->ca_periphbase + L2C_ADDR,
139 	    L2C_SIZE, 0, &sc->sc_ioh))
140 		panic("arml2cc_attach: bus_space_map failed!");
141 
142 	printf(": rtl %d", bus_space_read_4(sc->sc_iot, sc->sc_ioh,
143 	    L2C_CACHE_ID) & 0x3f);
144 
145 	arml2cc_sc = sc;
146 
147 	if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CTL))
148 		panic("L2 Cache controller was already enabled");
149 
150 	sc->sc_dcache_line_size = 32 << (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CACHE_TYPE) & L2C_CACHE_TYPE_LINESIZE);
151 	sc->sc_waymask = (8 << ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_AUXCTL)
152 			    >> L2C_AUXCTL_ASSOC_SHIFT) & L2C_AUXCTL_ASSOC_MASK)) - 1;
153 	printf(" waymask: 0x%08x\n", sc->sc_waymask);
154 
155 	arml2cc_enable(sc);
156 	sc->sc_enabled = 1;
157 
158 	arml2cc_sdcache_wbinv_all();
159 
160 	cpufuncs.cf_sdcache_wbinv_all = arml2cc_sdcache_wbinv_all;
161 	cpufuncs.cf_sdcache_wbinv_range = arml2cc_sdcache_wbinv_range;
162 	cpufuncs.cf_sdcache_inv_range = arml2cc_sdcache_inv_range;
163 	cpufuncs.cf_sdcache_wb_range = arml2cc_sdcache_wb_range;
164 	cpufuncs.cf_sdcache_drain_writebuf = arml2cc_sdcache_drain_writebuf;
165 }
166 
167 void
arml2cc_enable(struct arml2cc_softc * sc)168 arml2cc_enable(struct arml2cc_softc *sc)
169 {
170 	int s;
171 	s = splhigh();
172 
173 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_CTL, SMC_L2_CTL,
174 	    1);
175 
176 	arml2cc_cache_way_op(sc, L2C_INV_WAY, sc->sc_waymask);
177 	arml2cc_cache_sync(sc);
178 
179 	splx(s);
180 }
181 
182 void
arml2cc_disable(struct arml2cc_softc * sc)183 arml2cc_disable(struct arml2cc_softc *sc)
184 {
185 	int s;
186 	s = splhigh();
187 
188 	arml2cc_cache_way_op(sc, L2C_CLEAN_INV_WAY, sc->sc_waymask);
189 	arml2cc_cache_sync(sc);
190 
191 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_CTL, SMC_L2_CTL, 0);
192 
193 	splx(s);
194 }
195 
196 void
arml2cc_cache_op(struct arml2cc_softc * sc,bus_size_t off,uint32_t val)197 arml2cc_cache_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t val)
198 {
199 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
200 	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off) & 1) {
201 		/* spin */
202 	}
203 }
204 
205 void
arml2cc_cache_way_op(struct arml2cc_softc * sc,bus_size_t off,uint32_t way_mask)206 arml2cc_cache_way_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t way_mask)
207 {
208 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, way_mask);
209 	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off) & way_mask) {
210 		/* spin */
211 	}
212 }
213 
214 void
arml2cc_cache_sync(struct arml2cc_softc * sc)215 arml2cc_cache_sync(struct arml2cc_softc *sc)
216 {
217 	/* ARM Errata 753970 */
218 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, 0x740, 0xffffffff);
219 }
220 
221 void
arml2cc_sdcache_drain_writebuf(void)222 arml2cc_sdcache_drain_writebuf(void)
223 {
224 	struct arml2cc_softc * const sc = arml2cc_sc;
225 	if (sc == NULL || !sc->sc_enabled)
226 		return;
227 
228 	arml2cc_cache_sync(sc);
229 }
230 
231 void
arml2cc_cache_range_op(paddr_t pa,psize_t len,bus_size_t cache_op)232 arml2cc_cache_range_op(paddr_t pa, psize_t len, bus_size_t cache_op)
233 {
234 	struct arml2cc_softc * const sc = arml2cc_sc;
235 	size_t line_size = sc->sc_dcache_line_size;
236 	size_t line_mask = line_size - 1;
237 	paddr_t endpa;
238 
239 	endpa = pa + len;
240 	pa = pa & ~line_mask;
241 
242 	// printf("l2inv op %x %08x %08x incr %d %d\n", cache_op, pa, endpa, line_size, len);
243 	while (endpa > pa) {
244 		arml2cc_cache_op(sc, cache_op, pa);
245 		pa += line_size;
246 	}
247 }
248 
249 void
arml2cc_sdcache_wbinv_all(void)250 arml2cc_sdcache_wbinv_all(void)
251 {
252 	struct arml2cc_softc *sc = arml2cc_sc;
253 	if (sc == NULL || !sc->sc_enabled)
254 		return;
255 
256 #ifdef PL310_ERRATA_727915
257 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3);
258 #endif
259 
260 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY, sc->sc_waymask);
261 	while(bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY) & sc->sc_waymask);
262 
263 #ifdef PL310_ERRATA_727915
264 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0);
265 #endif
266 
267 	arml2cc_cache_sync(sc);
268 }
269 void
arml2cc_sdcache_wbinv_range(vaddr_t va,paddr_t pa,psize_t len)270 arml2cc_sdcache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len)
271 {
272 	struct arml2cc_softc *sc = arml2cc_sc;
273 	if (sc == NULL || !sc->sc_enabled)
274 		return;
275 
276 #ifdef PL310_ERRATA_727915
277 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3);
278 #endif
279 
280 	arml2cc_cache_range_op(pa, len, L2C_CLEAN_INV_PA);
281 	arml2cc_cache_sync(sc);
282 
283 #ifdef PL310_ERRATA_727915
284 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0);
285 #endif
286 }
287 
288 void
arml2cc_sdcache_inv_range(vaddr_t va,paddr_t pa,psize_t len)289 arml2cc_sdcache_inv_range(vaddr_t va, paddr_t pa, psize_t len)
290 {
291 	struct arml2cc_softc *sc = arml2cc_sc;
292 	if (sc == NULL || !sc->sc_enabled)
293 		return;
294 	arml2cc_cache_range_op(pa, len, L2C_INV_PA);
295 	arml2cc_cache_sync(sc);
296 }
297 
298 void
arml2cc_sdcache_wb_range(vaddr_t va,paddr_t pa,psize_t len)299 arml2cc_sdcache_wb_range(vaddr_t va, paddr_t pa, psize_t len)
300 {
301 	struct arml2cc_softc *sc = arml2cc_sc;
302 	if (sc == NULL || !sc->sc_enabled)
303 		return;
304 	arml2cc_cache_range_op(pa, len, L2C_CLEAN_PA);
305 	arml2cc_cache_sync(sc);
306 }
307