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 <linux/compiler.h> 9 #include <linux/kernel.h> 10 #include <asm/arcregs.h> 11 #include <asm/cache.h> 12 13 #define CACHE_LINE_MASK (~(CONFIG_SYS_CACHELINE_SIZE - 1)) 14 15 /* Bit values in IC_CTRL */ 16 #define IC_CTRL_CACHE_DISABLE (1 << 0) 17 18 /* Bit values in DC_CTRL */ 19 #define DC_CTRL_CACHE_DISABLE (1 << 0) 20 #define DC_CTRL_INV_MODE_FLUSH (1 << 6) 21 #define DC_CTRL_FLUSH_STATUS (1 << 8) 22 #define CACHE_VER_NUM_MASK 0xF 23 #define SLC_CTRL_SB (1 << 2) 24 25 #define OP_INV 0x1 26 #define OP_FLUSH 0x2 27 #define OP_INV_IC 0x3 28 29 #ifdef CONFIG_ISA_ARCV2 30 /* 31 * By default that variable will fall into .bss section. 32 * But .bss section is not relocated and so it will be initilized before 33 * relocation but will be used after being zeroed. 34 */ 35 int slc_line_sz __section(".data"); 36 int slc_exists __section(".data"); 37 38 static unsigned int __before_slc_op(const int op) 39 { 40 unsigned int reg = reg; 41 42 if (op == OP_INV) { 43 /* 44 * IM is set by default and implies Flush-n-inv 45 * Clear it here for vanilla inv 46 */ 47 reg = read_aux_reg(ARC_AUX_SLC_CTRL); 48 write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 49 } 50 51 return reg; 52 } 53 54 static void __after_slc_op(const int op, unsigned int reg) 55 { 56 if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 57 while (read_aux_reg(ARC_AUX_SLC_CTRL) & 58 DC_CTRL_FLUSH_STATUS) 59 ; 60 61 /* Switch back to default Invalidate mode */ 62 if (op == OP_INV) 63 write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 64 } 65 66 static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, 67 const int op) 68 { 69 unsigned int aux_cmd; 70 int num_lines; 71 72 #define SLC_LINE_MASK (~(slc_line_sz - 1)) 73 74 aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; 75 76 sz += paddr & ~SLC_LINE_MASK; 77 paddr &= SLC_LINE_MASK; 78 79 num_lines = DIV_ROUND_UP(sz, slc_line_sz); 80 81 while (num_lines-- > 0) { 82 write_aux_reg(aux_cmd, paddr); 83 paddr += slc_line_sz; 84 } 85 } 86 87 static inline void __slc_entire_op(const int cacheop) 88 { 89 int aux; 90 unsigned int ctrl_reg = __before_slc_op(cacheop); 91 92 if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 93 aux = ARC_AUX_SLC_INVALIDATE; 94 else 95 aux = ARC_AUX_SLC_FLUSH; 96 97 write_aux_reg(aux, 0x1); 98 99 __after_slc_op(cacheop, ctrl_reg); 100 } 101 102 static inline void __slc_line_op(unsigned long paddr, unsigned long sz, 103 const int cacheop) 104 { 105 unsigned int ctrl_reg = __before_slc_op(cacheop); 106 __slc_line_loop(paddr, sz, cacheop); 107 __after_slc_op(cacheop, ctrl_reg); 108 } 109 #else 110 #define __slc_entire_op(cacheop) 111 #define __slc_line_op(paddr, sz, cacheop) 112 #endif 113 114 static inline int icache_exists(void) 115 { 116 /* Check if Instruction Cache is available */ 117 if (read_aux_reg(ARC_BCR_IC_BUILD) & CACHE_VER_NUM_MASK) 118 return 1; 119 else 120 return 0; 121 } 122 123 static inline int dcache_exists(void) 124 { 125 /* Check if Data Cache is available */ 126 if (read_aux_reg(ARC_BCR_DC_BUILD) & CACHE_VER_NUM_MASK) 127 return 1; 128 else 129 return 0; 130 } 131 132 void cache_init(void) 133 { 134 #ifdef CONFIG_ISA_ARCV2 135 /* Check if System-Level Cache (SLC) is available */ 136 if (read_aux_reg(ARC_BCR_SLC) & CACHE_VER_NUM_MASK) { 137 #define LSIZE_OFFSET 4 138 #define LSIZE_MASK 3 139 if (read_aux_reg(ARC_AUX_SLC_CONFIG) & 140 (LSIZE_MASK << LSIZE_OFFSET)) 141 slc_line_sz = 64; 142 else 143 slc_line_sz = 128; 144 slc_exists = 1; 145 } else { 146 slc_exists = 0; 147 } 148 #endif 149 } 150 151 int icache_status(void) 152 { 153 if (!icache_exists()) 154 return 0; 155 156 if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) 157 return 0; 158 else 159 return 1; 160 } 161 162 void icache_enable(void) 163 { 164 if (icache_exists()) 165 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & 166 ~IC_CTRL_CACHE_DISABLE); 167 } 168 169 void icache_disable(void) 170 { 171 if (icache_exists()) 172 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | 173 IC_CTRL_CACHE_DISABLE); 174 } 175 176 #ifndef CONFIG_SYS_DCACHE_OFF 177 void invalidate_icache_all(void) 178 { 179 /* Any write to IC_IVIC register triggers invalidation of entire I$ */ 180 if (icache_status()) { 181 write_aux_reg(ARC_AUX_IC_IVIC, 1); 182 read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ 183 } 184 } 185 #else 186 void invalidate_icache_all(void) 187 { 188 } 189 #endif 190 191 int dcache_status(void) 192 { 193 if (!dcache_exists()) 194 return 0; 195 196 if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) 197 return 0; 198 else 199 return 1; 200 } 201 202 void dcache_enable(void) 203 { 204 if (!dcache_exists()) 205 return; 206 207 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & 208 ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE)); 209 } 210 211 void dcache_disable(void) 212 { 213 if (!dcache_exists()) 214 return; 215 216 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | 217 DC_CTRL_CACHE_DISABLE); 218 } 219 220 #ifndef CONFIG_SYS_DCACHE_OFF 221 /* 222 * Common Helper for Line Operations on {I,D}-Cache 223 */ 224 static inline void __cache_line_loop(unsigned long paddr, unsigned long sz, 225 const int cacheop) 226 { 227 unsigned int aux_cmd; 228 #if (CONFIG_ARC_MMU_VER == 3) 229 unsigned int aux_tag; 230 #endif 231 int num_lines; 232 233 if (cacheop == OP_INV_IC) { 234 aux_cmd = ARC_AUX_IC_IVIL; 235 #if (CONFIG_ARC_MMU_VER == 3) 236 aux_tag = ARC_AUX_IC_PTAG; 237 #endif 238 } else { 239 /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 240 aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL; 241 #if (CONFIG_ARC_MMU_VER == 3) 242 aux_tag = ARC_AUX_DC_PTAG; 243 #endif 244 } 245 246 sz += paddr & ~CACHE_LINE_MASK; 247 paddr &= CACHE_LINE_MASK; 248 249 num_lines = DIV_ROUND_UP(sz, CONFIG_SYS_CACHELINE_SIZE); 250 251 while (num_lines-- > 0) { 252 #if (CONFIG_ARC_MMU_VER == 3) 253 write_aux_reg(aux_tag, paddr); 254 #endif 255 write_aux_reg(aux_cmd, paddr); 256 paddr += CONFIG_SYS_CACHELINE_SIZE; 257 } 258 } 259 260 static unsigned int __before_dc_op(const int op) 261 { 262 unsigned int reg; 263 264 if (op == OP_INV) { 265 /* 266 * IM is set by default and implies Flush-n-inv 267 * Clear it here for vanilla inv 268 */ 269 reg = read_aux_reg(ARC_AUX_DC_CTRL); 270 write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 271 } 272 273 return reg; 274 } 275 276 static void __after_dc_op(const int op, unsigned int reg) 277 { 278 if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 279 while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS) 280 ; 281 282 /* Switch back to default Invalidate mode */ 283 if (op == OP_INV) 284 write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 285 } 286 287 static inline void __dc_entire_op(const int cacheop) 288 { 289 int aux; 290 unsigned int ctrl_reg = __before_dc_op(cacheop); 291 292 if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 293 aux = ARC_AUX_DC_IVDC; 294 else 295 aux = ARC_AUX_DC_FLSH; 296 297 write_aux_reg(aux, 0x1); 298 299 __after_dc_op(cacheop, ctrl_reg); 300 } 301 302 static inline void __dc_line_op(unsigned long paddr, unsigned long sz, 303 const int cacheop) 304 { 305 unsigned int ctrl_reg = __before_dc_op(cacheop); 306 __cache_line_loop(paddr, sz, cacheop); 307 __after_dc_op(cacheop, ctrl_reg); 308 } 309 #else 310 #define __dc_entire_op(cacheop) 311 #define __dc_line_op(paddr, sz, cacheop) 312 #endif /* !CONFIG_SYS_DCACHE_OFF */ 313 314 void invalidate_dcache_range(unsigned long start, unsigned long end) 315 { 316 __dc_line_op(start, end - start, OP_INV); 317 #ifdef CONFIG_ISA_ARCV2 318 if (slc_exists) 319 __slc_line_op(start, end - start, OP_INV); 320 #endif 321 } 322 323 void flush_dcache_range(unsigned long start, unsigned long end) 324 { 325 __dc_line_op(start, end - start, OP_FLUSH); 326 #ifdef CONFIG_ISA_ARCV2 327 if (slc_exists) 328 __slc_line_op(start, end - start, OP_FLUSH); 329 #endif 330 } 331 332 void flush_cache(unsigned long start, unsigned long size) 333 { 334 flush_dcache_range(start, start + size); 335 } 336 337 void invalidate_dcache_all(void) 338 { 339 __dc_entire_op(OP_INV); 340 #ifdef CONFIG_ISA_ARCV2 341 if (slc_exists) 342 __slc_entire_op(OP_INV); 343 #endif 344 } 345 346 void flush_dcache_all(void) 347 { 348 __dc_entire_op(OP_FLUSH); 349 #ifdef CONFIG_ISA_ARCV2 350 if (slc_exists) 351 __slc_entire_op(OP_FLUSH); 352 #endif 353 } 354