[PATCH 03/27] ARM: cache: drive the XSC3 cache with the ARMv4 functions

Sascha Hauer s.hauer at pengutronix.de
Sun Aug 16 10:56:23 PDT 2026


XSC3 reports ARMv5TE and is dispatched to the ARMv5 cache functions
accordingly, where v5_mmu_cache_flush() cleans the D-cache with

	1:	mrc	p15, 0, r15, c7, c14, 3	@ test,clean,invalidate
		bne	1b

XSC3 does not implement that operation - Linux' xsc3_flush_kern_cache_all()
uses a set/way loop instead - so the condition flags never come back with
the cache reported clean and the loop does not end. The board hangs in
sync_caches_for_execution(), between the PBL and barebox proper, before
anything has been printed.

The ARMv4 functions flush by reading through the cache and use nothing
XScale is missing, so send XSC3 there.

This only shows up in a build that has another ARMv5 core in it, which is
why the PXA board defconfigs are unaffected and multi_v5_v6_defconfig
hangs. On its own CONFIG_CPU_XSC3 selects CPU_32v4T and no other CPU_32v*,
so ARM_MULTIARCH is never defined, cpu_architecture() is the compile time
constant CPU_ARCH_ARMv4T, and the same functions are reached by accident.
Add an ARM926 or an ARM1176 to the config and the runtime detection takes
over, correctly returns ARMv5TE, and picks code the core cannot run.

Assisted-by: Claude Opus 5
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/cpu/cache_32.c            | 31 +++++++++++++++++++++++++++++++
 arch/arm/include/asm/system_info.h |  9 +++++++++
 2 files changed, 40 insertions(+)

diff --git a/arch/arm/cpu/cache_32.c b/arch/arm/cpu/cache_32.c
index 0ac50c4d9a..e82cd212d2 100644
--- a/arch/arm/cpu/cache_32.c
+++ b/arch/arm/cpu/cache_32.c
@@ -39,10 +39,35 @@ DEFINE_CPU_FNS(v5)
 DEFINE_CPU_FNS(v6)
 DEFINE_CPU_FNS(v7)
 
+/*
+ * XSC3 reports ARMv5TE, and it is - but its cache is not the one the ARMv5
+ * code drives. v5_mmu_cache_flush() cleans the D-cache with the ARM926
+ * test-and-clean operation (c7, c14, 3), which XSC3 does not implement, so
+ * the loop waiting for it to report the cache clean never ends. The ARMv4
+ * code flushes by reading through the cache instead and uses nothing XScale
+ * is missing, so send these cores there.
+ *
+ * This only ever comes up in a build that has another ARMv5 core in it. On
+ * its own CPU_XSC3 selects CPU_32v4T and no other CPU_32v*, which leaves
+ * cpu_architecture() a compile time ARMv4T and lands on the same functions
+ * by accident.
+ */
+static struct cache_fns *cache_fns_by_core(void)
+{
+	if (IS_ENABLED(CONFIG_CPU_32v4T) && cpu_is_xsc3())
+		return &cache_fns_armv4;
+
+	return NULL;
+}
+
 static struct cache_fns *cache_functions(void)
 {
 	static struct cache_fns *cache_fns;
 
+	if (cache_fns)
+		return cache_fns;
+
+	cache_fns = cache_fns_by_core();
 	if (cache_fns)
 		return cache_fns;
 
@@ -119,6 +144,12 @@ void __mmu_cache_flush(void)
  */
 void arm_early_mmu_cache_flush(void)
 {
+	/* see cache_fns_by_core() */
+	if (IS_ENABLED(CONFIG_CPU_32v4T) && cpu_is_xsc3()) {
+		v4_mmu_cache_flush();
+		return;
+	}
+
 	switch (arm_early_get_cpu_architecture()) {
 #ifdef CONFIG_CPU_32v4T
 	case CPU_ARCH_ARMv4T:
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
index 5a84fde75b..1fde203063 100644
--- a/arch/arm/include/asm/system_info.h
+++ b/arch/arm/include/asm/system_info.h
@@ -59,6 +59,9 @@
 #define CPU_IS_PXA270		0x69054110
 #define CPU_IS_PXA270_MASK	0xfffff7f0
 
+#define CPU_IS_XSC3		0x69056000
+#define CPU_IS_XSC3_MASK	0xffffe000
+
 #define cpu_is_arm(core) ((read_cpuid_id() & CPU_IS_##core##_MASK) == CPU_IS_##core)
 
 #ifdef CONFIG_CPU_32v4T
@@ -80,6 +83,12 @@
 #define cpu_is_pxa270() (0)
 #endif
 
+#ifdef CONFIG_CPU_XSC3
+#define cpu_is_xsc3()	cpu_is_arm(XSC3)
+#else
+#define cpu_is_xsc3()	(0)
+#endif
+
 #ifdef CONFIG_CPU_32v5
 #ifdef ARM_ARCH
 #define ARM_MULTIARCH

-- 
2.47.3




More information about the barebox mailing list