From 08e3656b517cf029dec5f9830c2e09b947e46e8b Mon Sep 17 00:00:00 2001 From: David Hendricks Date: Mon, 25 Mar 2013 15:02:29 -0700 Subject: armv7: import updated cache/MMU stuff from coreboot This imports the newest cache and MMU code from coreboot. This time it's so new that it hasn't even been checked in to coreboot. However, this version at least allows DMA to work properly for the MSHC driver. So even if we rebase a few more times, this version is at least a step in the right direction. Note: This omits the stuff that sets up dcache policy since libpayload should not need to worry about that and it depends on cbmem stuff. Change-Id: Idd42b083e8019634aaaa44d5bf5b51db6c3912f5 Signed-off-by: David Hendricks Reviewed-on: http://review.coreboot.org/2975 Reviewed-by: David Hendricks Tested-by: build bot (Jenkins) --- payloads/libpayload/arch/armv7/cache.c | 141 +++++++++++++++++++++++++++++---- 1 file changed, 125 insertions(+), 16 deletions(-) (limited to 'payloads/libpayload/arch') diff --git a/payloads/libpayload/arch/armv7/cache.c b/payloads/libpayload/arch/armv7/cache.c index 60d5f742b9..9fac442f17 100644 --- a/payloads/libpayload/arch/armv7/cache.c +++ b/payloads/libpayload/arch/armv7/cache.c @@ -26,7 +26,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * cache.c: Low-level cache operations for ARMv7 + * cache.c: Cache maintenance routines for ARMv7-A and ARMv7-R + * + * Reference: ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition */ #include @@ -52,8 +54,8 @@ void tlb_invalidate_all(void) { /* * FIXME: ARMv7 Architecture Ref. Manual claims that the distinction - * instruction vs. data TLBs is deprecated in ARMv7. But that doesn't - * really seem true for Cortex-A15? + * instruction vs. data TLBs is deprecated in ARMv7, however this does + * not seem to be the case as of Cortex-A15. */ tlbiall(); dtlbiall(); @@ -64,7 +66,8 @@ void tlb_invalidate_all(void) void icache_invalidate_all(void) { - /* icache can be entirely invalidated with one operation. + /* + * icache can be entirely invalidated with one operation. * Note: If branch predictors are architecturally-visible, ICIALLU * also performs a BPIALL operation (B2-1283 in arch manual) */ @@ -74,10 +77,17 @@ void icache_invalidate_all(void) enum dcache_op { OP_DCCISW, - OP_DCISW + OP_DCISW, + OP_DCCIMVAC, + OP_DCCMVAC, }; -/* do a dcache operation on entire cache by set/way */ +/* + * Do a dcache operation on entire cache by set/way. This is done for + * portability because mapping of memory address to cache location is + * implementation defined (See note on "Requirements for operations by + * set/way" in arch ref. manual). + */ static void dcache_op_set_way(enum dcache_op op) { uint32_t ccsidr; @@ -101,6 +111,8 @@ static void dcache_op_set_way(enum dcache_op op) /* FIXME: do we need to use CTR.DminLine here? */ linesize_bytes = (1 << ((ccsidr & 0x7) + 2)) * 4; + dsb(); + /* * Set/way operations require an interesting bit packing. See section * B4-35 in the ARMv7 Architecture Reference Manual: @@ -134,8 +146,7 @@ static void dcache_op_set_way(enum dcache_op op) } } } - - dsb(); + isb(); } void dcache_clean_invalidate_all(void) @@ -161,18 +172,116 @@ static unsigned int line_bytes(void) return size; } +/* + * Do a dcache operation by modified virtual address. This is useful for + * maintaining coherency in drivers which do DMA transfers and only need to + * perform cache maintenance on a particular memory range rather than the + * entire cache. + */ +static void dcache_op_mva(unsigned long addr, + unsigned long len, enum dcache_op op) +{ + unsigned long line, linesize; + + linesize = line_bytes(); + line = addr & ~(linesize - 1); + + dsb(); + while (line < addr + len) { + switch(op) { + case OP_DCCIMVAC: + dccimvac(line); + break; + default: + break; + } + line += linesize; + } + isb(); +} + +void dcache_clean_by_mva(unsigned long addr, unsigned long len) +{ + dcache_op_mva(addr, len, OP_DCCMVAC); +} + void dcache_clean_invalidate_by_mva(unsigned long addr, unsigned long len) { - unsigned long line, i; + dcache_op_mva(addr, len, OP_DCCIMVAC); +} + +void dcache_mmu_disable(void) +{ + uint32_t sctlr, csselr; + + /* ensure L1 data/unified cache is selected */ + csselr = read_csselr(); + csselr &= ~0xf; + write_csselr(csselr); + + dcache_clean_invalidate_all(); + + sctlr = read_sctlr(); + sctlr &= ~(SCTLR_C | SCTLR_M); + write_sctlr(sctlr); +} + + +void dcache_mmu_enable(void) +{ + uint32_t sctlr; - line = line_bytes(); - for (i = addr & ~(line - 1); i < addr + len - 1; i += line) - dccimvac(addr); + sctlr = read_sctlr(); + dcache_clean_invalidate_all(); + sctlr |= SCTLR_C | SCTLR_M; + write_sctlr(sctlr); } -/* FIXME: wrapper around imported mmu_setup() for now */ -extern void mmu_setup(unsigned long start, unsigned long size); -void mmu_setup_by_mva(unsigned long start, unsigned long size) +void armv7_invalidate_caches(void) { - mmu_setup(start, size); + uint32_t clidr; + int level; + + /* Invalidate branch predictor */ + bpiall(); + + /* Iterate thru each cache identified in CLIDR and invalidate */ + clidr = read_clidr(); + for (level = 0; level < 7; level++) { + unsigned int ctype = (clidr >> (level * 3)) & 0x7; + uint32_t csselr; + + switch(ctype) { + case 0x0: + /* no cache */ + break; + case 0x1: + /* icache only */ + csselr = (level << 1) | 1; + write_csselr(csselr); + icache_invalidate_all(); + break; + case 0x2: + case 0x4: + /* dcache only or unified cache */ + dcache_invalidate_all(); + break; + case 0x3: + /* separate icache and dcache */ + csselr = (level << 1) | 1; + write_csselr(csselr); + icache_invalidate_all(); + + csselr = level < 1; + write_csselr(csselr); + dcache_invalidate_all(); + break; + default: + /* reserved */ + break; + } + } + + /* Invalidate TLB */ + tlb_invalidate_all(); } -- cgit v1.2.3