summaryrefslogtreecommitdiff
path: root/arch/arc/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/lib')
-rw-r--r--arch/arc/lib/cache.c175
1 files changed, 132 insertions, 43 deletions
diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c
index ed8e8e7..56988dd 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,14 +25,21 @@
#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");
+int ioc_exists __section(".data");
static unsigned int __before_slc_op(const int op)
{
@@ -111,46 +117,113 @@ 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;
+ }
+
+ union {
+ struct bcr_clust_cfg {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
+#else
+ unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
+#endif
+ } fields;
+ unsigned int word;
+ } cbcr;
+
+ cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
+ if (cbcr.fields.c)
+ ioc_exists = 1;
}
+#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();
+
+ if (ioc_exists) {
+ /* IO coherency base - 0x8z */
+ write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000);
+ /* IO coherency aperture size - 512Mb: 0x8z-0xAz */
+ write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 0x11);
+ /* Enable partial writes */
+ write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
+ /* Enable IO coherency */
+ write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
}
#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 +234,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 +263,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 +274,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 +283,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 +319,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;
}
}
@@ -313,18 +386,26 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
void invalidate_dcache_range(unsigned long start, unsigned long end)
{
- __dc_line_op(start, end - start, OP_INV);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists)
+ if (!ioc_exists)
+#endif
+ __dc_line_op(start, end - start, OP_INV);
+
+#ifdef CONFIG_ISA_ARCV2
+ if (slc_exists && !ioc_exists)
__slc_line_op(start, end - start, OP_INV);
#endif
}
void flush_dcache_range(unsigned long start, unsigned long end)
{
- __dc_line_op(start, end - start, OP_FLUSH);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists)
+ if (!ioc_exists)
+#endif
+ __dc_line_op(start, end - start, OP_FLUSH);
+
+#ifdef CONFIG_ISA_ARCV2
+ if (slc_exists && !ioc_exists)
__slc_line_op(start, end - start, OP_FLUSH);
#endif
}
@@ -336,18 +417,26 @@ void flush_cache(unsigned long start, unsigned long size)
void invalidate_dcache_all(void)
{
- __dc_entire_op(OP_INV);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists)
+ if (!ioc_exists)
+#endif
+ __dc_entire_op(OP_INV);
+
+#ifdef CONFIG_ISA_ARCV2
+ if (slc_exists && !ioc_exists)
__slc_entire_op(OP_INV);
#endif
}
void flush_dcache_all(void)
{
- __dc_entire_op(OP_FLUSH);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists)
+ if (!ioc_exists)
+#endif
+ __dc_entire_op(OP_FLUSH);
+
+#ifdef CONFIG_ISA_ARCV2
+ if (slc_exists && !ioc_exists)
__slc_entire_op(OP_FLUSH);
#endif
}