summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/cache_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/cache_32.c')
-rw-r--r--arch/arm/cpu/cache_32.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/arch/arm/cpu/cache_32.c b/arch/arm/cpu/cache_32.c
new file mode 100644
index 0000000000..0ac50c4d9a
--- /dev/null
+++ b/arch/arm/cpu/cache_32.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <init.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+#include <asm/system_info.h>
+
+#include "mmu_32.h"
+
+struct cache_fns {
+ void (*dma_clean_range)(unsigned long start, unsigned long end);
+ void (*dma_flush_range)(unsigned long start, unsigned long end);
+ void (*dma_inv_range)(unsigned long start, unsigned long end);
+ void (*mmu_cache_on)(void);
+ void (*mmu_cache_off)(void);
+ void (*mmu_cache_flush)(void);
+};
+
+#define DEFINE_CPU_FNS(arch) \
+ void arch##_dma_clean_range(unsigned long start, unsigned long end); \
+ void arch##_dma_flush_range(unsigned long start, unsigned long end); \
+ void arch##_dma_inv_range(unsigned long start, unsigned long end); \
+ void arch##_mmu_cache_on(void); \
+ void arch##_mmu_cache_off(void); \
+ void arch##_mmu_cache_flush(void); \
+ \
+ static struct cache_fns __maybe_unused cache_fns_arm##arch = { \
+ .dma_clean_range = arch##_dma_clean_range, \
+ .dma_flush_range = arch##_dma_flush_range, \
+ .dma_inv_range = arch##_dma_inv_range, \
+ .mmu_cache_on = arch##_mmu_cache_on, \
+ .mmu_cache_off = arch##_mmu_cache_off, \
+ .mmu_cache_flush = arch##_mmu_cache_flush, \
+ };
+
+DEFINE_CPU_FNS(v4)
+DEFINE_CPU_FNS(v5)
+DEFINE_CPU_FNS(v6)
+DEFINE_CPU_FNS(v7)
+
+static struct cache_fns *cache_functions(void)
+{
+ static struct cache_fns *cache_fns;
+
+ if (cache_fns)
+ return cache_fns;
+
+ switch (cpu_architecture()) {
+#ifdef CONFIG_CPU_32v4T
+ case CPU_ARCH_ARMv4T:
+ cache_fns = &cache_fns_armv4;
+ break;
+#endif
+#ifdef CONFIG_CPU_32v5
+ case CPU_ARCH_ARMv5:
+ case CPU_ARCH_ARMv5T:
+ case CPU_ARCH_ARMv5TE:
+ case CPU_ARCH_ARMv5TEJ:
+ cache_fns = &cache_fns_armv5;
+ break;
+#endif
+#ifdef CONFIG_CPU_32v6
+ case CPU_ARCH_ARMv6:
+ cache_fns = &cache_fns_armv6;
+ break;
+#endif
+#ifdef CONFIG_CPU_32v7
+ case CPU_ARCH_ARMv7:
+ cache_fns = &cache_fns_armv7;
+ break;
+#endif
+ default:
+ while(1);
+ }
+
+ return cache_fns;
+}
+
+void __dma_clean_range(unsigned long start, unsigned long end)
+{
+ cache_functions()->dma_clean_range(start, end);
+}
+
+void __dma_flush_range(unsigned long start, unsigned long end)
+{
+ cache_functions()->dma_flush_range(start, end);
+}
+
+void __dma_inv_range(unsigned long start, unsigned long end)
+{
+ cache_functions()->dma_inv_range(start, end);
+}
+
+#ifdef CONFIG_MMU
+
+void __mmu_cache_on(void)
+{
+ cache_functions()->mmu_cache_on();
+}
+
+void __mmu_cache_off(void)
+{
+ cache_functions()->mmu_cache_off();
+}
+
+void __mmu_cache_flush(void)
+{
+ cache_functions()->mmu_cache_flush();
+ if (outer_cache.flush_all)
+ outer_cache.flush_all();
+}
+
+#endif
+
+/*
+ * Early function to flush the caches. This is for use when the
+ * C environment is not yet fully initialized.
+ */
+void arm_early_mmu_cache_flush(void)
+{
+ switch (arm_early_get_cpu_architecture()) {
+#ifdef CONFIG_CPU_32v4T
+ case CPU_ARCH_ARMv4T:
+ v4_mmu_cache_flush();
+ return;
+#endif
+#ifdef CONFIG_CPU_32v5
+ case CPU_ARCH_ARMv5:
+ case CPU_ARCH_ARMv5T:
+ case CPU_ARCH_ARMv5TE:
+ case CPU_ARCH_ARMv5TEJ:
+ v5_mmu_cache_flush();
+ return;
+#endif
+#ifdef CONFIG_CPU_32v6
+ case CPU_ARCH_ARMv6:
+ v6_mmu_cache_flush();
+ return;
+#endif
+#ifdef CONFIG_CPU_32v7
+ case CPU_ARCH_ARMv7:
+ v7_mmu_cache_flush();
+ return;
+#endif
+ }
+}
+
+void v7_mmu_cache_invalidate(void);
+
+void arm_early_mmu_cache_invalidate(void)
+{
+ switch (arm_early_get_cpu_architecture()) {
+#if __LINUX_ARM_ARCH__ <= 7
+ case CPU_ARCH_ARMv4T:
+ case CPU_ARCH_ARMv5:
+ case CPU_ARCH_ARMv5T:
+ case CPU_ARCH_ARMv5TE:
+ case CPU_ARCH_ARMv5TEJ:
+ case CPU_ARCH_ARMv6:
+ asm volatile("mcr p15, 0, %0, c7, c6, 0\n" : : "r"(0));
+ return;
+#ifdef CONFIG_CPU_32v7
+ case CPU_ARCH_ARMv7:
+ v7_mmu_cache_invalidate();
+ return;
+#endif
+#endif
+ }
+}