*/
#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)
#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");
#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)
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);
}
int dcache_status(void)
{
- if (!dcache_exists())
+ if (!dcache_exists)
return 0;
if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE)
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) &
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) |
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;
}
}