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...@atmel.com> Tested-by: Elen Song <elen.s...@atmel.com> CC: Albert Aribaud <albert.u.b...@aribaud.net> CC: Aneesh V <ane...@ti.com> CC: Marek Vasut <marek.va...@gmail.com> CC: Reinhard Meyer <u-b...@emk-elektronik.de> CC: Heiko Schocher <h...@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 v4: invalidate_dcache_range will emit clearer warning message Per Albert's suggestion, if not alighed to cache line size, round up start address, round down stop addres Per Marek Vasut's suggestion, use __func__ stated in C99 arch/arm/lib/cache.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 58 insertions(+), 0 deletions(-) diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 92b61a2..4c8e160 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -53,3 +53,61 @@ 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 - start address 0x%08x not aligned to" + "cache line size(%d bytes)\n", __func__, start, + cache_line_len); + /* Round up starting address */ + mva = (mva | (cache_line_len - 1)) + 1; + } + if ((stop & (cache_line_len - 1)) != 0) { + printf("WARNING: %s - stop address 0x%08x not aligned to" + "cache line size(%d bytes)\n", __func__, stop, + cache_line_len); + /* Round down ending address */ + stop &= ~(cache_line_len - 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"))); -- 1.7.6 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot