In U-Boot proper, enable_caches() runs from initr_caches(), before
initr_dm() sets up driver model again, so it cannot find the L2 cache
device and flush_dcache_all() never reaches L2. Without the I/O
coherence port (IOCP), DMA masters do not snoop the CPU caches and
can then read stale data from memory.

Call enable_caches() again from an EVT_DM_POST_INIT_R spy, unless
SYS_DCACHE_OFF is set. In S-mode, U-Boot proper then drives the L2
controller itself, as the Linux ax45mp_cache driver does, and
"dcache off" and "dcache on" turn L2 off and on. In M-mode U-Boot
proper, L2 is now enabled, as enable_caches() intends.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Randolph Lin <[email protected]>
---
 arch/riscv/cpu/andes/cache.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/riscv/cpu/andes/cache.c b/arch/riscv/cpu/andes/cache.c
index 30d766da8f9..9a1ca950e11 100644
--- a/arch/riscv/cpu/andes/cache.c
+++ b/arch/riscv/cpu/andes/cache.c
@@ -10,6 +10,7 @@
 #include <cpu_func.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
+#include <event.h>
 #include <asm/arch-andes/csr.h>
 
 #ifdef CONFIG_ANDES_L2_CACHE
@@ -30,6 +31,20 @@ void enable_caches(void)
        }
 }
 
+/*
+ * In U-Boot proper, enable_caches() runs before driver model is set up
+ * again after relocation and cannot find the L2 cache device. Run it
+ * again once driver model is ready.
+ */
+static int andes_l2_init_r(void)
+{
+       if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
+               enable_caches();
+
+       return 0;
+}
+EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, andes_l2_init_r);
+
 static void cache_ops(int (*ops)(struct udevice *dev))
 {
        struct udevice *dev = NULL;
-- 
2.34.1

Reply via email to