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

Reply via email to