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