1660d5f0dSAlexey Brodkin /* 2660d5f0dSAlexey Brodkin * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved. 3660d5f0dSAlexey Brodkin * 4660d5f0dSAlexey Brodkin * SPDX-License-Identifier: GPL-2.0+ 5660d5f0dSAlexey Brodkin */ 6660d5f0dSAlexey Brodkin 7660d5f0dSAlexey Brodkin #include <config.h> 8379b3280SAlexey Brodkin #include <common.h> 9ef639e6fSAlexey Brodkin #include <linux/compiler.h> 10ef639e6fSAlexey Brodkin #include <linux/kernel.h> 11660d5f0dSAlexey Brodkin #include <asm/arcregs.h> 12205e7a7bSAlexey Brodkin #include <asm/cache.h> 13660d5f0dSAlexey Brodkin 14660d5f0dSAlexey Brodkin /* Bit values in IC_CTRL */ 15660d5f0dSAlexey Brodkin #define IC_CTRL_CACHE_DISABLE (1 << 0) 16660d5f0dSAlexey Brodkin 17660d5f0dSAlexey Brodkin /* Bit values in DC_CTRL */ 18660d5f0dSAlexey Brodkin #define DC_CTRL_CACHE_DISABLE (1 << 0) 19660d5f0dSAlexey Brodkin #define DC_CTRL_INV_MODE_FLUSH (1 << 6) 20660d5f0dSAlexey Brodkin #define DC_CTRL_FLUSH_STATUS (1 << 8) 21660d5f0dSAlexey Brodkin #define CACHE_VER_NUM_MASK 0xF 226eb15e50SAlexey Brodkin #define SLC_CTRL_SB (1 << 2) 23660d5f0dSAlexey Brodkin 24ef639e6fSAlexey Brodkin #define OP_INV 0x1 25ef639e6fSAlexey Brodkin #define OP_FLUSH 0x2 26ef639e6fSAlexey Brodkin #define OP_INV_IC 0x3 27ef639e6fSAlexey Brodkin 28ef639e6fSAlexey Brodkin /* 29ef639e6fSAlexey Brodkin * By default that variable will fall into .bss section. 30ef639e6fSAlexey Brodkin * But .bss section is not relocated and so it will be initilized before 31ef639e6fSAlexey Brodkin * relocation but will be used after being zeroed. 32ef639e6fSAlexey Brodkin */ 33379b3280SAlexey Brodkin int l1_line_sz __section(".data"); 34379b3280SAlexey Brodkin int dcache_exists __section(".data"); 35379b3280SAlexey Brodkin int icache_exists __section(".data"); 36379b3280SAlexey Brodkin 37379b3280SAlexey Brodkin #define CACHE_LINE_MASK (~(l1_line_sz - 1)) 38379b3280SAlexey Brodkin 39379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 40ef639e6fSAlexey Brodkin int slc_line_sz __section(".data"); 41ef639e6fSAlexey Brodkin int slc_exists __section(".data"); 42db6ce231SAlexey Brodkin int ioc_exists __section(".data"); 43ef639e6fSAlexey Brodkin 44ef639e6fSAlexey Brodkin static unsigned int __before_slc_op(const int op) 45ef639e6fSAlexey Brodkin { 46ef639e6fSAlexey Brodkin unsigned int reg = reg; 47ef639e6fSAlexey Brodkin 48ef639e6fSAlexey Brodkin if (op == OP_INV) { 49ef639e6fSAlexey Brodkin /* 50ef639e6fSAlexey Brodkin * IM is set by default and implies Flush-n-inv 51ef639e6fSAlexey Brodkin * Clear it here for vanilla inv 52ef639e6fSAlexey Brodkin */ 53ef639e6fSAlexey Brodkin reg = read_aux_reg(ARC_AUX_SLC_CTRL); 54ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 55ef639e6fSAlexey Brodkin } 56ef639e6fSAlexey Brodkin 57ef639e6fSAlexey Brodkin return reg; 58ef639e6fSAlexey Brodkin } 59ef639e6fSAlexey Brodkin 60ef639e6fSAlexey Brodkin static void __after_slc_op(const int op, unsigned int reg) 61ef639e6fSAlexey Brodkin { 62ef639e6fSAlexey Brodkin if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 63ef639e6fSAlexey Brodkin while (read_aux_reg(ARC_AUX_SLC_CTRL) & 64ef639e6fSAlexey Brodkin DC_CTRL_FLUSH_STATUS) 65ef639e6fSAlexey Brodkin ; 66ef639e6fSAlexey Brodkin 67ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 68ef639e6fSAlexey Brodkin if (op == OP_INV) 69ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 70ef639e6fSAlexey Brodkin } 71ef639e6fSAlexey Brodkin 72ef639e6fSAlexey Brodkin static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, 73ef639e6fSAlexey Brodkin const int op) 74ef639e6fSAlexey Brodkin { 75ef639e6fSAlexey Brodkin unsigned int aux_cmd; 76ef639e6fSAlexey Brodkin int num_lines; 77ef639e6fSAlexey Brodkin 78ef639e6fSAlexey Brodkin #define SLC_LINE_MASK (~(slc_line_sz - 1)) 79ef639e6fSAlexey Brodkin 80ef639e6fSAlexey Brodkin aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; 81ef639e6fSAlexey Brodkin 82ef639e6fSAlexey Brodkin sz += paddr & ~SLC_LINE_MASK; 83ef639e6fSAlexey Brodkin paddr &= SLC_LINE_MASK; 84ef639e6fSAlexey Brodkin 85ef639e6fSAlexey Brodkin num_lines = DIV_ROUND_UP(sz, slc_line_sz); 86ef639e6fSAlexey Brodkin 87ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 88ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 89ef639e6fSAlexey Brodkin paddr += slc_line_sz; 90ef639e6fSAlexey Brodkin } 91ef639e6fSAlexey Brodkin } 92ef639e6fSAlexey Brodkin 93ef639e6fSAlexey Brodkin static inline void __slc_entire_op(const int cacheop) 94ef639e6fSAlexey Brodkin { 95ef639e6fSAlexey Brodkin int aux; 96ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_slc_op(cacheop); 97ef639e6fSAlexey Brodkin 98ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 99ef639e6fSAlexey Brodkin aux = ARC_AUX_SLC_INVALIDATE; 100ef639e6fSAlexey Brodkin else 101ef639e6fSAlexey Brodkin aux = ARC_AUX_SLC_FLUSH; 102ef639e6fSAlexey Brodkin 103ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 104ef639e6fSAlexey Brodkin 105ef639e6fSAlexey Brodkin __after_slc_op(cacheop, ctrl_reg); 106ef639e6fSAlexey Brodkin } 107ef639e6fSAlexey Brodkin 108ef639e6fSAlexey Brodkin static inline void __slc_line_op(unsigned long paddr, unsigned long sz, 109ef639e6fSAlexey Brodkin const int cacheop) 110ef639e6fSAlexey Brodkin { 111ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_slc_op(cacheop); 112ef639e6fSAlexey Brodkin __slc_line_loop(paddr, sz, cacheop); 113ef639e6fSAlexey Brodkin __after_slc_op(cacheop, ctrl_reg); 114ef639e6fSAlexey Brodkin } 115ef639e6fSAlexey Brodkin #else 116ef639e6fSAlexey Brodkin #define __slc_entire_op(cacheop) 117ef639e6fSAlexey Brodkin #define __slc_line_op(paddr, sz, cacheop) 118ef639e6fSAlexey Brodkin #endif 119ef639e6fSAlexey Brodkin 120379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 121379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void) 122ef639e6fSAlexey Brodkin { 123379b3280SAlexey Brodkin union { 124379b3280SAlexey Brodkin struct { 125379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 126379b3280SAlexey Brodkin unsigned int pad:24, way:2, lsz:2, sz:4; 127379b3280SAlexey Brodkin #else 128379b3280SAlexey Brodkin unsigned int sz:4, lsz:2, way:2, pad:24; 129379b3280SAlexey Brodkin #endif 130379b3280SAlexey Brodkin } fields; 131379b3280SAlexey Brodkin unsigned int word; 132379b3280SAlexey Brodkin } slc_cfg; 133379b3280SAlexey Brodkin 134379b3280SAlexey Brodkin union { 135379b3280SAlexey Brodkin struct { 136379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 137379b3280SAlexey Brodkin unsigned int pad:24, ver:8; 138379b3280SAlexey Brodkin #else 139379b3280SAlexey Brodkin unsigned int ver:8, pad:24; 140379b3280SAlexey Brodkin #endif 141379b3280SAlexey Brodkin } fields; 142379b3280SAlexey Brodkin unsigned int word; 143379b3280SAlexey Brodkin } sbcr; 144379b3280SAlexey Brodkin 145379b3280SAlexey Brodkin sbcr.word = read_aux_reg(ARC_BCR_SLC); 146379b3280SAlexey Brodkin if (sbcr.fields.ver) { 147379b3280SAlexey Brodkin slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); 148379b3280SAlexey Brodkin slc_exists = 1; 149379b3280SAlexey Brodkin slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; 150379b3280SAlexey Brodkin } 151db6ce231SAlexey Brodkin 152db6ce231SAlexey Brodkin union { 153db6ce231SAlexey Brodkin struct bcr_clust_cfg { 154db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 155db6ce231SAlexey Brodkin unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8; 156db6ce231SAlexey Brodkin #else 157db6ce231SAlexey Brodkin unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7; 158db6ce231SAlexey Brodkin #endif 159db6ce231SAlexey Brodkin } fields; 160db6ce231SAlexey Brodkin unsigned int word; 161db6ce231SAlexey Brodkin } cbcr; 162db6ce231SAlexey Brodkin 163db6ce231SAlexey Brodkin cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); 164db6ce231SAlexey Brodkin if (cbcr.fields.c) 165db6ce231SAlexey Brodkin ioc_exists = 1; 166379b3280SAlexey Brodkin } 167379b3280SAlexey Brodkin #endif 168379b3280SAlexey Brodkin 169379b3280SAlexey Brodkin void read_decode_cache_bcr(void) 170379b3280SAlexey Brodkin { 171379b3280SAlexey Brodkin int dc_line_sz = 0, ic_line_sz = 0; 172379b3280SAlexey Brodkin 173379b3280SAlexey Brodkin union { 174379b3280SAlexey Brodkin struct { 175379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 176379b3280SAlexey Brodkin unsigned int pad:12, line_len:4, sz:4, config:4, ver:8; 177379b3280SAlexey Brodkin #else 178379b3280SAlexey Brodkin unsigned int ver:8, config:4, sz:4, line_len:4, pad:12; 179379b3280SAlexey Brodkin #endif 180379b3280SAlexey Brodkin } fields; 181379b3280SAlexey Brodkin unsigned int word; 182379b3280SAlexey Brodkin } ibcr, dbcr; 183379b3280SAlexey Brodkin 184379b3280SAlexey Brodkin ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); 185379b3280SAlexey Brodkin if (ibcr.fields.ver) { 186379b3280SAlexey Brodkin icache_exists = 1; 187379b3280SAlexey Brodkin l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; 188379b3280SAlexey Brodkin if (!ic_line_sz) 189379b3280SAlexey Brodkin panic("Instruction exists but line length is 0\n"); 190ef639e6fSAlexey Brodkin } 191ef639e6fSAlexey Brodkin 192379b3280SAlexey Brodkin dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); 193379b3280SAlexey Brodkin if (dbcr.fields.ver){ 194379b3280SAlexey Brodkin dcache_exists = 1; 195379b3280SAlexey Brodkin l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; 196379b3280SAlexey Brodkin if (!dc_line_sz) 197379b3280SAlexey Brodkin panic("Data cache exists but line length is 0\n"); 198379b3280SAlexey Brodkin } 199379b3280SAlexey Brodkin 200379b3280SAlexey Brodkin if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) 201379b3280SAlexey Brodkin panic("Instruction and data cache line lengths differ\n"); 202ef639e6fSAlexey Brodkin } 203ef639e6fSAlexey Brodkin 204ef639e6fSAlexey Brodkin void cache_init(void) 205ef639e6fSAlexey Brodkin { 206379b3280SAlexey Brodkin read_decode_cache_bcr(); 207379b3280SAlexey Brodkin 208ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 209379b3280SAlexey Brodkin read_decode_cache_bcr_arcv2(); 210db6ce231SAlexey Brodkin 211db6ce231SAlexey Brodkin if (ioc_exists) { 212*a4a43fcfSAlexey Brodkin flush_dcache_all(); 213*a4a43fcfSAlexey Brodkin invalidate_dcache_all(); 214*a4a43fcfSAlexey Brodkin 215db6ce231SAlexey Brodkin /* IO coherency base - 0x8z */ 216db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000); 217db6ce231SAlexey Brodkin /* IO coherency aperture size - 512Mb: 0x8z-0xAz */ 218db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 0x11); 219db6ce231SAlexey Brodkin /* Enable partial writes */ 220db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1); 221db6ce231SAlexey Brodkin /* Enable IO coherency */ 222db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1); 223db6ce231SAlexey Brodkin } 224ef639e6fSAlexey Brodkin #endif 225ef639e6fSAlexey Brodkin } 226ef639e6fSAlexey Brodkin 227660d5f0dSAlexey Brodkin int icache_status(void) 228660d5f0dSAlexey Brodkin { 229379b3280SAlexey Brodkin if (!icache_exists) 230660d5f0dSAlexey Brodkin return 0; 231660d5f0dSAlexey Brodkin 232ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) 233ef639e6fSAlexey Brodkin return 0; 234ef639e6fSAlexey Brodkin else 235ef639e6fSAlexey Brodkin return 1; 236660d5f0dSAlexey Brodkin } 237660d5f0dSAlexey Brodkin 238660d5f0dSAlexey Brodkin void icache_enable(void) 239660d5f0dSAlexey Brodkin { 240379b3280SAlexey Brodkin if (icache_exists) 241660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & 242660d5f0dSAlexey Brodkin ~IC_CTRL_CACHE_DISABLE); 243660d5f0dSAlexey Brodkin } 244660d5f0dSAlexey Brodkin 245660d5f0dSAlexey Brodkin void icache_disable(void) 246660d5f0dSAlexey Brodkin { 247379b3280SAlexey Brodkin if (icache_exists) 248660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | 249660d5f0dSAlexey Brodkin IC_CTRL_CACHE_DISABLE); 250660d5f0dSAlexey Brodkin } 251660d5f0dSAlexey Brodkin 252ef639e6fSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 253660d5f0dSAlexey Brodkin void invalidate_icache_all(void) 254660d5f0dSAlexey Brodkin { 255660d5f0dSAlexey Brodkin /* Any write to IC_IVIC register triggers invalidation of entire I$ */ 256ef639e6fSAlexey Brodkin if (icache_status()) { 257660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_IVIC, 1); 258ef639e6fSAlexey Brodkin read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ 259660d5f0dSAlexey Brodkin } 260ef639e6fSAlexey Brodkin } 261ef639e6fSAlexey Brodkin #else 262ef639e6fSAlexey Brodkin void invalidate_icache_all(void) 263ef639e6fSAlexey Brodkin { 264ef639e6fSAlexey Brodkin } 265ef639e6fSAlexey Brodkin #endif 266660d5f0dSAlexey Brodkin 267660d5f0dSAlexey Brodkin int dcache_status(void) 268660d5f0dSAlexey Brodkin { 269379b3280SAlexey Brodkin if (!dcache_exists) 270660d5f0dSAlexey Brodkin return 0; 271660d5f0dSAlexey Brodkin 272ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) 273ef639e6fSAlexey Brodkin return 0; 274ef639e6fSAlexey Brodkin else 275ef639e6fSAlexey Brodkin return 1; 276660d5f0dSAlexey Brodkin } 277660d5f0dSAlexey Brodkin 278660d5f0dSAlexey Brodkin void dcache_enable(void) 279660d5f0dSAlexey Brodkin { 280379b3280SAlexey Brodkin if (!dcache_exists) 281660d5f0dSAlexey Brodkin return; 282660d5f0dSAlexey Brodkin 283660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & 284660d5f0dSAlexey Brodkin ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE)); 285660d5f0dSAlexey Brodkin } 286660d5f0dSAlexey Brodkin 287660d5f0dSAlexey Brodkin void dcache_disable(void) 288660d5f0dSAlexey Brodkin { 289379b3280SAlexey Brodkin if (!dcache_exists) 290660d5f0dSAlexey Brodkin return; 291660d5f0dSAlexey Brodkin 292660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | 293660d5f0dSAlexey Brodkin DC_CTRL_CACHE_DISABLE); 294660d5f0dSAlexey Brodkin } 295660d5f0dSAlexey Brodkin 296660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 297660d5f0dSAlexey Brodkin /* 298ef639e6fSAlexey Brodkin * Common Helper for Line Operations on {I,D}-Cache 299660d5f0dSAlexey Brodkin */ 300ef639e6fSAlexey Brodkin static inline void __cache_line_loop(unsigned long paddr, unsigned long sz, 301ef639e6fSAlexey Brodkin const int cacheop) 302660d5f0dSAlexey Brodkin { 303ef639e6fSAlexey Brodkin unsigned int aux_cmd; 304ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 305ef639e6fSAlexey Brodkin unsigned int aux_tag; 306ef639e6fSAlexey Brodkin #endif 307ef639e6fSAlexey Brodkin int num_lines; 308660d5f0dSAlexey Brodkin 309ef639e6fSAlexey Brodkin if (cacheop == OP_INV_IC) { 310ef639e6fSAlexey Brodkin aux_cmd = ARC_AUX_IC_IVIL; 311ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 312ef639e6fSAlexey Brodkin aux_tag = ARC_AUX_IC_PTAG; 313ef639e6fSAlexey Brodkin #endif 314ef639e6fSAlexey Brodkin } else { 315ef639e6fSAlexey Brodkin /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 316ef639e6fSAlexey Brodkin aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL; 317ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 318ef639e6fSAlexey Brodkin aux_tag = ARC_AUX_DC_PTAG; 319ef639e6fSAlexey Brodkin #endif 320660d5f0dSAlexey Brodkin } 321660d5f0dSAlexey Brodkin 322ef639e6fSAlexey Brodkin sz += paddr & ~CACHE_LINE_MASK; 323ef639e6fSAlexey Brodkin paddr &= CACHE_LINE_MASK; 324ef639e6fSAlexey Brodkin 325379b3280SAlexey Brodkin num_lines = DIV_ROUND_UP(sz, l1_line_sz); 326ef639e6fSAlexey Brodkin 327ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 328ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 329ef639e6fSAlexey Brodkin write_aux_reg(aux_tag, paddr); 330ef639e6fSAlexey Brodkin #endif 331ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 332379b3280SAlexey Brodkin paddr += l1_line_sz; 333ef639e6fSAlexey Brodkin } 334ef639e6fSAlexey Brodkin } 335ef639e6fSAlexey Brodkin 336ef639e6fSAlexey Brodkin static unsigned int __before_dc_op(const int op) 337ef639e6fSAlexey Brodkin { 338ef639e6fSAlexey Brodkin unsigned int reg; 339ef639e6fSAlexey Brodkin 340ef639e6fSAlexey Brodkin if (op == OP_INV) { 341ef639e6fSAlexey Brodkin /* 342ef639e6fSAlexey Brodkin * IM is set by default and implies Flush-n-inv 343ef639e6fSAlexey Brodkin * Clear it here for vanilla inv 344ef639e6fSAlexey Brodkin */ 345ef639e6fSAlexey Brodkin reg = read_aux_reg(ARC_AUX_DC_CTRL); 346ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 347ef639e6fSAlexey Brodkin } 348ef639e6fSAlexey Brodkin 349ef639e6fSAlexey Brodkin return reg; 350ef639e6fSAlexey Brodkin } 351ef639e6fSAlexey Brodkin 352ef639e6fSAlexey Brodkin static void __after_dc_op(const int op, unsigned int reg) 353ef639e6fSAlexey Brodkin { 354ef639e6fSAlexey Brodkin if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 355ef639e6fSAlexey Brodkin while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS) 356ef639e6fSAlexey Brodkin ; 357ef639e6fSAlexey Brodkin 358ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 359ef639e6fSAlexey Brodkin if (op == OP_INV) 360ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 361ef639e6fSAlexey Brodkin } 362ef639e6fSAlexey Brodkin 363ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop) 364ef639e6fSAlexey Brodkin { 365ef639e6fSAlexey Brodkin int aux; 366ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 367ef639e6fSAlexey Brodkin 368ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 369ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_IVDC; 370ef639e6fSAlexey Brodkin else 371ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_FLSH; 372ef639e6fSAlexey Brodkin 373ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 374ef639e6fSAlexey Brodkin 375ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 376ef639e6fSAlexey Brodkin } 377ef639e6fSAlexey Brodkin 378ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz, 379ef639e6fSAlexey Brodkin const int cacheop) 380ef639e6fSAlexey Brodkin { 381ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 382ef639e6fSAlexey Brodkin __cache_line_loop(paddr, sz, cacheop); 383ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 384ef639e6fSAlexey Brodkin } 385ef639e6fSAlexey Brodkin #else 386ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop) 387ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop) 388ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */ 389ef639e6fSAlexey Brodkin 390660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end) 391660d5f0dSAlexey Brodkin { 392ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 393db6ce231SAlexey Brodkin if (!ioc_exists) 394db6ce231SAlexey Brodkin #endif 395db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_INV); 396db6ce231SAlexey Brodkin 397db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 398db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 399ef639e6fSAlexey Brodkin __slc_line_op(start, end - start, OP_INV); 400660d5f0dSAlexey Brodkin #endif 401660d5f0dSAlexey Brodkin } 402660d5f0dSAlexey Brodkin 403ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end) 404660d5f0dSAlexey Brodkin { 405ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 406db6ce231SAlexey Brodkin if (!ioc_exists) 407db6ce231SAlexey Brodkin #endif 408db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_FLUSH); 409db6ce231SAlexey Brodkin 410db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 411db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 412ef639e6fSAlexey Brodkin __slc_line_op(start, end - start, OP_FLUSH); 413ef639e6fSAlexey Brodkin #endif 414660d5f0dSAlexey Brodkin } 415660d5f0dSAlexey Brodkin 416660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size) 417660d5f0dSAlexey Brodkin { 418660d5f0dSAlexey Brodkin flush_dcache_range(start, start + size); 419660d5f0dSAlexey Brodkin } 4206eb15e50SAlexey Brodkin 421ef639e6fSAlexey Brodkin void invalidate_dcache_all(void) 422ef639e6fSAlexey Brodkin { 423db6ce231SAlexey Brodkin __dc_entire_op(OP_INV); 424db6ce231SAlexey Brodkin 425db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 426bd91508bSAlexey Brodkin if (slc_exists) 427ef639e6fSAlexey Brodkin __slc_entire_op(OP_INV); 428ef639e6fSAlexey Brodkin #endif 4296eb15e50SAlexey Brodkin } 4306eb15e50SAlexey Brodkin 431ef639e6fSAlexey Brodkin void flush_dcache_all(void) 4326eb15e50SAlexey Brodkin { 433db6ce231SAlexey Brodkin __dc_entire_op(OP_FLUSH); 434db6ce231SAlexey Brodkin 435db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 4362a8382c6SAlexey Brodkin if (slc_exists) 437ef639e6fSAlexey Brodkin __slc_entire_op(OP_FLUSH); 438ef639e6fSAlexey Brodkin #endif 4396eb15e50SAlexey Brodkin } 440