[PATCH v2 2/3] ARM: Cortex-A9: invalidate caches in early lowlevel init

Ahmad Fatoum a.fatoum at pengutronix.de
Tue Jun 10 13:13:19 PDT 2025


The optee-early code was initially added for i.MX6UL. Trying to naively
enable it on an i.MX6Q boards was observed to cause spurious hangs on
return from OP-TEE to barebox.

Quoting Lucas[1]:

  The real issue with the Cortex A9 caches is that the tags aren't
  cleared on power-up, so some sets/ways may end up in "valid" state if
  not explicitly invalidated. Thus any write to memory may get stuck in
  the cache, even if caching is disabled, as this knob only turns off
  allocation in the cache, but doesn't prevent updates of such bogus
  valid lines. If you then proceed to invalidate the cache, you may
  discard data that has not yet reached DRAM.

This issue did likely not affect the original i.MX6UL, Quoting Lucas
again[2]:

  > How do we know we only need this for Cortex-A9 though?
  > Couldn't e.g. the Cortex-A8 also be affected?

  We can't be 100% sure without specific knowledge about each SoC
  integration. Both the Cortex A8 [1] and Cortex A15 [2] TRMs define a
  reset sequence that mandates the straps to be set in such a way that
  the processor will clear all L1 and L2 memory arrays on power-on reset.

  The only odd one where the TRM doesn't even mention memory arrays in
  the reset sequence is the Cortex A9 [3], which pretty much lines up
  with the number of SoCs where we have seen issues due to uninitialized
  cache content.

Therefore, let's call arm_early_mmu_cache_invalidate() very early in the
low level init. We don't have a common Cortex-A9 init and the locations
touched here were determined by a grep for the Cortex-A9 errata that are
already being worked around by imx6_cpu_lowlevel_init().

[1]: https://lore.barebox.org/barebox/569963942cf35755dfdf34b240c350986fda4727.camel@pengutronix.de/
[2]: https://lore.barebox.org/barebox/d6a0be9631286122e56fdfd87b9911c310554baf.camel@pengutronix.de/

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - replace too late invalidation in start_optee_early with very early
    invalidation in the lowlevel init.
---
 arch/arm/mach-imx/cpu_init.c                 | 2 ++
 arch/arm/mach-socfpga/cpu_init.c             | 2 ++
 arch/arm/mach-tegra/tegra_maincomplex_init.c | 2 ++
 arch/arm/mach-zynq/cpu_init.c                | 2 ++
 4 files changed, 8 insertions(+)

diff --git a/arch/arm/mach-imx/cpu_init.c b/arch/arm/mach-imx/cpu_init.c
index aebbd3defaec..e9f42945528e 100644
--- a/arch/arm/mach-imx/cpu_init.c
+++ b/arch/arm/mach-imx/cpu_init.c
@@ -14,6 +14,7 @@
 #include <mach/imx/imx9-regs.h>
 #include <mach/imx/trdc.h>
 #include <io.h>
+#include <asm/cache.h>
 #include <asm/syscounter.h>
 #include <asm/system.h>
 
@@ -36,6 +37,7 @@ void imx6_cpu_lowlevel_init(void)
 {
 	arm_cpu_lowlevel_init();
 
+	arm_early_mmu_cache_invalidate();
 	enable_arm_errata_742230_war();
 	enable_arm_errata_743622_war();
 	enable_arm_errata_751472_war();
diff --git a/arch/arm/mach-socfpga/cpu_init.c b/arch/arm/mach-socfpga/cpu_init.c
index 73b69c34c56f..f10cd468da96 100644
--- a/arch/arm/mach-socfpga/cpu_init.c
+++ b/arch/arm/mach-socfpga/cpu_init.c
@@ -2,11 +2,13 @@
 
 #include <common.h>
 #include <asm/barebox-arm-head.h>
+#include <asm/cache.h>
 #include <asm/errata.h>
 #include <mach/socfpga/init.h>
 
 void arria10_cpu_lowlevel_init(void)
 {
+	arm_early_mmu_cache_invalidate();
 	enable_arm_errata_794072_war();
 	enable_arm_errata_845369_war();
 }
diff --git a/arch/arm/mach-tegra/tegra_maincomplex_init.c b/arch/arm/mach-tegra/tegra_maincomplex_init.c
index 2a2272a99fbc..e4cc3e780cbe 100644
--- a/arch/arm/mach-tegra/tegra_maincomplex_init.c
+++ b/arch/arm/mach-tegra/tegra_maincomplex_init.c
@@ -19,6 +19,7 @@
 #include <asm/barebox-arm-head.h>
 #include <asm/barebox-arm.h>
 #include <asm/errata.h>
+#include <asm/cache.h>
 #include <mach/tegra/lowlevel.h>
 #include <mach/tegra/tegra20-pmc.h>
 #include <mach/tegra/tegra20-car.h>
@@ -30,6 +31,7 @@ void tegra_maincomplex_entry(char *fdt)
 	u32 reg = 0;
 
 	arm_cpu_lowlevel_init();
+	arm_early_mmu_cache_invalidate();
 
 	chiptype = tegra_get_chiptype();
 
diff --git a/arch/arm/mach-zynq/cpu_init.c b/arch/arm/mach-zynq/cpu_init.c
index cc7b8d1142a9..f26e2947fd6a 100644
--- a/arch/arm/mach-zynq/cpu_init.c
+++ b/arch/arm/mach-zynq/cpu_init.c
@@ -2,6 +2,7 @@
 
 #include <common.h>
 #include <asm/barebox-arm-head.h>
+#include <asm/cache.h>
 #include <asm/errata.h>
 #include <mach/zynq/init.h>
 
@@ -9,6 +10,7 @@ void zynq_cpu_lowlevel_init(void)
 {
 	arm_cpu_lowlevel_init();
 
+	arm_early_mmu_cache_invalidate();
 	enable_arm_errata_761320_war();
 	enable_arm_errata_794072_war();
 	enable_arm_errata_845369_war();
-- 
2.39.5




More information about the barebox mailing list