1 /* $OpenBSD: arml2cc.c,v 1.5 2016/08/22 01:42:00 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 void arml2cc_sdcache_drain_writebuf(void); 118 119 struct cfattach armliicc_ca = { 120 sizeof (struct arml2cc_softc), arml2cc_match, arml2cc_attach 121 }; 122 123 struct cfdriver armliicc_cd = { 124 NULL, "armliicc", DV_DULL 125 }; 126 127 int 128 arml2cc_match(struct device *parent, void *cfdata, void *aux) 129 { 130 if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9) 131 return (1); 132 133 return (0); 134 } 135 136 void 137 arml2cc_attach(struct device *parent, struct device *self, void *args) 138 { 139 struct cortex_attach_args *ia = args; 140 struct arml2cc_softc *sc = (struct arml2cc_softc *) self; 141 142 sc->sc_iot = ia->ca_iot; 143 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + L2C_ADDR, 144 L2C_SIZE, 0, &sc->sc_ioh)) 145 panic("arml2cc_attach: bus_space_map failed!"); 146 147 printf(": rtl %d", bus_space_read_4(sc->sc_iot, sc->sc_ioh, 148 L2C_CACHE_ID) & 0x3f); 149 150 arml2cc_sc = sc; 151 152 if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CTL)) 153 panic("L2 Cache controller was already enabled\n"); 154 155 sc->sc_dcache_line_size = 32 << (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CACHE_TYPE) & L2C_CACHE_TYPE_LINESIZE); 156 sc->sc_waymask = (8 << ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_AUXCTL) 157 >> L2C_AUXCTL_ASSOC_SHIFT) & L2C_AUXCTL_ASSOC_MASK)) - 1; 158 printf(" waymask: 0x%08x\n", sc->sc_waymask); 159 160 arml2cc_enable(sc); 161 sc->sc_enabled = 1; 162 163 arml2cc_sdcache_wbinv_all(); 164 165 cpufuncs.cf_sdcache_wbinv_all = arml2cc_sdcache_wbinv_all; 166 cpufuncs.cf_sdcache_wbinv_range = arml2cc_sdcache_wbinv_range; 167 cpufuncs.cf_sdcache_inv_range = arml2cc_sdcache_inv_range; 168 cpufuncs.cf_sdcache_wb_range = arml2cc_sdcache_wb_range; 169 cpufuncs.cf_sdcache_drain_writebuf = arml2cc_sdcache_drain_writebuf; 170 } 171 172 void 173 arml2cc_enable(struct arml2cc_softc *sc) 174 { 175 int s; 176 s = splhigh(); 177 178 platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_CTL, SMC_L2_CTL, 179 1); 180 181 arml2cc_cache_way_op(sc, L2C_INV_WAY, sc->sc_waymask); 182 arml2cc_cache_sync(sc); 183 184 splx(s); 185 } 186 187 void 188 arml2cc_disable(struct arml2cc_softc *sc) 189 { 190 int s; 191 s = splhigh(); 192 193 arml2cc_cache_way_op(sc, L2C_CLEAN_INV_WAY, sc->sc_waymask); 194 arml2cc_cache_sync(sc); 195 196 platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_CTL, SMC_L2_CTL, 0); 197 198 splx(s); 199 } 200 201 void 202 arml2cc_cache_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t val) 203 { 204 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val); 205 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off) & 1) { 206 /* spin */ 207 } 208 } 209 210 void 211 arml2cc_cache_way_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t way_mask) 212 { 213 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, way_mask); 214 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off) & way_mask) { 215 /* spin */ 216 } 217 } 218 219 void 220 arml2cc_cache_sync(struct arml2cc_softc *sc) 221 { 222 /* ARM Errata 753970 */ 223 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 0x740, 0xffffffff); 224 } 225 226 void 227 arml2cc_sdcache_drain_writebuf(void) 228 { 229 struct arml2cc_softc * const sc = arml2cc_sc; 230 if (sc == NULL || !sc->sc_enabled) 231 return; 232 233 arml2cc_cache_sync(sc); 234 } 235 236 void 237 arml2cc_cache_range_op(paddr_t pa, psize_t len, bus_size_t cache_op) 238 { 239 struct arml2cc_softc * const sc = arml2cc_sc; 240 size_t line_size = sc->sc_dcache_line_size; 241 size_t line_mask = line_size - 1; 242 paddr_t endpa; 243 244 endpa = pa + len; 245 pa = pa & ~line_mask; 246 247 // printf("l2inv op %x %08x %08x incr %d %d\n", cache_op, pa, endpa, line_size, len); 248 while (endpa > pa) { 249 arml2cc_cache_op(sc, cache_op, pa); 250 pa += line_size; 251 } 252 } 253 254 void 255 arml2cc_sdcache_wbinv_all(void) 256 { 257 struct arml2cc_softc *sc = arml2cc_sc; 258 if (sc == NULL || !sc->sc_enabled) 259 return; 260 261 #ifdef PL310_ERRATA_727915 262 platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3); 263 #endif 264 265 bus_space_write_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY, sc->sc_waymask); 266 while(bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY) & sc->sc_waymask); 267 268 #ifdef PL310_ERRATA_727915 269 platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0); 270 #endif 271 272 arml2cc_cache_sync(sc); 273 } 274 void 275 arml2cc_sdcache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len) 276 { 277 struct arml2cc_softc *sc = arml2cc_sc; 278 if (sc == NULL || !sc->sc_enabled) 279 return; 280 281 #ifdef PL310_ERRATA_727915 282 platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3); 283 #endif 284 285 arml2cc_cache_range_op(pa, len, L2C_CLEAN_INV_PA); 286 arml2cc_cache_sync(sc); 287 288 #ifdef PL310_ERRATA_727915 289 platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0); 290 #endif 291 } 292 293 void 294 arml2cc_sdcache_inv_range(vaddr_t va, paddr_t pa, psize_t len) 295 { 296 struct arml2cc_softc *sc = arml2cc_sc; 297 if (sc == NULL || !sc->sc_enabled) 298 return; 299 arml2cc_cache_range_op(pa, len, L2C_INV_PA); 300 arml2cc_cache_sync(sc); 301 } 302 303 void 304 arml2cc_sdcache_wb_range(vaddr_t va, paddr_t pa, psize_t len) 305 { 306 struct arml2cc_softc *sc = arml2cc_sc; 307 if (sc == NULL || !sc->sc_enabled) 308 return; 309 arml2cc_cache_range_op(pa, len, L2C_CLEAN_PA); 310 arml2cc_cache_sync(sc); 311 } 312