
After DMA operation, we need to maintain D-Cache coherency. So that the DCache must be invalidated (hence CPU will fetch data written by DMA controller from RAM).
Tested on AT91SAM9261EK with Peripheral DMA controller.
Signed-off-by: Hong Xu hong.xu@atmel.com Tested-by: Elen Song elen.song@atmel.com CC: Albert Aribaud albert.u.boot@aribaud.net CC: Aneesh V aneesh@ti.com CC: Reinhard Meyer u-boot@emk-elektronik.de CC: Heiko Schocher hs@denx.de --- V2: Per Albert's suggestion, add invalidate_dcache_range
V3: invalidate_dcache_range emits warning when detecting unaligned buffer
invalidate_dcache_range won't clean any adjacent cache line when detecting unaligned buffer and only round up/down the buffer address
arch/arm/lib/cache.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 92b61a2..9e6aa47 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -53,3 +53,57 @@ void __flush_dcache_all(void) } void flush_dcache_all(void) __attribute__((weak, alias("__flush_dcache_all"))); + +/* + * The buffer range to be invalidated is [start, stop) + */ +void __invalidate_dcache_range(unsigned long start, unsigned long stop) +{ + int cache_line_len; + unsigned long mva; + +#ifdef CONFIG_ARM926EJS +#ifdef CONFIG_SYS_CACHELINE_SIZE + cache_line_len = CONFIG_SYS_CACHELINE_SIZE; +#else + /* + * ARM926EJ-S Technical Reference Manual, Chap 2.3.1 Table 2-9 + * only b'10, aka. 32 bytes cache line len is valid + */ + cache_line_len = 32; +#endif + mva = start; + if ((mva & (cache_line_len - 1)) != 0) { + printf("WARNING: %s - unaligned buffer detected, starting " + "address: 0x%08x\n", __FUNCTION__, start); + mva &= ~(cache_line_len - 1); + } + if ((stop & (cache_line_len - 1)) != 0) { + printf("WARNING: %s - unaligned buffer detected, ending " + "address: 0x%08x\n", __FUNCTION__, stop); + stop = (stop | (cache_line_len - 1)) + 1; + } + + while (mva < stop) { + asm("mcr p15, 0, %0, c7, c6, 1" : : "r"(mva)); + mva += cache_line_len; + } + + /* Drain the WB */ + asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); +#endif + + return; +} +void invalidate_dcache_range(unsigned long start, unsigned long stop) + __attribute__((weak, alias("__invalidate_dcache_range"))); + +void __invalidate_dcache_all(void) +{ +#ifdef CONFIG_ARM926EJS + asm("mcr p15, 0, %0, c7, c6, 0" : : "r" (0)); +#endif + return; +} +void invalidate_dcache_all(void) + __attribute__((weak, alias("__invalidate_dcache_all")));