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> 1197a63144SAlexey Brodkin #include <linux/log2.h> 12660d5f0dSAlexey Brodkin #include <asm/arcregs.h> 13205e7a7bSAlexey Brodkin #include <asm/cache.h> 14660d5f0dSAlexey Brodkin 15660d5f0dSAlexey Brodkin /* Bit values in IC_CTRL */ 16660d5f0dSAlexey Brodkin #define IC_CTRL_CACHE_DISABLE (1 << 0) 17660d5f0dSAlexey Brodkin 18660d5f0dSAlexey Brodkin /* Bit values in DC_CTRL */ 19660d5f0dSAlexey Brodkin #define DC_CTRL_CACHE_DISABLE (1 << 0) 20660d5f0dSAlexey Brodkin #define DC_CTRL_INV_MODE_FLUSH (1 << 6) 21660d5f0dSAlexey Brodkin #define DC_CTRL_FLUSH_STATUS (1 << 8) 22660d5f0dSAlexey Brodkin #define CACHE_VER_NUM_MASK 0xF 236eb15e50SAlexey Brodkin #define SLC_CTRL_SB (1 << 2) 24660d5f0dSAlexey Brodkin 25ef639e6fSAlexey Brodkin #define OP_INV 0x1 26ef639e6fSAlexey Brodkin #define OP_FLUSH 0x2 27ef639e6fSAlexey Brodkin #define OP_INV_IC 0x3 28ef639e6fSAlexey Brodkin 29ef639e6fSAlexey Brodkin /* 30ef639e6fSAlexey Brodkin * By default that variable will fall into .bss section. 31ef639e6fSAlexey Brodkin * But .bss section is not relocated and so it will be initilized before 32ef639e6fSAlexey Brodkin * relocation but will be used after being zeroed. 33ef639e6fSAlexey Brodkin */ 34379b3280SAlexey Brodkin int l1_line_sz __section(".data"); 35379b3280SAlexey Brodkin int dcache_exists __section(".data"); 36379b3280SAlexey Brodkin int icache_exists __section(".data"); 37379b3280SAlexey Brodkin 38379b3280SAlexey Brodkin #define CACHE_LINE_MASK (~(l1_line_sz - 1)) 39379b3280SAlexey Brodkin 40379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 41ef639e6fSAlexey Brodkin int slc_line_sz __section(".data"); 42ef639e6fSAlexey Brodkin int slc_exists __section(".data"); 43db6ce231SAlexey Brodkin int ioc_exists __section(".data"); 44ef639e6fSAlexey Brodkin 45ef639e6fSAlexey Brodkin static unsigned int __before_slc_op(const int op) 46ef639e6fSAlexey Brodkin { 47ef639e6fSAlexey Brodkin unsigned int reg = reg; 48ef639e6fSAlexey Brodkin 49ef639e6fSAlexey Brodkin if (op == OP_INV) { 50ef639e6fSAlexey Brodkin /* 51ef639e6fSAlexey Brodkin * IM is set by default and implies Flush-n-inv 52ef639e6fSAlexey Brodkin * Clear it here for vanilla inv 53ef639e6fSAlexey Brodkin */ 54ef639e6fSAlexey Brodkin reg = read_aux_reg(ARC_AUX_SLC_CTRL); 55ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 56ef639e6fSAlexey Brodkin } 57ef639e6fSAlexey Brodkin 58ef639e6fSAlexey Brodkin return reg; 59ef639e6fSAlexey Brodkin } 60ef639e6fSAlexey Brodkin 61ef639e6fSAlexey Brodkin static void __after_slc_op(const int op, unsigned int reg) 62ef639e6fSAlexey Brodkin { 6340a808f1SAlexey Brodkin if (op & OP_FLUSH) { /* flush / flush-n-inv both wait */ 6440a808f1SAlexey Brodkin /* 6540a808f1SAlexey Brodkin * Make sure "busy" bit reports correct status, 6640a808f1SAlexey Brodkin * see STAR 9001165532 6740a808f1SAlexey Brodkin */ 6840a808f1SAlexey Brodkin read_aux_reg(ARC_AUX_SLC_CTRL); 69ef639e6fSAlexey Brodkin while (read_aux_reg(ARC_AUX_SLC_CTRL) & 70ef639e6fSAlexey Brodkin DC_CTRL_FLUSH_STATUS) 71ef639e6fSAlexey Brodkin ; 7240a808f1SAlexey Brodkin } 73ef639e6fSAlexey Brodkin 74ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 75ef639e6fSAlexey Brodkin if (op == OP_INV) 76ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 77ef639e6fSAlexey Brodkin } 78ef639e6fSAlexey Brodkin 79ef639e6fSAlexey Brodkin static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, 80ef639e6fSAlexey Brodkin const int op) 81ef639e6fSAlexey Brodkin { 82ef639e6fSAlexey Brodkin unsigned int aux_cmd; 83ef639e6fSAlexey Brodkin int num_lines; 84ef639e6fSAlexey Brodkin 85ef639e6fSAlexey Brodkin #define SLC_LINE_MASK (~(slc_line_sz - 1)) 86ef639e6fSAlexey Brodkin 87ef639e6fSAlexey Brodkin aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; 88ef639e6fSAlexey Brodkin 89ef639e6fSAlexey Brodkin sz += paddr & ~SLC_LINE_MASK; 90ef639e6fSAlexey Brodkin paddr &= SLC_LINE_MASK; 91ef639e6fSAlexey Brodkin 92ef639e6fSAlexey Brodkin num_lines = DIV_ROUND_UP(sz, slc_line_sz); 93ef639e6fSAlexey Brodkin 94ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 95ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 96ef639e6fSAlexey Brodkin paddr += slc_line_sz; 97ef639e6fSAlexey Brodkin } 98ef639e6fSAlexey Brodkin } 99ef639e6fSAlexey Brodkin 100ef639e6fSAlexey Brodkin static inline void __slc_entire_op(const int cacheop) 101ef639e6fSAlexey Brodkin { 102ef639e6fSAlexey Brodkin int aux; 103ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_slc_op(cacheop); 104ef639e6fSAlexey Brodkin 105ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 106ef639e6fSAlexey Brodkin aux = ARC_AUX_SLC_INVALIDATE; 107ef639e6fSAlexey Brodkin else 108ef639e6fSAlexey Brodkin aux = ARC_AUX_SLC_FLUSH; 109ef639e6fSAlexey Brodkin 110ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 111ef639e6fSAlexey Brodkin 112ef639e6fSAlexey Brodkin __after_slc_op(cacheop, ctrl_reg); 113ef639e6fSAlexey Brodkin } 114ef639e6fSAlexey Brodkin 115ef639e6fSAlexey Brodkin static inline void __slc_line_op(unsigned long paddr, unsigned long sz, 116ef639e6fSAlexey Brodkin const int cacheop) 117ef639e6fSAlexey Brodkin { 118ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_slc_op(cacheop); 119ef639e6fSAlexey Brodkin __slc_line_loop(paddr, sz, cacheop); 120ef639e6fSAlexey Brodkin __after_slc_op(cacheop, ctrl_reg); 121ef639e6fSAlexey Brodkin } 122ef639e6fSAlexey Brodkin #else 123ef639e6fSAlexey Brodkin #define __slc_entire_op(cacheop) 124ef639e6fSAlexey Brodkin #define __slc_line_op(paddr, sz, cacheop) 125ef639e6fSAlexey Brodkin #endif 126ef639e6fSAlexey Brodkin 127379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 128379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void) 129ef639e6fSAlexey Brodkin { 130379b3280SAlexey Brodkin union { 131379b3280SAlexey Brodkin struct { 132379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 133379b3280SAlexey Brodkin unsigned int pad:24, way:2, lsz:2, sz:4; 134379b3280SAlexey Brodkin #else 135379b3280SAlexey Brodkin unsigned int sz:4, lsz:2, way:2, pad:24; 136379b3280SAlexey Brodkin #endif 137379b3280SAlexey Brodkin } fields; 138379b3280SAlexey Brodkin unsigned int word; 139379b3280SAlexey Brodkin } slc_cfg; 140379b3280SAlexey Brodkin 141379b3280SAlexey Brodkin union { 142379b3280SAlexey Brodkin struct { 143379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 144379b3280SAlexey Brodkin unsigned int pad:24, ver:8; 145379b3280SAlexey Brodkin #else 146379b3280SAlexey Brodkin unsigned int ver:8, pad:24; 147379b3280SAlexey Brodkin #endif 148379b3280SAlexey Brodkin } fields; 149379b3280SAlexey Brodkin unsigned int word; 150379b3280SAlexey Brodkin } sbcr; 151379b3280SAlexey Brodkin 152379b3280SAlexey Brodkin sbcr.word = read_aux_reg(ARC_BCR_SLC); 153379b3280SAlexey Brodkin if (sbcr.fields.ver) { 154379b3280SAlexey Brodkin slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); 155379b3280SAlexey Brodkin slc_exists = 1; 156379b3280SAlexey Brodkin slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; 157379b3280SAlexey Brodkin } 158db6ce231SAlexey Brodkin 159db6ce231SAlexey Brodkin union { 160db6ce231SAlexey Brodkin struct bcr_clust_cfg { 161db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 162db6ce231SAlexey Brodkin unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8; 163db6ce231SAlexey Brodkin #else 164db6ce231SAlexey Brodkin unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7; 165db6ce231SAlexey Brodkin #endif 166db6ce231SAlexey Brodkin } fields; 167db6ce231SAlexey Brodkin unsigned int word; 168db6ce231SAlexey Brodkin } cbcr; 169db6ce231SAlexey Brodkin 170db6ce231SAlexey Brodkin cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); 171db6ce231SAlexey Brodkin if (cbcr.fields.c) 172db6ce231SAlexey Brodkin ioc_exists = 1; 173379b3280SAlexey Brodkin } 174379b3280SAlexey Brodkin #endif 175379b3280SAlexey Brodkin 176379b3280SAlexey Brodkin void read_decode_cache_bcr(void) 177379b3280SAlexey Brodkin { 178379b3280SAlexey Brodkin int dc_line_sz = 0, ic_line_sz = 0; 179379b3280SAlexey Brodkin 180379b3280SAlexey Brodkin union { 181379b3280SAlexey Brodkin struct { 182379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 183379b3280SAlexey Brodkin unsigned int pad:12, line_len:4, sz:4, config:4, ver:8; 184379b3280SAlexey Brodkin #else 185379b3280SAlexey Brodkin unsigned int ver:8, config:4, sz:4, line_len:4, pad:12; 186379b3280SAlexey Brodkin #endif 187379b3280SAlexey Brodkin } fields; 188379b3280SAlexey Brodkin unsigned int word; 189379b3280SAlexey Brodkin } ibcr, dbcr; 190379b3280SAlexey Brodkin 191379b3280SAlexey Brodkin ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); 192379b3280SAlexey Brodkin if (ibcr.fields.ver) { 193379b3280SAlexey Brodkin icache_exists = 1; 194379b3280SAlexey Brodkin l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; 195379b3280SAlexey Brodkin if (!ic_line_sz) 196379b3280SAlexey Brodkin panic("Instruction exists but line length is 0\n"); 197ef639e6fSAlexey Brodkin } 198ef639e6fSAlexey Brodkin 199379b3280SAlexey Brodkin dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); 200379b3280SAlexey Brodkin if (dbcr.fields.ver){ 201379b3280SAlexey Brodkin dcache_exists = 1; 202379b3280SAlexey Brodkin l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; 203379b3280SAlexey Brodkin if (!dc_line_sz) 204379b3280SAlexey Brodkin panic("Data cache exists but line length is 0\n"); 205379b3280SAlexey Brodkin } 206379b3280SAlexey Brodkin 207379b3280SAlexey Brodkin if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) 208379b3280SAlexey Brodkin panic("Instruction and data cache line lengths differ\n"); 209ef639e6fSAlexey Brodkin } 210ef639e6fSAlexey Brodkin 211ef639e6fSAlexey Brodkin void cache_init(void) 212ef639e6fSAlexey Brodkin { 213379b3280SAlexey Brodkin read_decode_cache_bcr(); 214379b3280SAlexey Brodkin 215ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 216379b3280SAlexey Brodkin read_decode_cache_bcr_arcv2(); 217db6ce231SAlexey Brodkin 218db6ce231SAlexey Brodkin if (ioc_exists) { 21997a63144SAlexey Brodkin /* IOC Aperture start is equal to DDR start */ 22097a63144SAlexey Brodkin unsigned int ap_base = CONFIG_SYS_SDRAM_BASE; 22197a63144SAlexey Brodkin /* IOC Aperture size is equal to DDR size */ 22297a63144SAlexey Brodkin long ap_size = CONFIG_SYS_SDRAM_SIZE; 22397a63144SAlexey Brodkin 224a4a43fcfSAlexey Brodkin flush_dcache_all(); 225a4a43fcfSAlexey Brodkin invalidate_dcache_all(); 226a4a43fcfSAlexey Brodkin 22797a63144SAlexey Brodkin if (!is_power_of_2(ap_size) || ap_size < 4096) 22897a63144SAlexey Brodkin panic("IOC Aperture size must be power of 2 and bigger 4Kib"); 22997a63144SAlexey Brodkin 23097a63144SAlexey Brodkin /* 23197a63144SAlexey Brodkin * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB, 23297a63144SAlexey Brodkin * so setting 0x11 implies 512M, 0x12 implies 1G... 23397a63144SAlexey Brodkin */ 23497a63144SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 23597a63144SAlexey Brodkin order_base_2(ap_size/1024) - 2); 23697a63144SAlexey Brodkin 23797a63144SAlexey Brodkin 23897a63144SAlexey Brodkin /* IOC Aperture start must be aligned to the size of the aperture */ 23997a63144SAlexey Brodkin if (ap_base % ap_size != 0) 24097a63144SAlexey Brodkin panic("IOC Aperture start must be aligned to the size of the aperture"); 24197a63144SAlexey Brodkin 24297a63144SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12); 243db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1); 244db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1); 24597a63144SAlexey Brodkin 246db6ce231SAlexey Brodkin } 247ef639e6fSAlexey Brodkin #endif 248ef639e6fSAlexey Brodkin } 249ef639e6fSAlexey Brodkin 250660d5f0dSAlexey Brodkin int icache_status(void) 251660d5f0dSAlexey Brodkin { 252379b3280SAlexey Brodkin if (!icache_exists) 253660d5f0dSAlexey Brodkin return 0; 254660d5f0dSAlexey Brodkin 255ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) 256ef639e6fSAlexey Brodkin return 0; 257ef639e6fSAlexey Brodkin else 258ef639e6fSAlexey Brodkin return 1; 259660d5f0dSAlexey Brodkin } 260660d5f0dSAlexey Brodkin 261660d5f0dSAlexey Brodkin void icache_enable(void) 262660d5f0dSAlexey Brodkin { 263379b3280SAlexey Brodkin if (icache_exists) 264660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & 265660d5f0dSAlexey Brodkin ~IC_CTRL_CACHE_DISABLE); 266660d5f0dSAlexey Brodkin } 267660d5f0dSAlexey Brodkin 268660d5f0dSAlexey Brodkin void icache_disable(void) 269660d5f0dSAlexey Brodkin { 270379b3280SAlexey Brodkin if (icache_exists) 271660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | 272660d5f0dSAlexey Brodkin IC_CTRL_CACHE_DISABLE); 273660d5f0dSAlexey Brodkin } 274660d5f0dSAlexey Brodkin 275ef639e6fSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 276660d5f0dSAlexey Brodkin void invalidate_icache_all(void) 277660d5f0dSAlexey Brodkin { 278660d5f0dSAlexey Brodkin /* Any write to IC_IVIC register triggers invalidation of entire I$ */ 279ef639e6fSAlexey Brodkin if (icache_status()) { 280660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_IVIC, 1); 281*f2a22678SAlexey Brodkin /* 282*f2a22678SAlexey Brodkin * As per ARC HS databook (see chapter 5.3.3.2) 283*f2a22678SAlexey Brodkin * it is required to add 3 NOPs after each write to IC_IVIC. 284*f2a22678SAlexey Brodkin */ 285*f2a22678SAlexey Brodkin __builtin_arc_nop(); 286*f2a22678SAlexey Brodkin __builtin_arc_nop(); 287*f2a22678SAlexey Brodkin __builtin_arc_nop(); 288ef639e6fSAlexey Brodkin read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ 289660d5f0dSAlexey Brodkin } 290ef639e6fSAlexey Brodkin } 291ef639e6fSAlexey Brodkin #else 292ef639e6fSAlexey Brodkin void invalidate_icache_all(void) 293ef639e6fSAlexey Brodkin { 294ef639e6fSAlexey Brodkin } 295ef639e6fSAlexey Brodkin #endif 296660d5f0dSAlexey Brodkin 297660d5f0dSAlexey Brodkin int dcache_status(void) 298660d5f0dSAlexey Brodkin { 299379b3280SAlexey Brodkin if (!dcache_exists) 300660d5f0dSAlexey Brodkin return 0; 301660d5f0dSAlexey Brodkin 302ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) 303ef639e6fSAlexey Brodkin return 0; 304ef639e6fSAlexey Brodkin else 305ef639e6fSAlexey Brodkin return 1; 306660d5f0dSAlexey Brodkin } 307660d5f0dSAlexey Brodkin 308660d5f0dSAlexey Brodkin void dcache_enable(void) 309660d5f0dSAlexey Brodkin { 310379b3280SAlexey Brodkin if (!dcache_exists) 311660d5f0dSAlexey Brodkin return; 312660d5f0dSAlexey Brodkin 313660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & 314660d5f0dSAlexey Brodkin ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE)); 315660d5f0dSAlexey Brodkin } 316660d5f0dSAlexey Brodkin 317660d5f0dSAlexey Brodkin void dcache_disable(void) 318660d5f0dSAlexey Brodkin { 319379b3280SAlexey Brodkin if (!dcache_exists) 320660d5f0dSAlexey Brodkin return; 321660d5f0dSAlexey Brodkin 322660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | 323660d5f0dSAlexey Brodkin DC_CTRL_CACHE_DISABLE); 324660d5f0dSAlexey Brodkin } 325660d5f0dSAlexey Brodkin 326660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 327660d5f0dSAlexey Brodkin /* 328ef639e6fSAlexey Brodkin * Common Helper for Line Operations on {I,D}-Cache 329660d5f0dSAlexey Brodkin */ 330ef639e6fSAlexey Brodkin static inline void __cache_line_loop(unsigned long paddr, unsigned long sz, 331ef639e6fSAlexey Brodkin const int cacheop) 332660d5f0dSAlexey Brodkin { 333ef639e6fSAlexey Brodkin unsigned int aux_cmd; 334ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 335ef639e6fSAlexey Brodkin unsigned int aux_tag; 336ef639e6fSAlexey Brodkin #endif 337ef639e6fSAlexey Brodkin int num_lines; 338660d5f0dSAlexey Brodkin 339ef639e6fSAlexey Brodkin if (cacheop == OP_INV_IC) { 340ef639e6fSAlexey Brodkin aux_cmd = ARC_AUX_IC_IVIL; 341ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 342ef639e6fSAlexey Brodkin aux_tag = ARC_AUX_IC_PTAG; 343ef639e6fSAlexey Brodkin #endif 344ef639e6fSAlexey Brodkin } else { 345ef639e6fSAlexey Brodkin /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 346ef639e6fSAlexey Brodkin aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL; 347ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 348ef639e6fSAlexey Brodkin aux_tag = ARC_AUX_DC_PTAG; 349ef639e6fSAlexey Brodkin #endif 350660d5f0dSAlexey Brodkin } 351660d5f0dSAlexey Brodkin 352ef639e6fSAlexey Brodkin sz += paddr & ~CACHE_LINE_MASK; 353ef639e6fSAlexey Brodkin paddr &= CACHE_LINE_MASK; 354ef639e6fSAlexey Brodkin 355379b3280SAlexey Brodkin num_lines = DIV_ROUND_UP(sz, l1_line_sz); 356ef639e6fSAlexey Brodkin 357ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 358ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 359ef639e6fSAlexey Brodkin write_aux_reg(aux_tag, paddr); 360ef639e6fSAlexey Brodkin #endif 361ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 362379b3280SAlexey Brodkin paddr += l1_line_sz; 363ef639e6fSAlexey Brodkin } 364ef639e6fSAlexey Brodkin } 365ef639e6fSAlexey Brodkin 366ef639e6fSAlexey Brodkin static unsigned int __before_dc_op(const int op) 367ef639e6fSAlexey Brodkin { 368ef639e6fSAlexey Brodkin unsigned int reg; 369ef639e6fSAlexey Brodkin 370ef639e6fSAlexey Brodkin if (op == OP_INV) { 371ef639e6fSAlexey Brodkin /* 372ef639e6fSAlexey Brodkin * IM is set by default and implies Flush-n-inv 373ef639e6fSAlexey Brodkin * Clear it here for vanilla inv 374ef639e6fSAlexey Brodkin */ 375ef639e6fSAlexey Brodkin reg = read_aux_reg(ARC_AUX_DC_CTRL); 376ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 377ef639e6fSAlexey Brodkin } 378ef639e6fSAlexey Brodkin 379ef639e6fSAlexey Brodkin return reg; 380ef639e6fSAlexey Brodkin } 381ef639e6fSAlexey Brodkin 382ef639e6fSAlexey Brodkin static void __after_dc_op(const int op, unsigned int reg) 383ef639e6fSAlexey Brodkin { 384ef639e6fSAlexey Brodkin if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 385ef639e6fSAlexey Brodkin while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS) 386ef639e6fSAlexey Brodkin ; 387ef639e6fSAlexey Brodkin 388ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 389ef639e6fSAlexey Brodkin if (op == OP_INV) 390ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 391ef639e6fSAlexey Brodkin } 392ef639e6fSAlexey Brodkin 393ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop) 394ef639e6fSAlexey Brodkin { 395ef639e6fSAlexey Brodkin int aux; 396ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 397ef639e6fSAlexey Brodkin 398ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 399ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_IVDC; 400ef639e6fSAlexey Brodkin else 401ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_FLSH; 402ef639e6fSAlexey Brodkin 403ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 404ef639e6fSAlexey Brodkin 405ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 406ef639e6fSAlexey Brodkin } 407ef639e6fSAlexey Brodkin 408ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz, 409ef639e6fSAlexey Brodkin const int cacheop) 410ef639e6fSAlexey Brodkin { 411ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 412ef639e6fSAlexey Brodkin __cache_line_loop(paddr, sz, cacheop); 413ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 414ef639e6fSAlexey Brodkin } 415ef639e6fSAlexey Brodkin #else 416ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop) 417ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop) 418ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */ 419ef639e6fSAlexey Brodkin 420660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end) 421660d5f0dSAlexey Brodkin { 422ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 423db6ce231SAlexey Brodkin if (!ioc_exists) 424db6ce231SAlexey Brodkin #endif 425db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_INV); 426db6ce231SAlexey Brodkin 427db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 428db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 429ef639e6fSAlexey Brodkin __slc_line_op(start, end - start, OP_INV); 430660d5f0dSAlexey Brodkin #endif 431660d5f0dSAlexey Brodkin } 432660d5f0dSAlexey Brodkin 433ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end) 434660d5f0dSAlexey Brodkin { 435ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 436db6ce231SAlexey Brodkin if (!ioc_exists) 437db6ce231SAlexey Brodkin #endif 438db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_FLUSH); 439db6ce231SAlexey Brodkin 440db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 441db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 442ef639e6fSAlexey Brodkin __slc_line_op(start, end - start, OP_FLUSH); 443ef639e6fSAlexey Brodkin #endif 444660d5f0dSAlexey Brodkin } 445660d5f0dSAlexey Brodkin 446660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size) 447660d5f0dSAlexey Brodkin { 448660d5f0dSAlexey Brodkin flush_dcache_range(start, start + size); 449660d5f0dSAlexey Brodkin } 4506eb15e50SAlexey Brodkin 451ef639e6fSAlexey Brodkin void invalidate_dcache_all(void) 452ef639e6fSAlexey Brodkin { 453db6ce231SAlexey Brodkin __dc_entire_op(OP_INV); 454db6ce231SAlexey Brodkin 455db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 456bd91508bSAlexey Brodkin if (slc_exists) 457ef639e6fSAlexey Brodkin __slc_entire_op(OP_INV); 458ef639e6fSAlexey Brodkin #endif 4596eb15e50SAlexey Brodkin } 4606eb15e50SAlexey Brodkin 461ef639e6fSAlexey Brodkin void flush_dcache_all(void) 4626eb15e50SAlexey Brodkin { 463db6ce231SAlexey Brodkin __dc_entire_op(OP_FLUSH); 464db6ce231SAlexey Brodkin 465db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 4662a8382c6SAlexey Brodkin if (slc_exists) 467ef639e6fSAlexey Brodkin __slc_entire_op(OP_FLUSH); 468ef639e6fSAlexey Brodkin #endif 4696eb15e50SAlexey Brodkin } 470