diff options
Diffstat (limited to 'arch/arc/lib/cache.c')
-rw-r--r-- | arch/arc/lib/cache.c | 118 |
1 files changed, 82 insertions, 36 deletions
diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index ed8e8e74e2a..8089f9df1e2 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -5,13 +5,12 @@ */ #include <config.h> +#include <common.h> #include <linux/compiler.h> #include <linux/kernel.h> #include <asm/arcregs.h> #include <asm/cache.h> -#define CACHE_LINE_MASK (~(CONFIG_SYS_CACHELINE_SIZE - 1)) - /* Bit values in IC_CTRL */ #define IC_CTRL_CACHE_DISABLE (1 << 0) @@ -26,12 +25,18 @@ #define OP_FLUSH 0x2 #define OP_INV_IC 0x3 -#ifdef CONFIG_ISA_ARCV2 /* * By default that variable will fall into .bss section. * But .bss section is not relocated and so it will be initilized before * relocation but will be used after being zeroed. */ +int l1_line_sz __section(".data"); +int dcache_exists __section(".data"); +int icache_exists __section(".data"); + +#define CACHE_LINE_MASK (~(l1_line_sz - 1)) + +#ifdef CONFIG_ISA_ARCV2 int slc_line_sz __section(".data"); int slc_exists __section(".data"); @@ -111,46 +116,87 @@ static inline void __slc_line_op(unsigned long paddr, unsigned long sz, #define __slc_line_op(paddr, sz, cacheop) #endif -static inline int icache_exists(void) +#ifdef CONFIG_ISA_ARCV2 +static void read_decode_cache_bcr_arcv2(void) { - /* Check if Instruction Cache is available */ - if (read_aux_reg(ARC_BCR_IC_BUILD) & CACHE_VER_NUM_MASK) - return 1; - else - return 0; + union { + struct { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad:24, way:2, lsz:2, sz:4; +#else + unsigned int sz:4, lsz:2, way:2, pad:24; +#endif + } fields; + unsigned int word; + } slc_cfg; + + union { + struct { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad:24, ver:8; +#else + unsigned int ver:8, pad:24; +#endif + } fields; + unsigned int word; + } sbcr; + + sbcr.word = read_aux_reg(ARC_BCR_SLC); + if (sbcr.fields.ver) { + slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); + slc_exists = 1; + slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; + } } +#endif -static inline int dcache_exists(void) +void read_decode_cache_bcr(void) { - /* Check if Data Cache is available */ - if (read_aux_reg(ARC_BCR_DC_BUILD) & CACHE_VER_NUM_MASK) - return 1; - else - return 0; + int dc_line_sz = 0, ic_line_sz = 0; + + union { + struct { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad:12, line_len:4, sz:4, config:4, ver:8; +#else + unsigned int ver:8, config:4, sz:4, line_len:4, pad:12; +#endif + } fields; + unsigned int word; + } ibcr, dbcr; + + ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); + if (ibcr.fields.ver) { + icache_exists = 1; + l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; + if (!ic_line_sz) + panic("Instruction exists but line length is 0\n"); + } + + dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); + if (dbcr.fields.ver){ + dcache_exists = 1; + l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; + if (!dc_line_sz) + panic("Data cache exists but line length is 0\n"); + } + + if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) + panic("Instruction and data cache line lengths differ\n"); } void cache_init(void) { + read_decode_cache_bcr(); + #ifdef CONFIG_ISA_ARCV2 - /* Check if System-Level Cache (SLC) is available */ - if (read_aux_reg(ARC_BCR_SLC) & CACHE_VER_NUM_MASK) { -#define LSIZE_OFFSET 4 -#define LSIZE_MASK 3 - if (read_aux_reg(ARC_AUX_SLC_CONFIG) & - (LSIZE_MASK << LSIZE_OFFSET)) - slc_line_sz = 64; - else - slc_line_sz = 128; - slc_exists = 1; - } else { - slc_exists = 0; - } + read_decode_cache_bcr_arcv2(); #endif } int icache_status(void) { - if (!icache_exists()) + if (!icache_exists) return 0; if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE) @@ -161,14 +207,14 @@ int icache_status(void) void icache_enable(void) { - if (icache_exists()) + if (icache_exists) write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) & ~IC_CTRL_CACHE_DISABLE); } void icache_disable(void) { - if (icache_exists()) + if (icache_exists) write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) | IC_CTRL_CACHE_DISABLE); } @@ -190,7 +236,7 @@ void invalidate_icache_all(void) int dcache_status(void) { - if (!dcache_exists()) + if (!dcache_exists) return 0; if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE) @@ -201,7 +247,7 @@ int dcache_status(void) void dcache_enable(void) { - if (!dcache_exists()) + if (!dcache_exists) return; write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) & @@ -210,7 +256,7 @@ void dcache_enable(void) void dcache_disable(void) { - if (!dcache_exists()) + if (!dcache_exists) return; write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) | @@ -246,14 +292,14 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long sz, sz += paddr & ~CACHE_LINE_MASK; paddr &= CACHE_LINE_MASK; - num_lines = DIV_ROUND_UP(sz, CONFIG_SYS_CACHELINE_SIZE); + num_lines = DIV_ROUND_UP(sz, l1_line_sz); while (num_lines-- > 0) { #if (CONFIG_ARC_MMU_VER == 3) write_aux_reg(aux_tag, paddr); #endif write_aux_reg(aux_cmd, paddr); - paddr += CONFIG_SYS_CACHELINE_SIZE; + paddr += l1_line_sz; } } |