1 /* 2 * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <config.h> 8 #include <common.h> 9 #include <linux/compiler.h> 10 #include <linux/kernel.h> 11 #include <asm/arcregs.h> 12 #include <asm/cache.h> 13 14 /* Bit values in IC_CTRL */ 15 #define IC_CTRL_CACHE_DISABLE (1 << 0) 16 17 /* Bit values in DC_CTRL */ 18 #define DC_CTRL_CACHE_DISABLE (1 << 0) 19 #define DC_CTRL_INV_MODE_FLUSH (1 << 6) 20 #define DC_CTRL_FLUSH_STATUS (1 << 8) 21 #define CACHE_VER_NUM_MASK 0xF 22 #define SLC_CTRL_SB (1 << 2) 23 24 #define OP_INV 0x1 25 #define OP_FLUSH 0x2 26 #define OP_INV_IC 0x3 27 28 /* 29 * By default that variable will fall into .bss section. 30 * But .bss section is not relocated and so it will be initilized before 31 * relocation but will be used after being zeroed. 32 */ 33 int l1_line_sz __section(".data"); 34 int dcache_exists __section(".data"); 35 int icache_exists __section(".data"); 36 37 #define CACHE_LINE_MASK (~(l1_line_sz - 1)) 38 39 #ifdef CONFIG_ISA_ARCV2 40 int slc_line_sz __section(".data"); 41 int slc_exists __section(".data"); 42 int ioc_exists __section(".data"); 43 44 static unsigned int __before_slc_op(const int op) 45 { 46 unsigned int reg = reg; 47 48 if (op == OP_INV) { 49 /* 50 * IM is set by default and implies Flush-n-inv 51 * Clear it here for vanilla inv 52 */ 53 reg = read_aux_reg(ARC_AUX_SLC_CTRL); 54 write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 55 } 56 57 return reg; 58 } 59 60 static void __after_slc_op(const int op, unsigned int reg) 61 { 62 if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 63 while (read_aux_reg(ARC_AUX_SLC_CTRL) & 64 DC_CTRL_FLUSH_STATUS) 65 ; 66 67 /* Switch back to default Invalidate mode */ 68 if (op == OP_INV) 69 write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 70 } 71 72 static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, 73 const int op) 74 { 75 unsigned int aux_cmd; 76 int num_lines; 77 78 #define SLC_LINE_MASK (~(slc_line_sz - 1)) 79 80 aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; 81 82 sz += paddr & ~SLC_LINE_MASK; 83 paddr &= SLC_LINE_MASK; 84 85 num_lines = DIV_ROUND_UP(sz, slc_line_sz); 86 87 while (num_lines-- > 0) { 88 write_aux_reg(aux_cmd, paddr); 89 paddr += slc_line_sz; 90 } 91 } 92 93 static inline void __slc_entire_op(const int cacheop) 94 { 95 int aux; 96 unsigned int ctrl_reg = __before_slc_op(cacheop); 97 98 if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 99 aux = ARC_AUX_SLC_INVALIDATE; 100 else 101 aux = ARC_AUX_SLC_FLUSH; 102 103 write_aux_reg(aux, 0x1); 104 105 __after_slc_op(cacheop, ctrl_reg); 106 } 107 108 static inline void __slc_line_op(unsigned long paddr, unsigned long sz, 109 const int cacheop) 110 { 111 unsigned int ctrl_reg = __before_slc_op(cacheop); 112 __slc_line_loop(paddr, sz, cacheop); 113 __after_slc_op(cacheop, ctrl_reg); 114 } 115 #else 116 #define __slc_entire_op(cacheop) 117 #define __slc_line_op(paddr, sz, cacheop) 118 #endif 119 120 #ifdef CONFIG_ISA_ARCV2 121 static void read_decode_cache_bcr_arcv2(void) 122 { 123 union { 124 struct { 125 #ifdef CONFIG_CPU_BIG_ENDIAN 126 unsigned int pad:24, way:2, lsz:2, sz:4; 127 #else 128 unsigned int sz:4, lsz:2, way:2, pad:24; 129 #endif 130 } fields; 131 unsigned int word; 132 } slc_cfg; 133 134 union { 135 struct { 136 #ifdef CONFIG_CPU_BIG_ENDIAN 137 unsigned int pad:24, ver:8; 138 #else 139 unsigned int ver:8, pad:24; 140 #endif 141 } fields; 142 unsigned int word; 143 } sbcr; 144 145 sbcr.word = read_aux_reg(ARC_BCR_SLC); 146 if (sbcr.fields.ver) { 147 slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); 148 slc_exists = 1; 149 slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; 150 } 151 152 union { 153 struct bcr_clust_cfg { 154 #ifdef CONFIG_CPU_BIG_ENDIAN 155 unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8; 156 #else 157 unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7; 158 #endif 159 } fields; 160 unsigned int word; 161 } cbcr; 162 163 cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); 164 if (cbcr.fields.c) 165 ioc_exists = 1; 166 } 167 #endif 168 169 void read_decode_cache_bcr(void) 170 { 171 int dc_line_sz = 0, ic_line_sz = 0; 172 173 union { 174 struct { 175 #ifdef CONFIG_CPU_BIG_ENDIAN 176 unsigned int pad:12, line_len:4, sz:4, config:4, ver:8; 177 #else 178 unsigned int ver:8, config:4, sz:4, line_len:4, pad:12; 179 #endif 180 } fields; 181 unsigned int word; 182 } ibcr, dbcr; 183 184 ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); 185 if (ibcr.fields.ver) { 186 icache_exists = 1; 187 l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; 188 if (!ic_line_sz) 189 panic("Instruction exists but line length is 0\n"); 190 } 191 192 dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); 193 if (dbcr.fields.ver){ 194 dcache_exists = 1; 195 l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; 196 if (!dc_line_sz) 197 panic("Data cache exists but line length is 0\n"); 198 } 199 200 if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) 201 panic("Instruction and data cache line lengths differ\n"); 202 } 203 204 void cache_init(void) 205 { 206 read_decode_cache_bcr(); 207 208 #ifdef CONFIG_ISA_ARCV2 209 read_decode_cache_bcr_arcv2(); 210 211 if (ioc_exists) { 212 /* IO coherency base - 0x8z */ 213 write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000); 214 /* IO coherency aperture size - 512Mb: 0x8z-0xAz */ 215 write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 0x11); 216 /* Enable partial writes */ 217 write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1); 218 /* Enable IO coherency */ 219 write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1); 220 } 221 #endif 222 } 223 224 int icache_status(void) 225 { 226 if (!icache_exists) 227 return 0; 228 229 if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) 230 return 0; 231 else 232 return 1; 233 } 234 235 void icache_enable(void) 236 { 237 if (icache_exists) 238 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & 239 ~IC_CTRL_CACHE_DISABLE); 240 } 241 242 void icache_disable(void) 243 { 244 if (icache_exists) 245 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | 246 IC_CTRL_CACHE_DISABLE); 247 } 248 249 #ifndef CONFIG_SYS_DCACHE_OFF 250 void invalidate_icache_all(void) 251 { 252 /* Any write to IC_IVIC register triggers invalidation of entire I$ */ 253 if (icache_status()) { 254 write_aux_reg(ARC_AUX_IC_IVIC, 1); 255 read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ 256 } 257 } 258 #else 259 void invalidate_icache_all(void) 260 { 261 } 262 #endif 263 264 int dcache_status(void) 265 { 266 if (!dcache_exists) 267 return 0; 268 269 if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) 270 return 0; 271 else 272 return 1; 273 } 274 275 void dcache_enable(void) 276 { 277 if (!dcache_exists) 278 return; 279 280 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & 281 ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE)); 282 } 283 284 void dcache_disable(void) 285 { 286 if (!dcache_exists) 287 return; 288 289 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | 290 DC_CTRL_CACHE_DISABLE); 291 } 292 293 #ifndef CONFIG_SYS_DCACHE_OFF 294 /* 295 * Common Helper for Line Operations on {I,D}-Cache 296 */ 297 static inline void __cache_line_loop(unsigned long paddr, unsigned long sz, 298 const int cacheop) 299 { 300 unsigned int aux_cmd; 301 #if (CONFIG_ARC_MMU_VER == 3) 302 unsigned int aux_tag; 303 #endif 304 int num_lines; 305 306 if (cacheop == OP_INV_IC) { 307 aux_cmd = ARC_AUX_IC_IVIL; 308 #if (CONFIG_ARC_MMU_VER == 3) 309 aux_tag = ARC_AUX_IC_PTAG; 310 #endif 311 } else { 312 /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 313 aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL; 314 #if (CONFIG_ARC_MMU_VER == 3) 315 aux_tag = ARC_AUX_DC_PTAG; 316 #endif 317 } 318 319 sz += paddr & ~CACHE_LINE_MASK; 320 paddr &= CACHE_LINE_MASK; 321 322 num_lines = DIV_ROUND_UP(sz, l1_line_sz); 323 324 while (num_lines-- > 0) { 325 #if (CONFIG_ARC_MMU_VER == 3) 326 write_aux_reg(aux_tag, paddr); 327 #endif 328 write_aux_reg(aux_cmd, paddr); 329 paddr += l1_line_sz; 330 } 331 } 332 333 static unsigned int __before_dc_op(const int op) 334 { 335 unsigned int reg; 336 337 if (op == OP_INV) { 338 /* 339 * IM is set by default and implies Flush-n-inv 340 * Clear it here for vanilla inv 341 */ 342 reg = read_aux_reg(ARC_AUX_DC_CTRL); 343 write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 344 } 345 346 return reg; 347 } 348 349 static void __after_dc_op(const int op, unsigned int reg) 350 { 351 if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 352 while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS) 353 ; 354 355 /* Switch back to default Invalidate mode */ 356 if (op == OP_INV) 357 write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 358 } 359 360 static inline void __dc_entire_op(const int cacheop) 361 { 362 int aux; 363 unsigned int ctrl_reg = __before_dc_op(cacheop); 364 365 if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 366 aux = ARC_AUX_DC_IVDC; 367 else 368 aux = ARC_AUX_DC_FLSH; 369 370 write_aux_reg(aux, 0x1); 371 372 __after_dc_op(cacheop, ctrl_reg); 373 } 374 375 static inline void __dc_line_op(unsigned long paddr, unsigned long sz, 376 const int cacheop) 377 { 378 unsigned int ctrl_reg = __before_dc_op(cacheop); 379 __cache_line_loop(paddr, sz, cacheop); 380 __after_dc_op(cacheop, ctrl_reg); 381 } 382 #else 383 #define __dc_entire_op(cacheop) 384 #define __dc_line_op(paddr, sz, cacheop) 385 #endif /* !CONFIG_SYS_DCACHE_OFF */ 386 387 void invalidate_dcache_range(unsigned long start, unsigned long end) 388 { 389 #ifdef CONFIG_ISA_ARCV2 390 if (!ioc_exists) 391 #endif 392 __dc_line_op(start, end - start, OP_INV); 393 394 #ifdef CONFIG_ISA_ARCV2 395 if (slc_exists && !ioc_exists) 396 __slc_line_op(start, end - start, OP_INV); 397 #endif 398 } 399 400 void flush_dcache_range(unsigned long start, unsigned long end) 401 { 402 #ifdef CONFIG_ISA_ARCV2 403 if (!ioc_exists) 404 #endif 405 __dc_line_op(start, end - start, OP_FLUSH); 406 407 #ifdef CONFIG_ISA_ARCV2 408 if (slc_exists && !ioc_exists) 409 __slc_line_op(start, end - start, OP_FLUSH); 410 #endif 411 } 412 413 void flush_cache(unsigned long start, unsigned long size) 414 { 415 flush_dcache_range(start, start + size); 416 } 417 418 void invalidate_dcache_all(void) 419 { 420 #ifdef CONFIG_ISA_ARCV2 421 if (!ioc_exists) 422 #endif 423 __dc_entire_op(OP_INV); 424 425 #ifdef CONFIG_ISA_ARCV2 426 if (slc_exists && !ioc_exists) 427 __slc_entire_op(OP_INV); 428 #endif 429 } 430 431 void flush_dcache_all(void) 432 { 433 #ifdef CONFIG_ISA_ARCV2 434 if (!ioc_exists) 435 #endif 436 __dc_entire_op(OP_FLUSH); 437 438 #ifdef CONFIG_ISA_ARCV2 439 if (slc_exists && !ioc_exists) 440 __slc_entire_op(OP_FLUSH); 441 #endif 442 } 443