[PATCH 0/6] MSM8916: Bring secondary cores online with spin-table

This patch series depends on the "mach-snapdragon: handle platforms without PSCI support" patch that was submitted earlier today. That first patch lays some groundwork to handle detecting when a device is booting without PSCI and deletes the /psci node in that case.
This series builds on top of that detection by rewriting all CPUs with enable-method="psci" to "spin-table".
Once this is done, the existing spin-table support in U-Boot handles further patching the nodes with the appropriate cpu-release-addr and reserving the memory with the spin-table instructions.
Interestingly, this spin-table code doesn't seem to be in active use anywhere, and it had bitrotted a little. But after blowing the dust off it and fixing a couple of missing #includes, it works great.
I extended the spin-table support a little to make it easier for consumers to plug in a method that is called for each CPU that needs to be brought online. This saves the qcom board code from needing to hook into ft_board_setup or something that runs before booting the OS.
Signed-off-by: Sam Day me@samcday.com --- Sam Day (6): armv8: spin_table: Fix missing includes armv8: spin_table: add hook for booting cores mach-snapdragon: qcom SCM call support mach-snapdragon: fixup CPUs with PSCI enable-method mach-snapdragon: MSM8916 spin-table CPU boot support qcom_defconfig: enable spin-table support
arch/arm/cpu/armv8/spin_table.c | 10 ++ arch/arm/include/asm/spin_table.h | 3 + arch/arm/mach-snapdragon/Makefile | 2 + arch/arm/mach-snapdragon/board.c | 41 ++++++++ arch/arm/mach-snapdragon/msm8916-smp.c | 135 +++++++++++++++++++++++++++ arch/arm/mach-snapdragon/qcom-scm.c | 145 +++++++++++++++++++++++++++++ arch/arm/mach-snapdragon/qcom-scm.h | 165 +++++++++++++++++++++++++++++++++ configs/qcom_defconfig | 2 + 8 files changed, 503 insertions(+) --- base-commit: 2eed5a1ff36217372e19f7513bd07077fc76718a change-id: 20250127-msm8916-smp-support-5f5e7b49d07e prerequisite-change-id: 20250127-qcom-handle-absent-psci-6e8e8af7bcd7:v1 prerequisite-patch-id: 6f85e145b7a25346a286396d9edf6106ae131c0b prerequisite-patch-id: 3b11763ea1d10ae9e23cb5c1b888f02220919284 prerequisite-patch-id: 030300d29b72f14fc528f2ad46c0d9e229934e9e prerequisite-patch-id: de0427537d887654f8dbf2e97ca6a3bc956512cd prerequisite-patch-id: 30db99afc91f657e484d4bb5a6613b64fb77649b prerequisite-patch-id: b1c46de57d0f82756d2bbeee6d13cf31c1f27a0f prerequisite-patch-id: 2d7d38f6ea846a5f183462d07ff962182e20a87e prerequisite-patch-id: 76ce7f79c8f4e2a5042dc8804194b0bef2d0a24b prerequisite-patch-id: 05eac938e6d33019a091ee721eba2d2dc7a03960 prerequisite-patch-id: 243fe8829719909ab6d65b512b0efcff4f4c9438 prerequisite-patch-id: fb7780ba617c036bc3b4e8fbc53541d485ae89d8 prerequisite-patch-id: 16e2a268f01739da59598b5f5b0d86a80c31449f prerequisite-patch-id: 43e1512fd0768b763cdf2079dce0054a736e97ea prerequisite-patch-id: 02cffb68f48d9d64c26373d6366c82bfcb86a7a2 prerequisite-patch-id: 19f382ead12fd5f583ad8b82fe618e6dd2c59615 prerequisite-patch-id: 764cc2a29ae7486610b6279cd71bedfb267f18bd prerequisite-patch-id: e22fa6b807a5df8e0257636a3edf8de92d4b3a36 prerequisite-patch-id: 159efbb7a5bd037b11eb20993716bdc7e641c89f prerequisite-patch-id: 0c4373ed5bda9e74a488796de8ce2e0c59c62c46 prerequisite-patch-id: fb2e81bbe11eed5d7af8ac4b1c2a29e2bdb6b237 prerequisite-patch-id: b105b1ec3f2ab8d9ad212eacf3a4736417950930 prerequisite-patch-id: 302c34fd65875a4a750a5a36b933e43639859487 prerequisite-patch-id: b1b62ac7e28eb0cc8a66d529911d6294b40cc5cd prerequisite-patch-id: 43de5453463d592c16d5669345528ded4e897605 prerequisite-patch-id: 861de3de3e008cfffcbcbfdd25c5bf1cdd9925ea prerequisite-patch-id: c91bbc83ea9d167f2451c7e9a13692c4cc92d1cb prerequisite-patch-id: cf9a09214da66d4bb1175b40a4e49c98212aaae3 prerequisite-patch-id: 671819fe6f2c93b420fec5ee283149d8e51a4f1c prerequisite-patch-id: 02a9a32547b5e850d27ada3bed7e88b4c970d342 prerequisite-patch-id: cb7baa3ce35948742a83d9b4acb7449f660818a6 prerequisite-patch-id: 9dd97eb36b380b64b43fb6718075106e1f4186c5 prerequisite-patch-id: c9ef7bfbbcf3a55a821dac749236440ae10fc89c prerequisite-patch-id: d37f02b2f520d3a84e5b4a515f88d217f78841ee prerequisite-patch-id: ad99b38cc1326272ec03e7cdced069e76b850d59 prerequisite-patch-id: b7467e24f0a21c08a52008374e18d3af996e0668 prerequisite-patch-id: a7d97af191a6adfb55af0fd89bdb97c378f86f65 prerequisite-patch-id: 87de3dd294acc2a220d97142bd615bdcd01fb00b prerequisite-patch-id: 5f2a37841670e9b941dce8f8b28c3e7e6c6048f6 prerequisite-patch-id: 5a77c17b8b78e760cd9bd4982d564fdb60ba667e prerequisite-patch-id: afa8a5a8572452ff8ac2f0dac1fc132fc5423150 prerequisite-patch-id: d68ce45f8993ba7c6967c28c25abdbc0f78a2cb3 prerequisite-patch-id: 218f70c55c7ca23f1de87e5370655137e796c725 prerequisite-patch-id: 2f5b57d1cf40ef18ed9f942bee4dd35ad60f5c43 prerequisite-patch-id: 2e2278e28f7795aa48916be2e4865cc915d602fd prerequisite-patch-id: e86660dfec6465dc87f3deaeddc1bb814c7dd801 prerequisite-patch-id: a5136d73559a8eaee5ce7e460842ba02d8c7f7c7 prerequisite-patch-id: fae5d78eb2da7d044ee6408d03a887d537dedaae prerequisite-patch-id: 27dfcabf70c4b88395eabf07a60b286d4d1856d2 prerequisite-patch-id: 5414352fb0926632f6b9c4904f0240c2976ea38f prerequisite-patch-id: 3036949e76a7d5467b4c0842f852b84a1a48ae84 prerequisite-patch-id: 76cc9440f2cbd13090eebeb4c25c20dbb990049c prerequisite-patch-id: 7549f8d500cf0ce56b49c78fc3412353cd080ac4 prerequisite-patch-id: 19e7341bcdce3e1f39acf2125b44ea011f3352e1 prerequisite-patch-id: 2830a95408413ac5d4b8869e58006b2529fb1af7 prerequisite-patch-id: 097945624a0249b81bc3e7f747d7c54b1552f121 prerequisite-patch-id: 12e71f9202bdab483de4fb275710fcd738b89e99 prerequisite-patch-id: 6ae4a39f434fd00c4ba139ff1d91d0c9275cb208 prerequisite-patch-id: a0c8c2f64bb5951eb1794a6cf685d9898baa56ca prerequisite-patch-id: b5143f5cfec77eb66f2f3c65a2614d715255c1a7 prerequisite-patch-id: 7042961e52dc6a3691064c8f0cdeea611ad2d5ec prerequisite-patch-id: 36f5fed167531209347d743c8289150508684979 prerequisite-patch-id: 3ddd71ec0fa373ce98a05a7a5cbdc84399a66efc prerequisite-patch-id: 7fdce16aa47fe89f7c1afae677042edf2735385a prerequisite-patch-id: b841df88415770b8e7771104233179b35773e473 prerequisite-patch-id: 60085daf50c7c2b629f522069a51c480b3218f05 prerequisite-patch-id: 873eed9fa8f975be3cf37fac3ed662250ce11771 prerequisite-patch-id: a5ac5acc7b7c182fe008d856cc9bbaa2c5e9633a prerequisite-patch-id: 3939201e8927f038d843dcc9e0dd67781d73ce53 prerequisite-patch-id: cf6b26bdc312e808b1ef702e323cb7ab0f82b6a2 prerequisite-patch-id: 2dc7feea1ab83bab9852bc95a6c9a7d6a7006aac prerequisite-patch-id: 5ec17e2221f23dc8f10803404256db6b2ea86f17 prerequisite-patch-id: 0f8b032d456dda766799580f1185a124bafe3ee3 prerequisite-patch-id: b168c68d649ac27e2416a3bf1ae7b9b6a90822b8 prerequisite-patch-id: 69a892386b52cb7aa0839472ee96f5c0f9ac5ef3 prerequisite-patch-id: 7c0fd076b848535a0f0d5abb6fcbbc836f71b4e4 prerequisite-patch-id: 0800bc8110bdb23f177cdc8e6d80dcdb2f3b3059 prerequisite-patch-id: 22c12428b5345883a30f2e0dfbea78defb2cc5e2 prerequisite-patch-id: 889de73156ee67862e5a9eb00cb43934d1848afb prerequisite-patch-id: 122e9b8f48e2f67e10ec4345b4aaf5feba81b40a prerequisite-patch-id: ec144dd1adc629a0d8d7bc4ee0b520344faf0322 prerequisite-patch-id: a7c6c37875075e7d31a9eec9e50fb0cf960ccfa6 prerequisite-patch-id: a1f683dae05a61bdf15df04454960af2481b9ff0 prerequisite-patch-id: f031c546205485ab0dbde83e962f7a2341c62645 prerequisite-patch-id: 05c5e3f7c07d0c3072c59cd0cb1262e5f480a589 prerequisite-patch-id: f54e3917db830329ef185dd89c27085cbefb1881 prerequisite-patch-id: dfe80f29b2ef88d5cbe668949a74459ef53c660d prerequisite-patch-id: 2d85a2c47df09ba5831265c2119bf045d6bdeacd prerequisite-patch-id: 1439383a5a62edd6186af4705a5b4f59d27f4c40 prerequisite-patch-id: 11defde4d0eb072a2c2bcf022af0598edd597051 prerequisite-patch-id: 92b8c0b688026554b3633440f61572fd451c617e prerequisite-patch-id: 09c8682d1d6cb5ff1af975308ca039f25fe4c59a prerequisite-patch-id: e7c5c0b05eb4a395c93908dab766b3840dc3b302 prerequisite-patch-id: fa4c72a2c5d13579a831a41e9235e245b78a7dbc prerequisite-patch-id: a4ad3b9360284a935f1dd98a3bd01a765c8aa5bc prerequisite-patch-id: 32e46850ee3f2ae42aa806bc236ec4474c35dca0 prerequisite-patch-id: b0ba05b2600ec4767e8deb88fb39c261ea317a6d prerequisite-patch-id: a6841b49255ec70ffeff8470ffe3a0dbf65ee7b8 prerequisite-patch-id: ec523fb216a7dffabeb1b0966603c01bcd30c425 prerequisite-patch-id: 29559b5916dd715a8daec623c4a52a2896c4f853 prerequisite-patch-id: 935e2b0efe1f56f9c02d61a44ebd169b8aa01757 prerequisite-patch-id: 207cdd32d4721253767e87bad783e6cfd7894885 prerequisite-patch-id: d4fede4e48324bcbad94166381520e86de8c6b58 prerequisite-patch-id: 37e1e35c443f31444a815e7fa09ab9193b58ff33 prerequisite-patch-id: 89cfa619d48fc54564390069b445617e9cd3f272 prerequisite-patch-id: a4934111361709dec17274b4a9840b388e40927a prerequisite-patch-id: 84f11a9b07d4f28ecef51a8e689840c6650c29fb prerequisite-patch-id: 62f7cfc8675a161612ab84e6884baa0289140037 prerequisite-patch-id: fb6f1d0041b49bcf1a568af97be5221fba0bee68 prerequisite-patch-id: 4542cc51d6726e7993581124a2691821eaef06c7 prerequisite-patch-id: f801ea78e28a1d6a2f8a25c3376de7517b3a4f2c prerequisite-patch-id: 1e50e99eef583a5ea2e03a66363045b57146305f prerequisite-patch-id: 333e1147f78607d03964774cf2ccf7c16eea5e4a prerequisite-patch-id: 501c4d1e9f26129440505bcd08f62eee38605c31 prerequisite-patch-id: e58d99831b9ff24ebfa92ec5cab91eefa3bde05f prerequisite-patch-id: c29d323121307cf9e14bfae5b72aff0b281adb42 prerequisite-patch-id: 78c5227d2d0aebd3039d084bbeb517330c3f258e prerequisite-patch-id: eb502f8a13b74b8689304ab1e8993bb79ff4518b prerequisite-patch-id: c91159b4e90be4afa72dcda32efdf42dd8ca3888 prerequisite-patch-id: 0f125a3f46e7bb243cb78e9be0d74f318858a3ab prerequisite-patch-id: e3a1f152d9bb9c949a32ae1ec233c63bd7ad24bd prerequisite-patch-id: d6f656b49d9c1e0ed666732305db8d4e6ae9c9c9 prerequisite-patch-id: c41aff811e5487ecb069cacea0e85a358333dc37 prerequisite-patch-id: ff87d23252f02cd6a9abd43e71740968057f263a prerequisite-patch-id: fcab7e05ba0af8c43fce5149e952c69833c7c3b4 prerequisite-patch-id: b044600fd11584b74923079843b1456b480d5fa5 prerequisite-patch-id: bb963c51f31c76af938f8561c8779ed0f8511b7f prerequisite-patch-id: a9a675e9db9d2a0ec36a6ade80855636878b7d21 prerequisite-patch-id: 37caa389ca0cee716ab9408370bf9dbcac6a9d09 prerequisite-patch-id: ecc7ad1d94f8290f27c7749d27d1bebf5d11bf19 prerequisite-patch-id: 0966beb3fd1f486a79c791fc0a58c090533e789a prerequisite-patch-id: 2695a9bbf667850304a9c87c33d96db47f15504c prerequisite-patch-id: 1056292d88bb2ba81223a3315e52204078aa34f8 prerequisite-patch-id: 8c8bea9e74f88cd68e7096479f03353b0a77d35e prerequisite-patch-id: 3fb86a0aa7f1431e5480101cf992174eb9763c5c prerequisite-patch-id: 4229a08c9b3e78251f0fd12cca3b33b38f9c53b2 prerequisite-patch-id: 5b023bd57576a846cce1f9091926cf01af1e09e0 prerequisite-patch-id: 760da8469c8db63b0e5173079057ba1c91748688 prerequisite-patch-id: 8bc19d02fe8fd85c2c729de88e12a236549386b0 prerequisite-patch-id: 6c67a9cae4b0a873402355eac2e26943e6ac4ad6 prerequisite-patch-id: cffe93501f50aa986a4d0546614e59ad16b1b6b8 prerequisite-patch-id: cb823554e6cd1c736535944e1c87fb397e31d7e0 prerequisite-patch-id: b6b2b1079cd9864d9d785cbba7656706f2019357 prerequisite-patch-id: aaa2d626cfc8cdb4130a45706fdcb743de34e06f prerequisite-patch-id: 6511f02f5192e70025a03c323232c1925d5ec9ab prerequisite-patch-id: 4d49e42ca5ead7cc03372c6d99189d98d4af03ba prerequisite-patch-id: ee16181118c1b9f04a802ac725da9681fa5473b8 prerequisite-patch-id: 65448b5a93120d2117c1361035afc9bd911d005f prerequisite-patch-id: a1a62f04d90fb71042e2dabb15d1b37c7e7bbff2
Best regards,

Dropping the common.h header resulted in the spin table header missing asm/types.h and the source unit missing the errno.h includes.
Fixes: 7410cde67de ("arm: Remove <common.h> and add needed includes") Signed-off-by: Sam Day me@samcday.com --- arch/arm/cpu/armv8/spin_table.c | 1 + arch/arm/include/asm/spin_table.h | 2 ++ 2 files changed, 3 insertions(+)
diff --git a/arch/arm/cpu/armv8/spin_table.c b/arch/arm/cpu/armv8/spin_table.c index 485294b88d0ac5516f58fb616ca59eebe30ef022..13b300f5c67a6dd257b2cb53350a7b5bafa3db96 100644 --- a/arch/arm/cpu/armv8/spin_table.c +++ b/arch/arm/cpu/armv8/spin_table.c @@ -6,6 +6,7 @@
#include <linux/libfdt.h> #include <asm/spin_table.h> +#include <errno.h>
int spin_table_update_dt(void *fdt) { diff --git a/arch/arm/include/asm/spin_table.h b/arch/arm/include/asm/spin_table.h index dec18c6e5c1ba15c8f96ccae8e9bb5415c845a5b..8fc61237e07559f267e1da1fbc8ee646ef08721f 100644 --- a/arch/arm/include/asm/spin_table.h +++ b/arch/arm/include/asm/spin_table.h @@ -3,6 +3,8 @@ #ifndef __ASM_SPIN_TABLE_H__ #define __ASM_SPIN_TABLE_H__
+#include <asm/types.h> + extern u64 spin_table_cpu_release_addr; extern char spin_table_reserve_begin; extern char spin_table_reserve_end;

On Mon, Jan 27, 2025 at 11:02:53PM +0000, Sam Day wrote:
Dropping the common.h header resulted in the spin table header missing asm/types.h and the source unit missing the errno.h includes.
Fixes: 7410cde67de ("arm: Remove <common.h> and add needed includes") Signed-off-by: Sam Day me@samcday.com
Reviewed-by: Tom Rini trini@konsulko.com

Introduce the weak symbol spin_table_boot_cpu, which is called by spin_table_update_dt during pre-boot FDT fixup phase for each CPU that has enable-method="spin-table".
This saves the board/arch code from needing to scan the DT looking for CPUs to boot, and also makes it easier to bring the secondary CPUs online as late as possible.
Signed-off-by: Sam Day me@samcday.com --- arch/arm/cpu/armv8/spin_table.c | 9 +++++++++ arch/arm/include/asm/spin_table.h | 1 + 2 files changed, 10 insertions(+)
diff --git a/arch/arm/cpu/armv8/spin_table.c b/arch/arm/cpu/armv8/spin_table.c index 13b300f5c67a6dd257b2cb53350a7b5bafa3db96..f83ff456f26d41402b83f0e30a65f8fc48e42fbe 100644 --- a/arch/arm/cpu/armv8/spin_table.c +++ b/arch/arm/cpu/armv8/spin_table.c @@ -8,6 +8,11 @@ #include <asm/spin_table.h> #include <errno.h>
+int __weak spin_table_boot_cpu(void *fdt, int cpu_offset) +{ + return 0; +} + int spin_table_update_dt(void *fdt) { int cpus_offset, offset; @@ -45,6 +50,10 @@ int spin_table_update_dt(void *fdt) if (!prop || strcmp(prop, "cpu")) continue;
+ ret = spin_table_boot_cpu(fdt, offset); + if (ret) + return ret; + ret = fdt_setprop_u64(fdt, offset, "cpu-release-addr", (unsigned long)&spin_table_cpu_release_addr); if (ret) diff --git a/arch/arm/include/asm/spin_table.h b/arch/arm/include/asm/spin_table.h index 8fc61237e07559f267e1da1fbc8ee646ef08721f..3c422046b830a7a81d7de806ff0db92d346446d2 100644 --- a/arch/arm/include/asm/spin_table.h +++ b/arch/arm/include/asm/spin_table.h @@ -10,5 +10,6 @@ extern char spin_table_reserve_begin; extern char spin_table_reserve_end;
int spin_table_update_dt(void *fdt); +int spin_table_boot_cpu(void *fdt, int cpu_offset);
#endif /* __ASM_SPIN_TABLE_H__ */

:n Mon, Jan 27, 2025 at 11:03:01PM +0000, Sam Day wrote:
Introduce the weak symbol spin_table_boot_cpu, which is called by
spin_table_update_dt during pre-boot FDT fixup phase for each CPU that has enable-method="spin-table".
This saves the board/arch code from needing to scan the DT looking for CPUs to boot, and also makes it easier to bring the secondary CPUs online as late as possible.
Signed-off-by: Sam Day me@samcday.com
Reviewed-by: Tom Rini trini@konsulko.com

These calls are a little more complex than a standard SMCCC instruction. There's 32bit/64bit calling conventions, support for passing more arguments than can fit in the usual registers (by placing a pointer to the additional args in x7), and the use of a qcom-specific smccc quirk.
Signed-off-by: Sam Day me@samcday.com --- arch/arm/mach-snapdragon/Makefile | 1 + arch/arm/mach-snapdragon/qcom-scm.c | 145 +++++++++++++++++++++++++++++++ arch/arm/mach-snapdragon/qcom-scm.h | 165 ++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+)
diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index 343e825c6fdd05f36e210b138e741b7b7dd606ac..e3b9510d25da040e72aa61668014f4863add6b5a 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -3,5 +3,6 @@ # (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com
obj-y += board.o +obj-y += qcom-scm.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o obj-$(CONFIG_OF_LIVE) += of_fixup.o diff --git a/arch/arm/mach-snapdragon/qcom-scm.c b/arch/arm/mach-snapdragon/qcom-scm.c new file mode 100644 index 0000000000000000000000000000000000000000..b9ccd1bbb7c1a43d864f2d5f3804836a06607b11 --- /dev/null +++ b/arch/arm/mach-snapdragon/qcom-scm.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2025 Linaro Ltd. */ + +/* Much of this code was adapted from Linux kernel */ +/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved. + */ + +#include "qcom-scm.h" + +#define QCOM_SCM_EBUSY_WAIT_MS 30 +#define QCOM_SCM_EBUSY_MAX_RETRY 20 + +#define SCM_SMC_N_REG_ARGS 4 +#define SCM_SMC_FIRST_EXT_IDX (SCM_SMC_N_REG_ARGS - 1) +#define SCM_SMC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SCM_SMC_N_REG_ARGS + 1) +#define SCM_SMC_FIRST_REG_IDX 2 +#define SCM_SMC_LAST_REG_IDX (SCM_SMC_FIRST_REG_IDX + SCM_SMC_N_REG_ARGS - 1) + +/** + * struct arm_smccc_args + * @args: The array of values used in registers in smc instruction + */ +struct arm_smccc_args { + unsigned long args[8]; +}; + +static void __scm_smc_do_quirk(const struct arm_smccc_args *smc, + struct arm_smccc_res *res) +{ + unsigned long a0 = smc->args[0]; + struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 }; + + quirk.state.a6 = 0; + + do { + arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2], + smc->args[3], smc->args[4], smc->args[5], + quirk.state.a6, smc->args[7], res, &quirk); + + if (res->a0 == QCOM_SCM_INTERRUPTED) + a0 = res->a0; + + } while (res->a0 == QCOM_SCM_INTERRUPTED); +} + +static int __scm_smc_do(struct arm_smccc_args *smc, struct arm_smccc_res *res, + bool atomic) +{ + int retry_count = 0; + + do { + __scm_smc_do_quirk(smc, res); + + if (atomic) + return 0; + + if (res->a0 == QCOM_SCM_V2_EBUSY) { + if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) + break; + mdelay(QCOM_SCM_EBUSY_WAIT_MS); + } + } while (res->a0 == QCOM_SCM_V2_EBUSY); + + return 0; +} + +int qcom_scm_call(const struct qcom_scm_desc *desc, + enum qcom_scm_convention qcom_convention, + struct qcom_scm_res *res, bool atomic) +{ + int arglen = desc->arginfo & 0xf; + void *args = NULL; + int i, ret; + struct arm_smccc_args smc = {0}; + struct arm_smccc_res smc_res; + u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL; + u32 qcom_smccc_convention = (qcom_convention == SMC_CONVENTION_ARM_32) ? + ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64; + u32 fnid = SCM_SMC_FNID(desc->svc, desc->cmd); + + smc.args[0] = ARM_SMCCC_CALL_VAL(smccc_call_type, qcom_smccc_convention, + desc->owner, fnid); + smc.args[1] = desc->arginfo; + for (i = 0; i < SCM_SMC_N_REG_ARGS; i++) + smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i]; + + if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) { + args = malloc_cache_aligned(SCM_SMC_N_EXT_ARGS * sizeof(u64)); + if (!args) + return -ENOMEM; + + if (qcom_smccc_convention == ARM_SMCCC_SMC_32) { + __le32 *args32 = args; + + for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++) + args32[i] = cpu_to_le32(desc->args[i + + SCM_SMC_FIRST_EXT_IDX]); + } else { + __le64 *args64 = args; + + for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++) + args64[i] = cpu_to_le64(desc->args[i + + SCM_SMC_FIRST_EXT_IDX]); + } + + smc.args[SCM_SMC_LAST_REG_IDX] = (phys_addr_t)args; + flush_cache((unsigned long)args, SCM_SMC_N_EXT_ARGS * sizeof(u64)); + } + + ret = __scm_smc_do(&smc, &smc_res, atomic); + + if (args) + free(args); + + if (ret) + return ret; + + if (res) { + res->result[0] = smc_res.a1; + res->result[1] = smc_res.a2; + res->result[2] = smc_res.a3; + } + + return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0; +} + +bool qcom_scm_is_call_available(u32 svc_id, u32 cmd_id, + enum qcom_scm_convention convention) +{ + u32 fnid = SCM_SMC_FNID(svc_id, cmd_id); + struct qcom_scm_res scm_ret = {0}; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_INFO, + .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL, + .owner = ARM_SMCCC_OWNER_SIP, + .arginfo = QCOM_SCM_ARGS(1), + .args = { + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, convention, + ARM_SMCCC_OWNER_SIP, fnid) + }, + }; + if (qcom_scm_call(&desc, convention, &scm_ret, false)) + return false; + return scm_ret.result[0]; +} diff --git a/arch/arm/mach-snapdragon/qcom-scm.h b/arch/arm/mach-snapdragon/qcom-scm.h new file mode 100644 index 0000000000000000000000000000000000000000..053d8b3c8cd44566f62b129e228963a50c678e19 --- /dev/null +++ b/arch/arm/mach-snapdragon/qcom-scm.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* This header was adapted from linux/drivers/firmware/qcom/qcom_scm.h */ +/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved. + */ +#ifndef __QCOM_SCM_INT_H +#define __QCOM_SCM_INT_H + +#include <asm/io.h> +#include <errno.h> +#include <linux/arm-smccc.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <memalign.h> + +enum qcom_scm_convention { + SMC_CONVENTION_UNKNOWN, + SMC_CONVENTION_LEGACY, + SMC_CONVENTION_ARM_32, + SMC_CONVENTION_ARM_64, +}; + +extern enum qcom_scm_convention qcom_scm_convention; + +#define MAX_QCOM_SCM_ARGS 10 +#define MAX_QCOM_SCM_RETS 3 + +#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\ + (((a) & 0x3) << 4) | \ + (((b) & 0x3) << 6) | \ + (((c) & 0x3) << 8) | \ + (((d) & 0x3) << 10) | \ + (((e) & 0x3) << 12) | \ + (((f) & 0x3) << 14) | \ + (((g) & 0x3) << 16) | \ + (((h) & 0x3) << 18) | \ + (((i) & 0x3) << 20) | \ + (((j) & 0x3) << 22) | \ + ((num) & 0xf)) + +#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +/** + * struct qcom_scm_desc + * @arginfo: Metadata describing the arguments in args[] + * @args: The array of arguments for the secure syscall + */ +struct qcom_scm_desc { + u32 svc; + u32 cmd; + u32 arginfo; + u64 args[MAX_QCOM_SCM_ARGS]; + u32 owner; +}; + +/** + * struct qcom_scm_res + * @result: The values returned by the secure syscall + */ +struct qcom_scm_res { + u64 result[MAX_QCOM_SCM_RETS]; +}; + +#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) + +#define QCOM_SCM_SVC_BOOT 0x01 +#define QCOM_SCM_BOOT_SET_ADDR 0x01 +#define QCOM_SCM_BOOT_TERMINATE_PC 0x02 +#define QCOM_SCM_BOOT_SDI_CONFIG 0x09 +#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10 +#define QCOM_SCM_BOOT_SET_ADDR_MC 0x11 +#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a +#define QCOM_SCM_FLUSH_FLAG_MASK 0x3 +#define QCOM_SCM_BOOT_MAX_CPUS 4 +#define QCOM_SCM_BOOT_MC_FLAG_AARCH64 BIT(0) +#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1) +#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2) + +#define QCOM_SCM_SVC_PIL 0x02 +#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01 +#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02 +#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05 +#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 +#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 +#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a + +#define QCOM_SCM_SVC_IO 0x05 +#define QCOM_SCM_IO_READ 0x01 +#define QCOM_SCM_IO_WRITE 0x02 + +#define QCOM_SCM_SVC_INFO 0x06 +#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01 + +#define QCOM_SCM_SVC_MP 0x0c +#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02 +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03 +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04 +#define QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE 0x05 +#define QCOM_SCM_MP_VIDEO_VAR 0x08 +#define QCOM_SCM_MP_ASSIGN 0x16 +#define QCOM_SCM_MP_SHM_BRIDGE_ENABLE 0x1c +#define QCOM_SCM_MP_SHM_BRIDGE_DELETE 0x1d +#define QCOM_SCM_MP_SHM_BRIDGE_CREATE 0x1e + +#define QCOM_SCM_SVC_OCMEM 0x0f +#define QCOM_SCM_OCMEM_LOCK_CMD 0x01 +#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x02 + +#define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */ +#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03 +#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04 + +#define QCOM_SCM_SVC_HDCP 0x11 +#define QCOM_SCM_HDCP_INVOKE 0x01 + +#define QCOM_SCM_SVC_LMH 0x13 +#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE 0x01 +#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10 + +#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 +#define QCOM_SCM_SMMU_PT_FORMAT 0x01 +#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03 +#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02 + +#define QCOM_SCM_SVC_WAITQ 0x24 +#define QCOM_SCM_WAITQ_RESUME 0x02 +#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03 + +#define QCOM_SCM_SVC_GPU 0x28 +#define QCOM_SCM_SVC_GPU_INIT_REGS 0x01 + +/* common error codes */ +#define QCOM_SCM_V2_EBUSY -12 +#define QCOM_SCM_ENOMEM -5 +#define QCOM_SCM_EOPNOTSUPP -4 +#define QCOM_SCM_EINVAL_ADDR -3 +#define QCOM_SCM_EINVAL_ARG -2 +#define QCOM_SCM_ERROR -1 +#define QCOM_SCM_INTERRUPTED 1 + +static inline int qcom_scm_remap_error(int err) +{ + switch (err) { + case QCOM_SCM_ERROR: + return -EIO; + case QCOM_SCM_EINVAL_ADDR: + case QCOM_SCM_EINVAL_ARG: + return -EINVAL; + case QCOM_SCM_EOPNOTSUPP: + return -EOPNOTSUPP; + case QCOM_SCM_ENOMEM: + return -ENOMEM; + case QCOM_SCM_V2_EBUSY: + return -EBUSY; + } + return -EINVAL; +} + +bool qcom_scm_is_call_available(u32 svc_id, u32 cmd_id, + enum qcom_scm_convention convention); + +int qcom_scm_call(const struct qcom_scm_desc *desc, + enum qcom_scm_convention qcom_convention, + struct qcom_scm_res *res, bool atomic); + +#endif

If there's no PSCI implementation, then change the enable-method of all CPUs from "psci" to "spin-table". Later, when spin_table_update_dt runs, it will further patch the CPU nodes with the necessary cpu-release-addr.
This new fixup is only applied when CONFIG_ARMV8_SPIN_TABLE is enabled, since that also determines whether spin_table_update_dt runs.
Signed-off-by: Sam Day me@samcday.com --- arch/arm/mach-snapdragon/board.c | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index 75b9cf1a8a1b3383665eb2d4e6725efe59718de0..396898e270bb744151ffd2f0f4ea319f6018dcd4 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -181,7 +181,9 @@ static void show_psci_version(void) static void qcom_psci_fixup(void *fdt) { int offset, ret; + uint reg; struct arm_smccc_res res; + const char *prop;
arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
@@ -196,6 +198,45 @@ static void qcom_psci_fixup(void *fdt) ret = fdt_del_node(fdt, offset); if (ret) log_err("Failed to delete /psci node: %d\n", ret); + + if (!CONFIG_IS_ENABLED(ARMV8_SPIN_TABLE)) + return; + + /* If spin-table support is enabled, make sure any CPU nodes with a + * PSCI enable-method are updated to spin-table. Further, any PSCI + * power-domains properties are removed. + */ + + offset = fdt_path_offset(fdt, "/cpus"); + if (offset < 0) + return; + + for (offset = fdt_first_subnode(fdt, offset); + offset >= 0; + offset = fdt_next_subnode(fdt, offset)) { + prop = fdt_getprop(fdt, offset, "device_type", NULL); + if (!prop || strcmp(prop, "cpu")) + continue; + + prop = fdt_getprop(fdt, offset, "enable-method", NULL); + if (!prop || strcmp(prop, "psci")) + continue; + + reg = fdtdec_get_uint(fdt, offset, "reg", 0); + ret = fdt_setprop_string(fdt, offset, + "enable-method", "spin-table"); + if (ret) + log_err("Failed to set CPU%d enable-method to 'spin-table', this CPU will not be available to booted OS! %d\n", + reg, ret); + + log_info("Patched CPU%d enable-method to 'spin-table'\n", reg); + + prop = fdt_getprop(fdt, offset, "power-domain-names", NULL); + if (prop && !strcmp(prop, "psci")) { + fdt_delprop(fdt, offset, "power-domains"); + fdt_delprop(fdt, offset, "power-domain-names"); + } + } }
/* We support booting U-Boot with an internal DT when running as a first-stage bootloader

Most MSM8916 devices lack PSCI support, instead they're brought online with a qcom SCM call to set the boot address, and some register poking of the APCS register block.
Signed-off-by: Sam Day me@samcday.com --- arch/arm/mach-snapdragon/Makefile | 1 + arch/arm/mach-snapdragon/msm8916-smp.c | 135 +++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+)
diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index e3b9510d25da040e72aa61668014f4863add6b5a..b5122946229afb57d14e20360de12650a5343df7 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -6,3 +6,4 @@ obj-y += board.o obj-y += qcom-scm.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o obj-$(CONFIG_OF_LIVE) += of_fixup.o +obj-$(CONFIG_ARMV8_SPIN_TABLE) += msm8916-smp.o diff --git a/arch/arm/mach-snapdragon/msm8916-smp.c b/arch/arm/mach-snapdragon/msm8916-smp.c new file mode 100644 index 0000000000000000000000000000000000000000..fb044a4df9203783ecaa195a027f037e6e28f6ed --- /dev/null +++ b/arch/arm/mach-snapdragon/msm8916-smp.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * On MSM8916 devices that lack a PSCI implementation, firing up the secondary + * cores requires a call to TZ to set the boot address, and some poking of ACPS + * register block. + * + * Copyright (c) 2025 Linaro Ltd. + */ + +#include <asm/spin_table.h> +#include <cpu_func.h> +#include <dm/ofnode.h> +#include "qcom-scm.h" + +#define APCS_CPU_PWR_CTL 0x04 +#define CORE_PWRD_UP BIT(7) +#define COREPOR_RST BIT(5) +#define CORE_RST BIT(4) +#define CORE_MEM_HS BIT(3) +#define CORE_MEM_CLAMP BIT(1) +#define CLAMP BIT(0) + +#define APC_PWR_GATE_CTL 0x14 +#define GDHS_CNT_SHIFT 24 +#define GDHS_EN BIT(0) + +static void qcom_boot_cortex_a53(phys_addr_t acc_base) +{ + u32 reg_val; + + /* Put the CPU into reset. */ + reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP; + writel(reg_val, acc_base + APCS_CPU_PWR_CTL); + + /* Turn on the GDHS and set the GDHS_CNT to 16 XO clock cycles */ + writel(GDHS_EN | (0x10 << GDHS_CNT_SHIFT), acc_base + APC_PWR_GATE_CTL); + /* Wait for the GDHS to settle */ + udelay(2); + + reg_val &= ~CORE_MEM_CLAMP; + writel(reg_val, acc_base + APCS_CPU_PWR_CTL); + reg_val |= CORE_MEM_HS; + writel(reg_val, acc_base + APCS_CPU_PWR_CTL); + udelay(2); + + reg_val &= ~CLAMP; + writel(reg_val, acc_base + APCS_CPU_PWR_CTL); + udelay(2); + + /* Release CPU out of reset and bring it to life. */ + reg_val &= ~(CORE_RST | COREPOR_RST); + writel(reg_val, acc_base + APCS_CPU_PWR_CTL); + reg_val |= CORE_PWRD_UP; + writel(reg_val, acc_base + APCS_CPU_PWR_CTL); +} + +int qcom_scm_set_boot_addr_mc(void *entry, unsigned int flags) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_SET_ADDR_MC, + .owner = ARM_SMCCC_OWNER_SIP, + .arginfo = QCOM_SCM_ARGS(6), + .args = { + (u64)entry, + /* Apply to all CPUs in all affinity levels */ + ~0ULL, ~0ULL, ~0ULL, ~0ULL, + flags, + }, + }; + + return qcom_scm_call(&desc, SMC_CONVENTION_ARM_32, NULL, false); +} + +static bool boot_addr_set; + +int spin_table_boot_cpu(void *fdt, int cpu_offset) +{ + struct fdtdec_phandle_args acc; + u32 mpidr_aff, acc_base, reg; + int ret; + + reg = fdtdec_get_uint(fdt, cpu_offset, "reg", 0); + + if (fdt_node_check_compatible(fdt, cpu_offset, "arm,cortex-a53")) { + log_warning("CPU%d is not arm,cortex-a53 compatible\n", reg); + return -EINVAL; + } + + if (!boot_addr_set) { + if (!qcom_scm_is_call_available(QCOM_SCM_SVC_BOOT, + QCOM_SCM_BOOT_SET_ADDR_MC, + SMC_CONVENTION_ARM_32)) { + log_warning("BOOT_SET_ADDR_MC unavailable\n"); + return -EPERM; + } + + debug("Setting CPU boot address to 0x%llx\n", + (phys_addr_t)&spin_table_reserve_begin); + ret = qcom_scm_set_boot_addr_mc(&spin_table_reserve_begin, + QCOM_SCM_BOOT_MC_FLAG_AARCH64 | + QCOM_SCM_BOOT_MC_FLAG_COLDBOOT); + if (ret) { + log_err("Failed to set CPU boot addr: %d\n", ret); + return ret; + } + + boot_addr_set = true; + } + + mpidr_aff = read_mpidr() & 0xffffff; + + if (reg == mpidr_aff) { + debug("Skipping boot of current CPU%d\n", reg); + return 0; + } + + ret = fdtdec_parse_phandle_with_args(fdt, cpu_offset, "qcom,acc", + NULL, 0, 0, &acc); + if (ret) { + log_err("Failed to parse qcom,acc phandle: %d\n", reg); + return ret; + } + + acc_base = fdtdec_get_addr_size_auto_noparent(fdt, acc.node, "reg", 0, + NULL, true); + if (!acc_base) { + log_err("Failed to parse qcom,acc regbase\n"); + return -EINVAL; + } + + log_info("Booting CPU%d @ 0x%x\n", reg, acc_base); + qcom_boot_cortex_a53(acc_base); + return 0; +}

This is used by MSM8916 to bring secondary cores online when no PSCI support is available.
Signed-off-by: Sam Day me@samcday.com --- configs/qcom_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index e4abfdf16bb50503953b79fcaec1263c6b74f41f..c5f0e33fe7cbe69419b80a1a487ad6aac76d8ed1 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -1,4 +1,6 @@ CONFIG_ARM=y +CONFIG_ARMV8_MULTIENTRY=y +CONFIG_ARMV8_SPIN_TABLE=y CONFIG_SKIP_LOWLEVEL_INIT=y CONFIG_POSITION_INDEPENDENT=y CONFIG_SYS_INIT_SP_BSS_OFFSET=1572864
participants (2)
-
Sam Day
-
Tom Rini