On QCS8275 (Monaco) the boot firmware enters U-Boot on a Cortex-A78C
core. The Cortex-A78C cores have pointer authentication and the
Cortex-A55 cores do not, and Linux only brings up CPUs that match its
boot CPU in that respect, so booting it from a Cortex-A78C leaves the
four Cortex-A55 cores offline.

Add BOOT0_QCOM_BOOT_CPU. On any CPU other than QCOM_BOOT_CPU_MPIDR it
powers that CPU on at _start with PSCI CPU_ON, passing x0 on as the
context ID, and turns the entering CPU off. If CPU_ON fails, U-Boot
carries on where it was entered.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Tyler Baker <[email protected]>
---
 arch/arm/mach-snapdragon/Kconfig                   | 21 ++++++++++++++
 arch/arm/mach-snapdragon/include/mach/boot0.h      |  2 ++
 .../mach-snapdragon/include/mach/boot_cpu_boot0.h  | 33 ++++++++++++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig
index ddded0029e..6770f5070a 100644
--- a/arch/arm/mach-snapdragon/Kconfig
+++ b/arch/arm/mach-snapdragon/Kconfig
@@ -80,6 +80,27 @@ config BOOT0_SDM845_WORKAROUND
        help
          Select this if you are building U-Boot SPL for sdm845.
 
+config BOOT0_QCOM_BOOT_CPU
+       bool "boot0.h hook to run U-Boot on a selected CPU"
+       help
+         At entry, if U-Boot runs on any CPU other than the one given by
+         QCOM_BOOT_CPU_MPIDR, power that CPU on at the U-Boot entry point
+         with PSCI CPU_ON and turn the entering CPU off, so U-Boot and the OS
+         it boots run on the selected CPU. PSCI is called through SMC.
+
+         On QCS8275 (Monaco) the boot firmware enters on a Cortex-A78C core,
+         which has pointer authentication, while the Cortex-A55 cores do not.
+         Linux only brings up CPUs that match its boot CPU's pointer
+         authentication support, so it has to boot on a Cortex-A55.
+
 endchoice
 
+config QCOM_BOOT_CPU_MPIDR
+       hex "MPIDR affinity of the CPU to run U-Boot on"
+       depends on BOOT0_QCOM_BOOT_CPU
+       default 0x0
+       help
+         Affinity fields (Aff3..Aff0) of the MPIDR of the CPU that U-Boot moves
+         to at entry.
+
 endif
diff --git a/arch/arm/mach-snapdragon/include/mach/boot0.h 
b/arch/arm/mach-snapdragon/include/mach/boot0.h
index b71aab37f4..2f6b724fe8 100644
--- a/arch/arm/mach-snapdragon/include/mach/boot0.h
+++ b/arch/arm/mach-snapdragon/include/mach/boot0.h
@@ -8,6 +8,8 @@
 #else
 #if defined(CONFIG_BOOT0_MSM8916_PSCI_WORKAROUND)
 #include "msm8916_boot0.h"
+#elif defined(CONFIG_BOOT0_QCOM_BOOT_CPU)
+#include "boot_cpu_boot0.h"
 #else
        b       reset
 #endif
diff --git a/arch/arm/mach-snapdragon/include/mach/boot_cpu_boot0.h 
b/arch/arm/mach-snapdragon/include/mach/boot_cpu_boot0.h
new file mode 100644
index 0000000000..0b9cc0bd58
--- /dev/null
+++ b/arch/arm/mach-snapdragon/include/mach/boot_cpu_boot0.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Move the boot to the CPU selected by CONFIG_QCOM_BOOT_CPU_MPIDR: power it
+ * on at _start with PSCI CPU_ON (over SMC), passing x0 on as the context ID,
+ * then power the entering CPU off. On SoCs with mixed CPU types the boot
+ * firmware may enter U-Boot on a CPU the OS cannot boot from.
+ */
+#include <asm/psci.h>
+
+       mrs     x9, mpidr_el1
+       ldr     x10, =0xff00ffffff              /* Aff3..Aff0 */
+       and     x9, x9, x10
+       ldr     x1, =CONFIG_QCOM_BOOT_CPU_MPIDR
+       cmp     x9, x1
+       b.eq    reset
+
+       mov     x9, x0
+       adr     x2, _start
+       mov     x3, x9
+       ldr     x0, =ARM_PSCI_0_2_FN64_CPU_ON
+       smc     #0
+       cbnz    x0, 2f
+
+       /* U-Boot now runs on the selected CPU; this one must not go on. */
+       ldr     x0, =ARM_PSCI_0_2_FN_CPU_OFF
+       smc     #0
+1:     wfi
+       b       1b
+
+       /* CPU_ON failed: stay on this CPU. */
+2:     mov     x0, x9
+       b       reset
+       .ltorg

-- 
2.47.3

Reply via email to