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 */ 1619b10a42SEugeniy Paltsev #define IC_CTRL_CACHE_DISABLE BIT(0) 17660d5f0dSAlexey Brodkin 18660d5f0dSAlexey Brodkin /* Bit values in DC_CTRL */ 1919b10a42SEugeniy Paltsev #define DC_CTRL_CACHE_DISABLE BIT(0) 2019b10a42SEugeniy Paltsev #define DC_CTRL_INV_MODE_FLUSH BIT(6) 2119b10a42SEugeniy Paltsev #define DC_CTRL_FLUSH_STATUS BIT(8) 22660d5f0dSAlexey Brodkin #define CACHE_VER_NUM_MASK 0xF 23660d5f0dSAlexey Brodkin 24ef639e6fSAlexey Brodkin #define OP_INV 0x1 25ef639e6fSAlexey Brodkin #define OP_FLUSH 0x2 26ef639e6fSAlexey Brodkin 2741cada4dSEugeniy Paltsev /* Bit val in SLC_CONTROL */ 2841cada4dSEugeniy Paltsev #define SLC_CTRL_DIS 0x001 2941cada4dSEugeniy Paltsev #define SLC_CTRL_IM 0x040 3041cada4dSEugeniy Paltsev #define SLC_CTRL_BUSY 0x100 3141cada4dSEugeniy Paltsev #define SLC_CTRL_RGN_OP_INV 0x200 3241cada4dSEugeniy Paltsev 33ef639e6fSAlexey Brodkin /* 34ef639e6fSAlexey Brodkin * By default that variable will fall into .bss section. 35ef639e6fSAlexey Brodkin * But .bss section is not relocated and so it will be initilized before 36ef639e6fSAlexey Brodkin * relocation but will be used after being zeroed. 37ef639e6fSAlexey Brodkin */ 38379b3280SAlexey Brodkin int l1_line_sz __section(".data"); 393cf23939SEugeniy Paltsev bool dcache_exists __section(".data") = false; 403cf23939SEugeniy Paltsev bool icache_exists __section(".data") = false; 41379b3280SAlexey Brodkin 42379b3280SAlexey Brodkin #define CACHE_LINE_MASK (~(l1_line_sz - 1)) 43379b3280SAlexey Brodkin 44379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 45ef639e6fSAlexey Brodkin int slc_line_sz __section(".data"); 463cf23939SEugeniy Paltsev bool slc_exists __section(".data") = false; 473cf23939SEugeniy Paltsev bool ioc_exists __section(".data") = false; 4841cada4dSEugeniy Paltsev bool pae_exists __section(".data") = false; 49ef639e6fSAlexey Brodkin 50b0146f9eSEugeniy Paltsev /* To force enable IOC set ioc_enable to 'true' */ 51b0146f9eSEugeniy Paltsev bool ioc_enable __section(".data") = false; 52b0146f9eSEugeniy Paltsev 5341cada4dSEugeniy Paltsev void read_decode_mmu_bcr(void) 54ef639e6fSAlexey Brodkin { 5541cada4dSEugeniy Paltsev /* TODO: should we compare mmu version from BCR and from CONFIG? */ 5641cada4dSEugeniy Paltsev #if (CONFIG_ARC_MMU_VER >= 4) 5741cada4dSEugeniy Paltsev u32 tmp; 58ef639e6fSAlexey Brodkin 5941cada4dSEugeniy Paltsev tmp = read_aux_reg(ARC_AUX_MMU_BCR); 60ef639e6fSAlexey Brodkin 6141cada4dSEugeniy Paltsev struct bcr_mmu_4 { 6241cada4dSEugeniy Paltsev #ifdef CONFIG_CPU_BIG_ENDIAN 6341cada4dSEugeniy Paltsev unsigned int ver:8, sasid:1, sz1:4, sz0:4, res:2, pae:1, 6441cada4dSEugeniy Paltsev n_ways:2, n_entry:2, n_super:2, u_itlb:3, u_dtlb:3; 65ef639e6fSAlexey Brodkin #else 6641cada4dSEugeniy Paltsev /* DTLB ITLB JES JE JA */ 6741cada4dSEugeniy Paltsev unsigned int u_dtlb:3, u_itlb:3, n_super:2, n_entry:2, n_ways:2, 6841cada4dSEugeniy Paltsev pae:1, res:2, sz0:4, sz1:4, sasid:1, ver:8; 6941cada4dSEugeniy Paltsev #endif /* CONFIG_CPU_BIG_ENDIAN */ 7041cada4dSEugeniy Paltsev } *mmu4; 7141cada4dSEugeniy Paltsev 7241cada4dSEugeniy Paltsev mmu4 = (struct bcr_mmu_4 *)&tmp; 7341cada4dSEugeniy Paltsev 7441cada4dSEugeniy Paltsev pae_exists = !!mmu4->pae; 7541cada4dSEugeniy Paltsev #endif /* (CONFIG_ARC_MMU_VER >= 4) */ 7641cada4dSEugeniy Paltsev } 7741cada4dSEugeniy Paltsev 7841cada4dSEugeniy Paltsev static void __slc_entire_op(const int op) 7941cada4dSEugeniy Paltsev { 8041cada4dSEugeniy Paltsev unsigned int ctrl; 8141cada4dSEugeniy Paltsev 8241cada4dSEugeniy Paltsev ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); 8341cada4dSEugeniy Paltsev 8441cada4dSEugeniy Paltsev if (!(op & OP_FLUSH)) /* i.e. OP_INV */ 8541cada4dSEugeniy Paltsev ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ 8641cada4dSEugeniy Paltsev else 8741cada4dSEugeniy Paltsev ctrl |= SLC_CTRL_IM; 8841cada4dSEugeniy Paltsev 8941cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_CTRL, ctrl); 9041cada4dSEugeniy Paltsev 9141cada4dSEugeniy Paltsev if (op & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 9241cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1); 9341cada4dSEugeniy Paltsev else 9441cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1); 9541cada4dSEugeniy Paltsev 9641cada4dSEugeniy Paltsev /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ 9741cada4dSEugeniy Paltsev read_aux_reg(ARC_AUX_SLC_CTRL); 9841cada4dSEugeniy Paltsev 9941cada4dSEugeniy Paltsev /* Important to wait for flush to complete */ 10041cada4dSEugeniy Paltsev while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); 10141cada4dSEugeniy Paltsev } 10241cada4dSEugeniy Paltsev 10341cada4dSEugeniy Paltsev static void slc_upper_region_init(void) 10441cada4dSEugeniy Paltsev { 10541cada4dSEugeniy Paltsev /* 10641cada4dSEugeniy Paltsev * ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1 are always == 0 10741cada4dSEugeniy Paltsev * as we don't use PAE40. 10841cada4dSEugeniy Paltsev */ 10941cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_RGN_END1, 0); 11041cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_RGN_START1, 0); 11141cada4dSEugeniy Paltsev } 11241cada4dSEugeniy Paltsev 11341cada4dSEugeniy Paltsev static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op) 11441cada4dSEugeniy Paltsev { 11541cada4dSEugeniy Paltsev unsigned int ctrl; 11641cada4dSEugeniy Paltsev unsigned long end; 11741cada4dSEugeniy Paltsev 11841cada4dSEugeniy Paltsev /* 11941cada4dSEugeniy Paltsev * The Region Flush operation is specified by CTRL.RGN_OP[11..9] 12041cada4dSEugeniy Paltsev * - b'000 (default) is Flush, 12141cada4dSEugeniy Paltsev * - b'001 is Invalidate if CTRL.IM == 0 12241cada4dSEugeniy Paltsev * - b'001 is Flush-n-Invalidate if CTRL.IM == 1 12341cada4dSEugeniy Paltsev */ 12441cada4dSEugeniy Paltsev ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); 12541cada4dSEugeniy Paltsev 12641cada4dSEugeniy Paltsev /* Don't rely on default value of IM bit */ 12741cada4dSEugeniy Paltsev if (!(op & OP_FLUSH)) /* i.e. OP_INV */ 12841cada4dSEugeniy Paltsev ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ 12941cada4dSEugeniy Paltsev else 13041cada4dSEugeniy Paltsev ctrl |= SLC_CTRL_IM; 13141cada4dSEugeniy Paltsev 13241cada4dSEugeniy Paltsev if (op & OP_INV) 13341cada4dSEugeniy Paltsev ctrl |= SLC_CTRL_RGN_OP_INV; /* Inv or flush-n-inv */ 13441cada4dSEugeniy Paltsev else 13541cada4dSEugeniy Paltsev ctrl &= ~SLC_CTRL_RGN_OP_INV; 13641cada4dSEugeniy Paltsev 13741cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_CTRL, ctrl); 13841cada4dSEugeniy Paltsev 13941cada4dSEugeniy Paltsev /* 14041cada4dSEugeniy Paltsev * Lower bits are ignored, no need to clip 14141cada4dSEugeniy Paltsev * END needs to be setup before START (latter triggers the operation) 14241cada4dSEugeniy Paltsev * END can't be same as START, so add (l2_line_sz - 1) to sz 14341cada4dSEugeniy Paltsev */ 14441cada4dSEugeniy Paltsev end = paddr + sz + slc_line_sz - 1; 14541cada4dSEugeniy Paltsev 14641cada4dSEugeniy Paltsev /* 14741cada4dSEugeniy Paltsev * Upper addresses (ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1) 14841cada4dSEugeniy Paltsev * are always == 0 as we don't use PAE40, so we only setup lower ones 14941cada4dSEugeniy Paltsev * (ARC_AUX_SLC_RGN_END and ARC_AUX_SLC_RGN_START) 15041cada4dSEugeniy Paltsev */ 15141cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_RGN_END, end); 15241cada4dSEugeniy Paltsev write_aux_reg(ARC_AUX_SLC_RGN_START, paddr); 15341cada4dSEugeniy Paltsev 15441cada4dSEugeniy Paltsev /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ 15541cada4dSEugeniy Paltsev read_aux_reg(ARC_AUX_SLC_CTRL); 15641cada4dSEugeniy Paltsev 15741cada4dSEugeniy Paltsev while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); 15841cada4dSEugeniy Paltsev } 15941cada4dSEugeniy Paltsev #endif /* CONFIG_ISA_ARCV2 */ 160ef639e6fSAlexey Brodkin 161379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 162379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void) 163ef639e6fSAlexey Brodkin { 164379b3280SAlexey Brodkin union { 165379b3280SAlexey Brodkin struct { 166379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 167379b3280SAlexey Brodkin unsigned int pad:24, way:2, lsz:2, sz:4; 168379b3280SAlexey Brodkin #else 169379b3280SAlexey Brodkin unsigned int sz:4, lsz:2, way:2, pad:24; 170379b3280SAlexey Brodkin #endif 171379b3280SAlexey Brodkin } fields; 172379b3280SAlexey Brodkin unsigned int word; 173379b3280SAlexey Brodkin } slc_cfg; 174379b3280SAlexey Brodkin 175379b3280SAlexey Brodkin union { 176379b3280SAlexey Brodkin struct { 177379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 178379b3280SAlexey Brodkin unsigned int pad:24, ver:8; 179379b3280SAlexey Brodkin #else 180379b3280SAlexey Brodkin unsigned int ver:8, pad:24; 181379b3280SAlexey Brodkin #endif 182379b3280SAlexey Brodkin } fields; 183379b3280SAlexey Brodkin unsigned int word; 184379b3280SAlexey Brodkin } sbcr; 185379b3280SAlexey Brodkin 186379b3280SAlexey Brodkin sbcr.word = read_aux_reg(ARC_BCR_SLC); 187379b3280SAlexey Brodkin if (sbcr.fields.ver) { 188379b3280SAlexey Brodkin slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); 1893cf23939SEugeniy Paltsev slc_exists = true; 190379b3280SAlexey Brodkin slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; 191379b3280SAlexey Brodkin } 192db6ce231SAlexey Brodkin 193db6ce231SAlexey Brodkin union { 194db6ce231SAlexey Brodkin struct bcr_clust_cfg { 195db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 196db6ce231SAlexey Brodkin unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8; 197db6ce231SAlexey Brodkin #else 198db6ce231SAlexey Brodkin unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7; 199db6ce231SAlexey Brodkin #endif 200db6ce231SAlexey Brodkin } fields; 201db6ce231SAlexey Brodkin unsigned int word; 202db6ce231SAlexey Brodkin } cbcr; 203db6ce231SAlexey Brodkin 204db6ce231SAlexey Brodkin cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); 205b0146f9eSEugeniy Paltsev if (cbcr.fields.c && ioc_enable) 2063cf23939SEugeniy Paltsev ioc_exists = true; 207379b3280SAlexey Brodkin } 208379b3280SAlexey Brodkin #endif 209379b3280SAlexey Brodkin 210379b3280SAlexey Brodkin void read_decode_cache_bcr(void) 211379b3280SAlexey Brodkin { 212379b3280SAlexey Brodkin int dc_line_sz = 0, ic_line_sz = 0; 213379b3280SAlexey Brodkin 214379b3280SAlexey Brodkin union { 215379b3280SAlexey Brodkin struct { 216379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN 217379b3280SAlexey Brodkin unsigned int pad:12, line_len:4, sz:4, config:4, ver:8; 218379b3280SAlexey Brodkin #else 219379b3280SAlexey Brodkin unsigned int ver:8, config:4, sz:4, line_len:4, pad:12; 220379b3280SAlexey Brodkin #endif 221379b3280SAlexey Brodkin } fields; 222379b3280SAlexey Brodkin unsigned int word; 223379b3280SAlexey Brodkin } ibcr, dbcr; 224379b3280SAlexey Brodkin 225379b3280SAlexey Brodkin ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); 226379b3280SAlexey Brodkin if (ibcr.fields.ver) { 2273cf23939SEugeniy Paltsev icache_exists = true; 228379b3280SAlexey Brodkin l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; 229379b3280SAlexey Brodkin if (!ic_line_sz) 230379b3280SAlexey Brodkin panic("Instruction exists but line length is 0\n"); 231ef639e6fSAlexey Brodkin } 232ef639e6fSAlexey Brodkin 233379b3280SAlexey Brodkin dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); 234379b3280SAlexey Brodkin if (dbcr.fields.ver) { 2353cf23939SEugeniy Paltsev dcache_exists = true; 236379b3280SAlexey Brodkin l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; 237379b3280SAlexey Brodkin if (!dc_line_sz) 238379b3280SAlexey Brodkin panic("Data cache exists but line length is 0\n"); 239379b3280SAlexey Brodkin } 240379b3280SAlexey Brodkin 241379b3280SAlexey Brodkin if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) 242379b3280SAlexey Brodkin panic("Instruction and data cache line lengths differ\n"); 243ef639e6fSAlexey Brodkin } 244ef639e6fSAlexey Brodkin 245ef639e6fSAlexey Brodkin void cache_init(void) 246ef639e6fSAlexey Brodkin { 247379b3280SAlexey Brodkin read_decode_cache_bcr(); 248379b3280SAlexey Brodkin 249ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 250379b3280SAlexey Brodkin read_decode_cache_bcr_arcv2(); 251db6ce231SAlexey Brodkin 252db6ce231SAlexey Brodkin if (ioc_exists) { 25397a63144SAlexey Brodkin /* IOC Aperture start is equal to DDR start */ 25497a63144SAlexey Brodkin unsigned int ap_base = CONFIG_SYS_SDRAM_BASE; 25597a63144SAlexey Brodkin /* IOC Aperture size is equal to DDR size */ 25697a63144SAlexey Brodkin long ap_size = CONFIG_SYS_SDRAM_SIZE; 25797a63144SAlexey Brodkin 258a4a43fcfSAlexey Brodkin flush_dcache_all(); 259a4a43fcfSAlexey Brodkin invalidate_dcache_all(); 260a4a43fcfSAlexey Brodkin 26197a63144SAlexey Brodkin if (!is_power_of_2(ap_size) || ap_size < 4096) 26297a63144SAlexey Brodkin panic("IOC Aperture size must be power of 2 and bigger 4Kib"); 26397a63144SAlexey Brodkin 26497a63144SAlexey Brodkin /* 26597a63144SAlexey Brodkin * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB, 26697a63144SAlexey Brodkin * so setting 0x11 implies 512M, 0x12 implies 1G... 26797a63144SAlexey Brodkin */ 26897a63144SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 26997a63144SAlexey Brodkin order_base_2(ap_size / 1024) - 2); 27097a63144SAlexey Brodkin 27197a63144SAlexey Brodkin /* IOC Aperture start must be aligned to the size of the aperture */ 27297a63144SAlexey Brodkin if (ap_base % ap_size != 0) 27397a63144SAlexey Brodkin panic("IOC Aperture start must be aligned to the size of the aperture"); 27497a63144SAlexey Brodkin 27597a63144SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12); 276db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1); 277db6ce231SAlexey Brodkin write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1); 278db6ce231SAlexey Brodkin } 27941cada4dSEugeniy Paltsev 28041cada4dSEugeniy Paltsev read_decode_mmu_bcr(); 28141cada4dSEugeniy Paltsev 28241cada4dSEugeniy Paltsev /* 28341cada4dSEugeniy Paltsev * ARC_AUX_SLC_RGN_START1 and ARC_AUX_SLC_RGN_END1 register exist 28441cada4dSEugeniy Paltsev * only if PAE exists in current HW. So we had to check pae_exist 28541cada4dSEugeniy Paltsev * before using them. 28641cada4dSEugeniy Paltsev */ 28741cada4dSEugeniy Paltsev if (slc_exists && pae_exists) 28841cada4dSEugeniy Paltsev slc_upper_region_init(); 28941cada4dSEugeniy Paltsev #endif /* CONFIG_ISA_ARCV2 */ 290ef639e6fSAlexey Brodkin } 291ef639e6fSAlexey Brodkin 292660d5f0dSAlexey Brodkin int icache_status(void) 293660d5f0dSAlexey Brodkin { 294379b3280SAlexey Brodkin if (!icache_exists) 295660d5f0dSAlexey Brodkin return 0; 296660d5f0dSAlexey Brodkin 297ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) 298ef639e6fSAlexey Brodkin return 0; 299ef639e6fSAlexey Brodkin else 300ef639e6fSAlexey Brodkin return 1; 301660d5f0dSAlexey Brodkin } 302660d5f0dSAlexey Brodkin 303660d5f0dSAlexey Brodkin void icache_enable(void) 304660d5f0dSAlexey Brodkin { 305379b3280SAlexey Brodkin if (icache_exists) 306660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & 307660d5f0dSAlexey Brodkin ~IC_CTRL_CACHE_DISABLE); 308660d5f0dSAlexey Brodkin } 309660d5f0dSAlexey Brodkin 310660d5f0dSAlexey Brodkin void icache_disable(void) 311660d5f0dSAlexey Brodkin { 312379b3280SAlexey Brodkin if (icache_exists) 313660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | 314660d5f0dSAlexey Brodkin IC_CTRL_CACHE_DISABLE); 315660d5f0dSAlexey Brodkin } 316660d5f0dSAlexey Brodkin 31716aeee81SEugeniy Paltsev /* IC supports only invalidation */ 31816aeee81SEugeniy Paltsev static inline void __ic_entire_invalidate(void) 319660d5f0dSAlexey Brodkin { 32016aeee81SEugeniy Paltsev if (!icache_status()) 32116aeee81SEugeniy Paltsev return; 32216aeee81SEugeniy Paltsev 323660d5f0dSAlexey Brodkin /* Any write to IC_IVIC register triggers invalidation of entire I$ */ 324660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_IC_IVIC, 1); 325f2a22678SAlexey Brodkin /* 326f2a22678SAlexey Brodkin * As per ARC HS databook (see chapter 5.3.3.2) 327f2a22678SAlexey Brodkin * it is required to add 3 NOPs after each write to IC_IVIC. 328f2a22678SAlexey Brodkin */ 329f2a22678SAlexey Brodkin __builtin_arc_nop(); 330f2a22678SAlexey Brodkin __builtin_arc_nop(); 331f2a22678SAlexey Brodkin __builtin_arc_nop(); 332ef639e6fSAlexey Brodkin read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ 333660d5f0dSAlexey Brodkin } 33441cada4dSEugeniy Paltsev 33516aeee81SEugeniy Paltsev void invalidate_icache_all(void) 33616aeee81SEugeniy Paltsev { 33716aeee81SEugeniy Paltsev __ic_entire_invalidate(); 33816aeee81SEugeniy Paltsev 33941cada4dSEugeniy Paltsev #ifdef CONFIG_ISA_ARCV2 34041cada4dSEugeniy Paltsev if (slc_exists) 34141cada4dSEugeniy Paltsev __slc_entire_op(OP_INV); 342ef639e6fSAlexey Brodkin #endif 34341cada4dSEugeniy Paltsev } 344660d5f0dSAlexey Brodkin 345660d5f0dSAlexey Brodkin int dcache_status(void) 346660d5f0dSAlexey Brodkin { 347379b3280SAlexey Brodkin if (!dcache_exists) 348660d5f0dSAlexey Brodkin return 0; 349660d5f0dSAlexey Brodkin 350ef639e6fSAlexey Brodkin if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) 351ef639e6fSAlexey Brodkin return 0; 352ef639e6fSAlexey Brodkin else 353ef639e6fSAlexey Brodkin return 1; 354660d5f0dSAlexey Brodkin } 355660d5f0dSAlexey Brodkin 356660d5f0dSAlexey Brodkin void dcache_enable(void) 357660d5f0dSAlexey Brodkin { 358379b3280SAlexey Brodkin if (!dcache_exists) 359660d5f0dSAlexey Brodkin return; 360660d5f0dSAlexey Brodkin 361660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & 362660d5f0dSAlexey Brodkin ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE)); 363660d5f0dSAlexey Brodkin } 364660d5f0dSAlexey Brodkin 365660d5f0dSAlexey Brodkin void dcache_disable(void) 366660d5f0dSAlexey Brodkin { 367379b3280SAlexey Brodkin if (!dcache_exists) 368660d5f0dSAlexey Brodkin return; 369660d5f0dSAlexey Brodkin 370660d5f0dSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | 371660d5f0dSAlexey Brodkin DC_CTRL_CACHE_DISABLE); 372660d5f0dSAlexey Brodkin } 373660d5f0dSAlexey Brodkin 374660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF 375*c4ef14d2SEugeniy Paltsev /* Common Helper for Line Operations on D-cache */ 376*c4ef14d2SEugeniy Paltsev static inline void __dcache_line_loop(unsigned long paddr, unsigned long sz, 377ef639e6fSAlexey Brodkin const int cacheop) 378660d5f0dSAlexey Brodkin { 379ef639e6fSAlexey Brodkin unsigned int aux_cmd; 380ef639e6fSAlexey Brodkin int num_lines; 381660d5f0dSAlexey Brodkin 382ef639e6fSAlexey Brodkin /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 383ef639e6fSAlexey Brodkin aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL; 384660d5f0dSAlexey Brodkin 385ef639e6fSAlexey Brodkin sz += paddr & ~CACHE_LINE_MASK; 386ef639e6fSAlexey Brodkin paddr &= CACHE_LINE_MASK; 387ef639e6fSAlexey Brodkin 388379b3280SAlexey Brodkin num_lines = DIV_ROUND_UP(sz, l1_line_sz); 389ef639e6fSAlexey Brodkin 390ef639e6fSAlexey Brodkin while (num_lines-- > 0) { 391ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3) 392*c4ef14d2SEugeniy Paltsev write_aux_reg(ARC_AUX_DC_PTAG, paddr); 393ef639e6fSAlexey Brodkin #endif 394ef639e6fSAlexey Brodkin write_aux_reg(aux_cmd, paddr); 395379b3280SAlexey Brodkin paddr += l1_line_sz; 396ef639e6fSAlexey Brodkin } 397ef639e6fSAlexey Brodkin } 398ef639e6fSAlexey Brodkin 399ef639e6fSAlexey Brodkin static unsigned int __before_dc_op(const int op) 400ef639e6fSAlexey Brodkin { 401ef639e6fSAlexey Brodkin unsigned int reg; 402ef639e6fSAlexey Brodkin 403ef639e6fSAlexey Brodkin if (op == OP_INV) { 404ef639e6fSAlexey Brodkin /* 405ef639e6fSAlexey Brodkin * IM is set by default and implies Flush-n-inv 406ef639e6fSAlexey Brodkin * Clear it here for vanilla inv 407ef639e6fSAlexey Brodkin */ 408ef639e6fSAlexey Brodkin reg = read_aux_reg(ARC_AUX_DC_CTRL); 409ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); 410ef639e6fSAlexey Brodkin } 411ef639e6fSAlexey Brodkin 412ef639e6fSAlexey Brodkin return reg; 413ef639e6fSAlexey Brodkin } 414ef639e6fSAlexey Brodkin 415ef639e6fSAlexey Brodkin static void __after_dc_op(const int op, unsigned int reg) 416ef639e6fSAlexey Brodkin { 417ef639e6fSAlexey Brodkin if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ 41819b10a42SEugeniy Paltsev while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); 419ef639e6fSAlexey Brodkin 420ef639e6fSAlexey Brodkin /* Switch back to default Invalidate mode */ 421ef639e6fSAlexey Brodkin if (op == OP_INV) 422ef639e6fSAlexey Brodkin write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); 423ef639e6fSAlexey Brodkin } 424ef639e6fSAlexey Brodkin 425ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop) 426ef639e6fSAlexey Brodkin { 427ef639e6fSAlexey Brodkin int aux; 428ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 429ef639e6fSAlexey Brodkin 430ef639e6fSAlexey Brodkin if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ 431ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_IVDC; 432ef639e6fSAlexey Brodkin else 433ef639e6fSAlexey Brodkin aux = ARC_AUX_DC_FLSH; 434ef639e6fSAlexey Brodkin 435ef639e6fSAlexey Brodkin write_aux_reg(aux, 0x1); 436ef639e6fSAlexey Brodkin 437ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 438ef639e6fSAlexey Brodkin } 439ef639e6fSAlexey Brodkin 440ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz, 441ef639e6fSAlexey Brodkin const int cacheop) 442ef639e6fSAlexey Brodkin { 443ef639e6fSAlexey Brodkin unsigned int ctrl_reg = __before_dc_op(cacheop); 44419b10a42SEugeniy Paltsev 445*c4ef14d2SEugeniy Paltsev __dcache_line_loop(paddr, sz, cacheop); 446ef639e6fSAlexey Brodkin __after_dc_op(cacheop, ctrl_reg); 447ef639e6fSAlexey Brodkin } 448ef639e6fSAlexey Brodkin #else 449ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop) 450ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop) 451ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */ 452ef639e6fSAlexey Brodkin 453660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end) 454660d5f0dSAlexey Brodkin { 45541cada4dSEugeniy Paltsev if (start >= end) 45641cada4dSEugeniy Paltsev return; 45741cada4dSEugeniy Paltsev 458ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 459db6ce231SAlexey Brodkin if (!ioc_exists) 460db6ce231SAlexey Brodkin #endif 461db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_INV); 462db6ce231SAlexey Brodkin 463db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 464db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 46541cada4dSEugeniy Paltsev __slc_rgn_op(start, end - start, OP_INV); 466660d5f0dSAlexey Brodkin #endif 467660d5f0dSAlexey Brodkin } 468660d5f0dSAlexey Brodkin 469ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end) 470660d5f0dSAlexey Brodkin { 47141cada4dSEugeniy Paltsev if (start >= end) 47241cada4dSEugeniy Paltsev return; 47341cada4dSEugeniy Paltsev 474ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 475db6ce231SAlexey Brodkin if (!ioc_exists) 476db6ce231SAlexey Brodkin #endif 477db6ce231SAlexey Brodkin __dc_line_op(start, end - start, OP_FLUSH); 478db6ce231SAlexey Brodkin 479db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 480db6ce231SAlexey Brodkin if (slc_exists && !ioc_exists) 48141cada4dSEugeniy Paltsev __slc_rgn_op(start, end - start, OP_FLUSH); 482ef639e6fSAlexey Brodkin #endif 483660d5f0dSAlexey Brodkin } 484660d5f0dSAlexey Brodkin 485660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size) 486660d5f0dSAlexey Brodkin { 487660d5f0dSAlexey Brodkin flush_dcache_range(start, start + size); 488660d5f0dSAlexey Brodkin } 4896eb15e50SAlexey Brodkin 490ef639e6fSAlexey Brodkin void invalidate_dcache_all(void) 491ef639e6fSAlexey Brodkin { 492db6ce231SAlexey Brodkin __dc_entire_op(OP_INV); 493db6ce231SAlexey Brodkin 494db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 495bd91508bSAlexey Brodkin if (slc_exists) 496ef639e6fSAlexey Brodkin __slc_entire_op(OP_INV); 497ef639e6fSAlexey Brodkin #endif 4986eb15e50SAlexey Brodkin } 4996eb15e50SAlexey Brodkin 500ef639e6fSAlexey Brodkin void flush_dcache_all(void) 5016eb15e50SAlexey Brodkin { 502db6ce231SAlexey Brodkin __dc_entire_op(OP_FLUSH); 503db6ce231SAlexey Brodkin 504db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2 5052a8382c6SAlexey Brodkin if (slc_exists) 506ef639e6fSAlexey Brodkin __slc_entire_op(OP_FLUSH); 507ef639e6fSAlexey Brodkin #endif 5086eb15e50SAlexey Brodkin } 509