xref: /openbsd-src/sys/arch/arm/cortex/arml2cc.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /* $OpenBSD: arml2cc.c,v 1.3 2013/06/14 23:58:30 patrick 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 	return (1);
130 }
131 
132 void
133 arml2cc_attach(struct device *parent, struct device *self, void *args)
134 {
135 	struct cortex_attach_args *ia = args;
136 	struct arml2cc_softc *sc = (struct arml2cc_softc *) self;
137 
138 	sc->sc_iot = ia->ca_iot;
139 	if (bus_space_map(sc->sc_iot, ia->ca_periphbase + L2C_ADDR,
140 	    L2C_SIZE, 0, &sc->sc_ioh))
141 		panic("arml2cc_attach: bus_space_map failed!");
142 
143 	printf(": rtl %d", bus_space_read_4(sc->sc_iot, sc->sc_ioh,
144 	    L2C_CACHE_ID) & 0x3f);
145 
146 	arml2cc_sc = sc;
147 
148 	if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CTL))
149 		panic("L2 Cache controller was already enabled\n");
150 
151 	sc->sc_dcache_line_size = 32 << (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CACHE_TYPE) & L2C_CACHE_TYPE_LINESIZE);
152 	sc->sc_waymask = (8 << ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_AUXCTL)
153 			    >> L2C_AUXCTL_ASSOC_SHIFT) & L2C_AUXCTL_ASSOC_MASK)) - 1;
154 	printf(" waymask: 0x%08x\n", sc->sc_waymask);
155 
156 	arml2cc_enable(sc);
157 	sc->sc_enabled = 1;
158 
159 	arml2cc_sdcache_wbinv_all();
160 
161 	cpufuncs.cf_sdcache_wbinv_all = arml2cc_sdcache_wbinv_all;
162 	cpufuncs.cf_sdcache_wbinv_range = arml2cc_sdcache_wbinv_range;
163 	cpufuncs.cf_sdcache_inv_range = arml2cc_sdcache_inv_range;
164 	cpufuncs.cf_sdcache_wb_range = arml2cc_sdcache_wb_range;
165 }
166 
167 void
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
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
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
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
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
222 arml2cc_cache_range_op(paddr_t pa, psize_t len, bus_size_t cache_op)
223 {
224 	struct arml2cc_softc * const sc = arml2cc_sc;
225 	size_t line_size = sc->sc_dcache_line_size;
226 	size_t line_mask = line_size - 1;
227 	paddr_t endpa;
228 
229 	endpa = pa + len;
230 	pa = pa & ~line_mask;
231 
232 	// printf("l2inv op %x %08x %08x incr %d %d\n", cache_op, pa, endpa, line_size, len);
233 	while (endpa > pa) {
234 		arml2cc_cache_op(sc, cache_op, pa);
235 		pa += line_size;
236 	}
237 }
238 
239 void
240 arml2cc_sdcache_wbinv_all(void)
241 {
242 	struct arml2cc_softc *sc = arml2cc_sc;
243 	if (sc == NULL || !sc->sc_enabled)
244 		return;
245 
246 #ifdef PL310_ERRATA_727915
247 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3);
248 #endif
249 
250 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY, sc->sc_waymask);
251 	while(bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY) & sc->sc_waymask);
252 
253 #ifdef PL310_ERRATA_727915
254 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0);
255 #endif
256 
257 	arml2cc_cache_sync(sc);
258 }
259 void
260 arml2cc_sdcache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len)
261 {
262 	struct arml2cc_softc *sc = arml2cc_sc;
263 	if (sc == NULL || !sc->sc_enabled)
264 		return;
265 
266 #ifdef PL310_ERRATA_727915
267 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3);
268 #endif
269 
270 	arml2cc_cache_range_op(pa, len, L2C_CLEAN_INV_PA);
271 	arml2cc_cache_sync(sc);
272 
273 #ifdef PL310_ERRATA_727915
274 	platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0);
275 #endif
276 }
277 
278 void
279 arml2cc_sdcache_inv_range(vaddr_t va, paddr_t pa, psize_t len)
280 {
281 	struct arml2cc_softc *sc = arml2cc_sc;
282 	if (sc == NULL || !sc->sc_enabled)
283 		return;
284 	arml2cc_cache_range_op(pa, len, L2C_INV_PA);
285 	arml2cc_cache_sync(sc);
286 }
287 
288 void
289 arml2cc_sdcache_wb_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_CLEAN_PA);
295 	arml2cc_cache_sync(sc);
296 }
297