summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arc/Kconfig11
-rw-r--r--arch/arc/include/asm/cache.h14
-rw-r--r--arch/arc/lib/cache.c118
3 files changed, 89 insertions, 54 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 264c83d261..f1dc6c8d77 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -116,17 +116,6 @@ config SYS_DCACHE_OFF
bool "Do not use Data Cache"
default n
-config ARC_CACHE_LINE_SHIFT
- int "Cache Line Length (as power of 2)"
- range 5 7
- default "6"
- depends on !SYS_DCACHE_OFF || !SYS_ICACHE_OFF
- help
- Starting with ARC700 4.9, Cache line length is configurable,
- This option specifies "N", with Line-len = 2 power N
- So line lengths of 32, 64, 128 are specified by 5,6,7, respectively
- Linux only supports same line lengths for I and D caches.
-
choice
prompt "Target select"
default TARGET_AXS101
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index 432606a433..d26d9fb18d 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -9,13 +9,13 @@
#include <config.h>
-#ifdef CONFIG_ARC_CACHE_LINE_SHIFT
-#define CONFIG_SYS_CACHELINE_SIZE (1 << CONFIG_ARC_CACHE_LINE_SHIFT)
-#define ARCH_DMA_MINALIGN CONFIG_SYS_CACHELINE_SIZE
-#else
-/* Satisfy users of ARCH_DMA_MINALIGN */
-#define ARCH_DMA_MINALIGN 128
-#endif
+/*
+ * As of today we may handle any L1 cache line length right in software.
+ * For that essentially cache line length is a variable not constant.
+ * And to satisfy users of ARCH_DMA_MINALIGN we just use largest line length
+ * that may exist in either L1 or L2 (AKA SLC) caches on ARC.
+ */
+#define ARCH_DMA_MINALIGN 128
#if defined(ARC_MMU_ABSENT)
#define CONFIG_ARC_MMU_VER 0
diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c
index ed8e8e74e2..8089f9df1e 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;
}
}