From fa476f75bfff55772f0ebde3d5e02dc745e70f40 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:42 +0000 Subject: mips32: detect L1 cache sizes if they're not defined For boards such as the MIPS Malta with an FPGA core card it is desirable to be able to detect the L1 cache sizes at runtime, since they are not dependant upon the board but on the FPGA bitstream in use. This patch performs that detection when the CONFIG_SYS_[DI]CACHE_SIZE macros are not defined by the board configuration. In cases where the sizes are detected this patch also removes the restriction that the I-cache & D-cache line sizes must be the same, as this is not necessarily true. If the cache sizes are defined by a configuration then they will be hardcoded as before, so this patch will not add overhead to such boards. Signed-off-by: Paul Burton --- arch/mips/cpu/mips32/cpu.c | 73 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 6 deletions(-) (limited to 'arch/mips/cpu/mips32/cpu.c') diff --git a/arch/mips/cpu/mips32/cpu.c b/arch/mips/cpu/mips32/cpu.c index 28d5c4568..278865b6f 100644 --- a/arch/mips/cpu/mips32/cpu.c +++ b/arch/mips/cpu/mips32/cpu.c @@ -34,28 +34,89 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } +#ifdef CONFIG_SYS_CACHELINE_SIZE + +static inline unsigned long icache_line_size(void) +{ + return CONFIG_SYS_CACHELINE_SIZE; +} + +static inline unsigned long dcache_line_size(void) +{ + return CONFIG_SYS_CACHELINE_SIZE; +} + +#else /* !CONFIG_SYS_CACHELINE_SIZE */ + +static inline unsigned long icache_line_size(void) +{ + unsigned long conf1, il; + conf1 = read_c0_config1(); + il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHIFT; + if (!il) + return 0; + return 2 << il; +} + +static inline unsigned long dcache_line_size(void) +{ + unsigned long conf1, dl; + conf1 = read_c0_config1(); + dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHIFT; + if (!dl) + return 0; + return 2 << dl; +} + +#endif /* !CONFIG_SYS_CACHELINE_SIZE */ + void flush_cache(ulong start_addr, ulong size) { - unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; - unsigned long addr = start_addr & ~(lsize - 1); - unsigned long aend = (start_addr + size - 1) & ~(lsize - 1); + unsigned long ilsize = icache_line_size(); + unsigned long dlsize = dcache_line_size(); + unsigned long addr, aend; /* aend will be miscalculated when size is zero, so we return here */ if (size == 0) return; + addr = start_addr & ~(dlsize - 1); + aend = (start_addr + size - 1) & ~(dlsize - 1); + + if (ilsize == dlsize) { + /* flush I-cache & D-cache simultaneously */ + while (1) { + cache_op(HIT_WRITEBACK_INV_D, addr); + cache_op(HIT_INVALIDATE_I, addr); + if (addr == aend) + break; + addr += dlsize; + } + return; + } + + /* flush D-cache */ while (1) { cache_op(HIT_WRITEBACK_INV_D, addr); + if (addr == aend) + break; + addr += dlsize; + } + + /* flush I-cache */ + addr = start_addr & ~(ilsize - 1); + aend = (start_addr + size - 1) & ~(ilsize - 1); + while (1) { cache_op(HIT_INVALIDATE_I, addr); if (addr == aend) break; - addr += lsize; + addr += ilsize; } } void flush_dcache_range(ulong start_addr, ulong stop) { - unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; + unsigned long lsize = dcache_line_size(); unsigned long addr = start_addr & ~(lsize - 1); unsigned long aend = (stop - 1) & ~(lsize - 1); @@ -69,7 +130,7 @@ void flush_dcache_range(ulong start_addr, ulong stop) void invalidate_dcache_range(ulong start_addr, ulong stop) { - unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; + unsigned long lsize = dcache_line_size(); unsigned long addr = start_addr & ~(lsize - 1); unsigned long aend = (stop - 1) & ~(lsize - 1); -- cgit v1.2.3-70-g09d2