diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c index 504f604684..5b23e3a71b 100644 --- a/arch/arm/cpu/arm926ejs/cache.c +++ b/arch/arm/cpu/arm926ejs/cache.c @@ -23,29 +23,71 @@ #include #ifndef CONFIG_SYS_DCACHE_OFF -static inline void dcache_noop(void) -{ - if (dcache_status()) { - puts("WARNING: cache operations are not implemented!\n" - "WARNING: disabling D-Cache now, you can re-enable it" - "later with 'dcache on' command\n"); - dcache_disable(); - } -} + +#ifndef CONFIG_SYS_CACHELINE_SIZE +#define CONFIG_SYS_CACHELINE_SIZE 32 +#endif void invalidate_dcache_all(void) { - dcache_noop(); + asm volatile("mcr p15, 0, %0, c7, c6, 0\n"::"r"(0)); +} + +void flush_dcache_all(void) +{ + asm volatile( + "0:" + "mrc p15, 0, r15, c7, c14, 3\n" + "bne 0b\n" + "mcr p15, 0, %0, c7, c10, 4\n" + ::"r"(0):"memory" + ); +} + +static int check_cache_range(unsigned long start, unsigned long stop) +{ + int ok = 1; + + if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (!ok) + printf("CACHE: Misaligned operation at range [%08lx, %08lx]\n", + start, stop); + + return ok; } void invalidate_dcache_range(unsigned long start, unsigned long stop) { - dcache_noop(); + if (!check_cache_range(start, stop)) + return; + + while (start < stop) { + asm volatile("mcr p15, 0, %0, c7, c6, 1\n"::"r"(start)); + start += CONFIG_SYS_CACHELINE_SIZE; + } } void flush_dcache_range(unsigned long start, unsigned long stop) { - dcache_noop(); + if (!check_cache_range(start, stop)) + return; + + while (start < stop) { + asm volatile("mcr p15, 0, %0, c7, c14, 1\n"::"r"(start)); + start += CONFIG_SYS_CACHELINE_SIZE; + } + + asm("mcr p15, 0, %0, c7, c10, 4\n"::"r"(0)); +} + +void flush_cache(unsigned long start, unsigned long size) +{ + flush_dcache_range(start, start + size); } #else /* #ifndef CONFIG_SYS_DCACHE_OFF */ void invalidate_dcache_all(void) @@ -64,7 +106,7 @@ void flush_dcache_range(unsigned long start, unsigned long stop) { } -void flush_cache(unsigned long start, unsigned long size) +void flush_cache(unsigned long start, unsigned long size) { } #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */