X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Fu-boot.git;a=blobdiff_plain;f=arch%2Farc%2Flib%2Fcache.c;h=d8741fe959c3fc7ddec39ecaf6bfaa7443cb8d38;hp=ed8e8e74e2a19a414a5aee265605815b1c91ea22;hb=f2a226780fa0e4055bec636b8108bf7e80951174;hpb=1254ff97abb7606ccd0d7bdcd9f22581c50fe535 diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index ed8e8e74e2..d8741fe959 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -5,13 +5,13 @@ */ #include +#include #include #include +#include #include #include -#define CACHE_LINE_MASK (~(CONFIG_SYS_CACHELINE_SIZE - 1)) - /* Bit values in IC_CTRL */ #define IC_CTRL_CACHE_DISABLE (1 << 0) @@ -26,14 +26,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) { @@ -53,10 +60,16 @@ static unsigned int __before_slc_op(const int op) static void __after_slc_op(const int op, unsigned int reg) { - if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ + if (op & OP_FLUSH) { /* flush / flush-n-inv both wait */ + /* + * Make sure "busy" bit reports correct status, + * see STAR 9001165532 + */ + read_aux_reg(ARC_AUX_SLC_CTRL); while (read_aux_reg(ARC_AUX_SLC_CTRL) & DC_CTRL_FLUSH_STATUS) ; + } /* Switch back to default Invalidate mode */ if (op == OP_INV) @@ -111,46 +124,132 @@ 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) { + /* IOC Aperture start is equal to DDR start */ + unsigned int ap_base = CONFIG_SYS_SDRAM_BASE; + /* IOC Aperture size is equal to DDR size */ + long ap_size = CONFIG_SYS_SDRAM_SIZE; + + flush_dcache_all(); + invalidate_dcache_all(); + + if (!is_power_of_2(ap_size) || ap_size < 4096) + panic("IOC Aperture size must be power of 2 and bigger 4Kib"); + + /* + * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB, + * so setting 0x11 implies 512M, 0x12 implies 1G... + */ + write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, + order_base_2(ap_size/1024) - 2); + + + /* IOC Aperture start must be aligned to the size of the aperture */ + if (ap_base % ap_size != 0) + panic("IOC Aperture start must be aligned to the size of the aperture"); + + write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12); + write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1); + 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 +260,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); } @@ -179,6 +278,13 @@ void invalidate_icache_all(void) /* Any write to IC_IVIC register triggers invalidation of entire I$ */ if (icache_status()) { write_aux_reg(ARC_AUX_IC_IVIC, 1); + /* + * As per ARC HS databook (see chapter 5.3.3.2) + * it is required to add 3 NOPs after each write to IC_IVIC. + */ + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ } } @@ -190,7 +296,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 +307,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 +316,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 +352,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 +419,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 } @@ -337,6 +451,7 @@ 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) __slc_entire_op(OP_INV); @@ -346,6 +461,7 @@ void invalidate_dcache_all(void) void flush_dcache_all(void) { __dc_entire_op(OP_FLUSH); + #ifdef CONFIG_ISA_ARCV2 if (slc_exists) __slc_entire_op(OP_FLUSH);