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 { 62*40a808f1SAlexey Brodkin if (op & OP_FLUSH) { /* flush / flush-n-inv both wait */ 63*40a808f1SAlexey Brodkin /* 64*40a808f1SAlexey Brodkin * Make sure "busy" bit reports correct status, 65*40a808f1SAlexey Brodkin * see STAR 9001165532 66*40a808f1SAlexey Brodkin */ 67*40a808f1SAlexey Brodkin read_aux_reg(ARC_AUX_SLC_CTRL); 68ef639e6fSAlexey Brodkin while (read_aux_reg(ARC_AUX_SLC_CTRL) & 69ef639e6fSAlexey Brodkin DC_CTRL_FLUSH_STATUS) 70ef639e6fSAlexey Brodkin ; 71*40a808f1SAlexey Brodkin } 72ef639e6fSAlexey Brodkin 73ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 74ef639e6fSAlexey Brodkin if (op == OP_INV) 75ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 76ef639e6fSAlexey Brodkin } 77ef639e6fSAlexey Brodkin 78ef639e6fSAlexey Brodkin static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, 79ef639e6fSAlexey Brodkin const int op) 80ef639e6fSAlexey Brodkin { 81ef639e6fSAlexey Brodkin unsigned int aux_cmd; 82ef639e6fSAlexey Brodkin int num_lines; 83ef639e6fSAlexey Brodkin 84ef639e6fSAlexey Brodkin #define SLC_LINE_MASK (~(slc_line_sz - 1)) 85ef639e6fSAlexey Brodkin 86ef639e6fSAlexey Brodkin aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; 87ef639e6fSAlexey Brodkin 88ef639e6fSAlexey Brodkin sz += paddr & ~SLC_LINE_MASK; 89ef639e6fSAlexey Brodkin paddr &= SLC_LINE_MASK; 90ef639e6fSAlexey Brodkin 91ef639e6fSAlexey Brodkin num_lines = DIV_ROUND_UP(sz, slc_line_sz); 92ef639e6fSAlexey Brodkin 93ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 94ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 95ef639e6fSAlexey Brodkin paddr += slc_line_sz; 96ef639e6fSAlexey Brodkin } 97ef639e6fSAlexey Brodkin } 98ef639e6fSAlexey Brodkin 99ef639e6fSAlexey Brodkin static inline void __slc_entire_op(const int cacheop) 100ef639e6fSAlexey Brodkin { 101ef639e6fSAlexey Brodkin int aux; 102ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_slc_op(cacheop); 103ef639e6fSAlexey Brodkin 104ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 105ef639e6fSAlexey Brodkin aux = ARC_AUX_SLC_INVALIDATE; 106ef639e6fSAlexey Brodkin else 107ef639e6fSAlexey Brodkin aux = ARC_AUX_SLC_FLUSH; 108ef639e6fSAlexey Brodkin 109ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 110ef639e6fSAlexey Brodkin 111ef639e6fSAlexey Brodkin __after_slc_op(cacheop, ctrl_reg); 112ef639e6fSAlexey Brodkin } 113ef639e6fSAlexey Brodkin 114ef639e6fSAlexey Brodkin static inline void __slc_line_op(unsigned long paddr, unsigned long sz, 115ef639e6fSAlexey Brodkin const int cacheop) 116ef639e6fSAlexey Brodkin { 117ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_slc_op(cacheop); 118ef639e6fSAlexey Brodkin __slc_line_loop(paddr, sz, cacheop); 119ef639e6fSAlexey Brodkin __after_slc_op(cacheop, ctrl_reg); 120ef639e6fSAlexey Brodkin } 121ef639e6fSAlexey Brodkin #else 122ef639e6fSAlexey Brodkin #define __slc_entire_op(cacheop) 123ef639e6fSAlexey Brodkin #define __slc_line_op(paddr, sz, cacheop) 124ef639e6fSAlexey Brodkin #endif 125ef639e6fSAlexey Brodkin 126379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 127379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void) 128ef639e6fSAlexey Brodkin { 129379b3280SAlexey Brodkin union { 130379b3280SAlexey Brodkin struct { 131379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 132379b3280SAlexey Brodkin unsigned int pad:24, way:2, lsz:2, sz:4; 133379b3280SAlexey Brodkin #else 134379b3280SAlexey Brodkin unsigned int sz:4, lsz:2, way:2, pad:24; 135379b3280SAlexey Brodkin #endif 136379b3280SAlexey Brodkin } fields; 137379b3280SAlexey Brodkin unsigned int word; 138379b3280SAlexey Brodkin } slc_cfg; 139379b3280SAlexey Brodkin 140379b3280SAlexey Brodkin union { 141379b3280SAlexey Brodkin struct { 142379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 143379b3280SAlexey Brodkin unsigned int pad:24, ver:8; 144379b3280SAlexey Brodkin #else 145379b3280SAlexey Brodkin unsigned int ver:8, pad:24; 146379b3280SAlexey Brodkin #endif 147379b3280SAlexey Brodkin } fields; 148379b3280SAlexey Brodkin unsigned int word; 149379b3280SAlexey Brodkin } sbcr; 150379b3280SAlexey Brodkin 151379b3280SAlexey Brodkin sbcr.word = read_aux_reg(ARC_BCR_SLC); 152379b3280SAlexey Brodkin if (sbcr.fields.ver) { 153379b3280SAlexey Brodkin slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); 154379b3280SAlexey Brodkin slc_exists = 1; 155379b3280SAlexey Brodkin slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; 156379b3280SAlexey Brodkin } 157db6ce231SAlexey Brodkin 158db6ce231SAlexey Brodkin union { 159db6ce231SAlexey Brodkin struct bcr_clust_cfg { 160db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 161db6ce231SAlexey Brodkin unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8; 162db6ce231SAlexey Brodkin #else 163db6ce231SAlexey Brodkin unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7; 164db6ce231SAlexey Brodkin #endif 165db6ce231SAlexey Brodkin } fields; 166db6ce231SAlexey Brodkin unsigned int word; 167db6ce231SAlexey Brodkin } cbcr; 168db6ce231SAlexey Brodkin 169db6ce231SAlexey Brodkin cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); 170db6ce231SAlexey Brodkin if (cbcr.fields.c) 171db6ce231SAlexey Brodkin ioc_exists = 1; 172379b3280SAlexey Brodkin } 173379b3280SAlexey Brodkin #endif 174379b3280SAlexey Brodkin 175379b3280SAlexey Brodkin void read_decode_cache_bcr(void) 176379b3280SAlexey Brodkin { 177379b3280SAlexey Brodkin int dc_line_sz = 0, ic_line_sz = 0; 178379b3280SAlexey Brodkin 179379b3280SAlexey Brodkin union { 180379b3280SAlexey Brodkin struct { 181379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 182379b3280SAlexey Brodkin unsigned int pad:12, line_len:4, sz:4, config:4, ver:8; 183379b3280SAlexey Brodkin #else 184379b3280SAlexey Brodkin unsigned int ver:8, config:4, sz:4, line_len:4, pad:12; 185379b3280SAlexey Brodkin #endif 186379b3280SAlexey Brodkin } fields; 187379b3280SAlexey Brodkin unsigned int word; 188379b3280SAlexey Brodkin } ibcr, dbcr; 189379b3280SAlexey Brodkin 190379b3280SAlexey Brodkin ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); 191379b3280SAlexey Brodkin if (ibcr.fields.ver) { 192379b3280SAlexey Brodkin icache_exists = 1; 193379b3280SAlexey Brodkin l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; 194379b3280SAlexey Brodkin if (!ic_line_sz) 195379b3280SAlexey Brodkin panic("Instruction exists but line length is 0\n"); 196ef639e6fSAlexey Brodkin } 197ef639e6fSAlexey Brodkin 198379b3280SAlexey Brodkin dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); 199379b3280SAlexey Brodkin if (dbcr.fields.ver){ 200379b3280SAlexey Brodkin dcache_exists = 1; 201379b3280SAlexey Brodkin l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; 202379b3280SAlexey Brodkin if (!dc_line_sz) 203379b3280SAlexey Brodkin panic("Data cache exists but line length is 0\n"); 204379b3280SAlexey Brodkin } 205379b3280SAlexey Brodkin 206379b3280SAlexey Brodkin if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) 207379b3280SAlexey Brodkin panic("Instruction and data cache line lengths differ\n"); 208ef639e6fSAlexey Brodkin } 209ef639e6fSAlexey Brodkin 210ef639e6fSAlexey Brodkin void cache_init(void) 211ef639e6fSAlexey Brodkin { 212379b3280SAlexey Brodkin read_decode_cache_bcr(); 213379b3280SAlexey Brodkin 214ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 215379b3280SAlexey Brodkin read_decode_cache_bcr_arcv2(); 216db6ce231SAlexey Brodkin 217db6ce231SAlexey Brodkin if (ioc_exists) { 218a4a43fcfSAlexey Brodkin flush_dcache_all(); 219a4a43fcfSAlexey Brodkin invalidate_dcache_all(); 220a4a43fcfSAlexey Brodkin 221db6ce231SAlexey Brodkin /* IO coherency base - 0x8z */ 222db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000); 223db6ce231SAlexey Brodkin /* IO coherency aperture size - 512Mb: 0x8z-0xAz */ 224db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 0x11); 225db6ce231SAlexey Brodkin /* Enable partial writes */ 226db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1); 227db6ce231SAlexey Brodkin /* Enable IO coherency */ 228db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1); 229db6ce231SAlexey Brodkin } 230ef639e6fSAlexey Brodkin #endif 231ef639e6fSAlexey Brodkin } 232ef639e6fSAlexey Brodkin 233660d5f0dSAlexey Brodkin int icache_status(void) 234660d5f0dSAlexey Brodkin { 235379b3280SAlexey Brodkin if (!icache_exists) 236660d5f0dSAlexey Brodkin return 0; 237660d5f0dSAlexey Brodkin 238ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) 239ef639e6fSAlexey Brodkin return 0; 240ef639e6fSAlexey Brodkin else 241ef639e6fSAlexey Brodkin return 1; 242660d5f0dSAlexey Brodkin } 243660d5f0dSAlexey Brodkin 244660d5f0dSAlexey Brodkin void icache_enable(void) 245660d5f0dSAlexey Brodkin { 246379b3280SAlexey Brodkin if (icache_exists) 247660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & 248660d5f0dSAlexey Brodkin ~IC_CTRL_CACHE_DISABLE); 249660d5f0dSAlexey Brodkin } 250660d5f0dSAlexey Brodkin 251660d5f0dSAlexey Brodkin void icache_disable(void) 252660d5f0dSAlexey Brodkin { 253379b3280SAlexey Brodkin if (icache_exists) 254660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | 255660d5f0dSAlexey Brodkin IC_CTRL_CACHE_DISABLE); 256660d5f0dSAlexey Brodkin } 257660d5f0dSAlexey Brodkin 258ef639e6fSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 259660d5f0dSAlexey Brodkin void invalidate_icache_all(void) 260660d5f0dSAlexey Brodkin { 261660d5f0dSAlexey Brodkin /* Any write to IC_IVIC register triggers invalidation of entire I$ */ 262ef639e6fSAlexey Brodkin if (icache_status()) { 263660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_IVIC, 1); 264ef639e6fSAlexey Brodkin read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ 265660d5f0dSAlexey Brodkin } 266ef639e6fSAlexey Brodkin } 267ef639e6fSAlexey Brodkin #else 268ef639e6fSAlexey Brodkin void invalidate_icache_all(void) 269ef639e6fSAlexey Brodkin { 270ef639e6fSAlexey Brodkin } 271ef639e6fSAlexey Brodkin #endif 272660d5f0dSAlexey Brodkin 273660d5f0dSAlexey Brodkin int dcache_status(void) 274660d5f0dSAlexey Brodkin { 275379b3280SAlexey Brodkin if (!dcache_exists) 276660d5f0dSAlexey Brodkin return 0; 277660d5f0dSAlexey Brodkin 278ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) 279ef639e6fSAlexey Brodkin return 0; 280ef639e6fSAlexey Brodkin else 281ef639e6fSAlexey Brodkin return 1; 282660d5f0dSAlexey Brodkin } 283660d5f0dSAlexey Brodkin 284660d5f0dSAlexey Brodkin void dcache_enable(void) 285660d5f0dSAlexey Brodkin { 286379b3280SAlexey Brodkin if (!dcache_exists) 287660d5f0dSAlexey Brodkin return; 288660d5f0dSAlexey Brodkin 289660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & 290660d5f0dSAlexey Brodkin ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE)); 291660d5f0dSAlexey Brodkin } 292660d5f0dSAlexey Brodkin 293660d5f0dSAlexey Brodkin void dcache_disable(void) 294660d5f0dSAlexey Brodkin { 295379b3280SAlexey Brodkin if (!dcache_exists) 296660d5f0dSAlexey Brodkin return; 297660d5f0dSAlexey Brodkin 298660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | 299660d5f0dSAlexey Brodkin DC_CTRL_CACHE_DISABLE); 300660d5f0dSAlexey Brodkin } 301660d5f0dSAlexey Brodkin 302660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 303660d5f0dSAlexey Brodkin /* 304ef639e6fSAlexey Brodkin * Common Helper for Line Operations on {I,D}-Cache 305660d5f0dSAlexey Brodkin */ 306ef639e6fSAlexey Brodkin static inline void __cache_line_loop(unsigned long paddr, unsigned long sz, 307ef639e6fSAlexey Brodkin const int cacheop) 308660d5f0dSAlexey Brodkin { 309ef639e6fSAlexey Brodkin unsigned int aux_cmd; 310ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 311ef639e6fSAlexey Brodkin unsigned int aux_tag; 312ef639e6fSAlexey Brodkin #endif 313ef639e6fSAlexey Brodkin int num_lines; 314660d5f0dSAlexey Brodkin 315ef639e6fSAlexey Brodkin if (cacheop == OP_INV_IC) { 316ef639e6fSAlexey Brodkin aux_cmd = ARC_AUX_IC_IVIL; 317ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 318ef639e6fSAlexey Brodkin aux_tag = ARC_AUX_IC_PTAG; 319ef639e6fSAlexey Brodkin #endif 320ef639e6fSAlexey Brodkin } else { 321ef639e6fSAlexey Brodkin /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 322ef639e6fSAlexey Brodkin aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL; 323ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 324ef639e6fSAlexey Brodkin aux_tag = ARC_AUX_DC_PTAG; 325ef639e6fSAlexey Brodkin #endif 326660d5f0dSAlexey Brodkin } 327660d5f0dSAlexey Brodkin 328ef639e6fSAlexey Brodkin sz += paddr & ~CACHE_LINE_MASK; 329ef639e6fSAlexey Brodkin paddr &= CACHE_LINE_MASK; 330ef639e6fSAlexey Brodkin 331379b3280SAlexey Brodkin num_lines = DIV_ROUND_UP(sz, l1_line_sz); 332ef639e6fSAlexey Brodkin 333ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 334ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 335ef639e6fSAlexey Brodkin write_aux_reg(aux_tag, paddr); 336ef639e6fSAlexey Brodkin #endif 337ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 338379b3280SAlexey Brodkin paddr += l1_line_sz; 339ef639e6fSAlexey Brodkin } 340ef639e6fSAlexey Brodkin } 341ef639e6fSAlexey Brodkin 342ef639e6fSAlexey Brodkin static unsigned int __before_dc_op(const int op) 343ef639e6fSAlexey Brodkin { 344ef639e6fSAlexey Brodkin unsigned int reg; 345ef639e6fSAlexey Brodkin 346ef639e6fSAlexey Brodkin if (op == OP_INV) { 347ef639e6fSAlexey Brodkin /* 348ef639e6fSAlexey Brodkin * IM is set by default and implies Flush-n-inv 349ef639e6fSAlexey Brodkin * Clear it here for vanilla inv 350ef639e6fSAlexey Brodkin */ 351ef639e6fSAlexey Brodkin reg = read_aux_reg(ARC_AUX_DC_CTRL); 352ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 353ef639e6fSAlexey Brodkin } 354ef639e6fSAlexey Brodkin 355ef639e6fSAlexey Brodkin return reg; 356ef639e6fSAlexey Brodkin } 357ef639e6fSAlexey Brodkin 358ef639e6fSAlexey Brodkin static void __after_dc_op(const int op, unsigned int reg) 359ef639e6fSAlexey Brodkin { 360ef639e6fSAlexey Brodkin if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 361ef639e6fSAlexey Brodkin while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS) 362ef639e6fSAlexey Brodkin ; 363ef639e6fSAlexey Brodkin 364ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 365ef639e6fSAlexey Brodkin if (op == OP_INV) 366ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 367ef639e6fSAlexey Brodkin } 368ef639e6fSAlexey Brodkin 369ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop) 370ef639e6fSAlexey Brodkin { 371ef639e6fSAlexey Brodkin int aux; 372ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 373ef639e6fSAlexey Brodkin 374ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 375ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_IVDC; 376ef639e6fSAlexey Brodkin else 377ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_FLSH; 378ef639e6fSAlexey Brodkin 379ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 380ef639e6fSAlexey Brodkin 381ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 382ef639e6fSAlexey Brodkin } 383ef639e6fSAlexey Brodkin 384ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz, 385ef639e6fSAlexey Brodkin const int cacheop) 386ef639e6fSAlexey Brodkin { 387ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 388ef639e6fSAlexey Brodkin __cache_line_loop(paddr, sz, cacheop); 389ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 390ef639e6fSAlexey Brodkin } 391ef639e6fSAlexey Brodkin #else 392ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop) 393ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop) 394ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */ 395ef639e6fSAlexey Brodkin 396660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end) 397660d5f0dSAlexey Brodkin { 398ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 399db6ce231SAlexey Brodkin if (!ioc_exists) 400db6ce231SAlexey Brodkin #endif 401db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_INV); 402db6ce231SAlexey Brodkin 403db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 404db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 405ef639e6fSAlexey Brodkin __slc_line_op(start, end - start, OP_INV); 406660d5f0dSAlexey Brodkin #endif 407660d5f0dSAlexey Brodkin } 408660d5f0dSAlexey Brodkin 409ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end) 410660d5f0dSAlexey Brodkin { 411ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 412db6ce231SAlexey Brodkin if (!ioc_exists) 413db6ce231SAlexey Brodkin #endif 414db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_FLUSH); 415db6ce231SAlexey Brodkin 416db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 417db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 418ef639e6fSAlexey Brodkin __slc_line_op(start, end - start, OP_FLUSH); 419ef639e6fSAlexey Brodkin #endif 420660d5f0dSAlexey Brodkin } 421660d5f0dSAlexey Brodkin 422660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size) 423660d5f0dSAlexey Brodkin { 424660d5f0dSAlexey Brodkin flush_dcache_range(start, start + size); 425660d5f0dSAlexey Brodkin } 4266eb15e50SAlexey Brodkin 427ef639e6fSAlexey Brodkin void invalidate_dcache_all(void) 428ef639e6fSAlexey Brodkin { 429db6ce231SAlexey Brodkin __dc_entire_op(OP_INV); 430db6ce231SAlexey Brodkin 431db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 432bd91508bSAlexey Brodkin if (slc_exists) 433ef639e6fSAlexey Brodkin __slc_entire_op(OP_INV); 434ef639e6fSAlexey Brodkin #endif 4356eb15e50SAlexey Brodkin } 4366eb15e50SAlexey Brodkin 437ef639e6fSAlexey Brodkin void flush_dcache_all(void) 4386eb15e50SAlexey Brodkin { 439db6ce231SAlexey Brodkin __dc_entire_op(OP_FLUSH); 440db6ce231SAlexey Brodkin 441db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 4422a8382c6SAlexey Brodkin if (slc_exists) 443ef639e6fSAlexey Brodkin __slc_entire_op(OP_FLUSH); 444ef639e6fSAlexey Brodkin #endif 4456eb15e50SAlexey Brodkin } 446