From d2b67fa99562bef7eb4a193909dc2248b9959bf0 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Mon, 7 Sep 2026 16:14:22 +0530 Subject: [PATCH 01/52] arm: dts: qcom: nord-ride: add qcom-hwinfo node Add the qcom,hwinfo U-Boot overlay node to nord-ride-u-boot.dtsi so that the qcom_hwinfo driver can read the IMEM boot cookie and the TCSR SOC_HW_VERSION register at boot. Signed-off-by: Aswin Murugan --- arch/arm/dts/nord-ride-u-boot.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/dts/nord-ride-u-boot.dtsi b/arch/arm/dts/nord-ride-u-boot.dtsi index a31aaabe849c..66500a979e9d 100644 --- a/arch/arm/dts/nord-ride-u-boot.dtsi +++ b/arch/arm/dts/nord-ride-u-boot.dtsi @@ -44,6 +44,27 @@ compatible = "qcom,smem"; memory-region = <&smem_region>; }; + + sram: sram@146d8000 { + compatible = "qcom,nord-imem", "syscon", "simple-mfd"; + reg = <0x0 0x146d8000 0x0 0x1000>; + ranges = <0x0 0x0 0x146d8000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + }; + + /* IMEM boot cookie + TCSR HW version offsets */ + qcom_hwinfo: qcom-hwinfo { + compatible = "qcom,hwinfo"; + + imem = <&sram>; + imem-boot-cookie-offset = <0x0>; + + tcsr = <&tcsr>; + tcsr-hw-version-offset = <0x68000>; + }; + }; &reserved_memory { From 15e729dc078e59547a4e92e1900c5aad88859942 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Sun, 6 Sep 2026 13:48:10 +0530 Subject: [PATCH 02/52] Revert "mach-snapdragon: skip redundant SCSI rescan for capsule updates" This reverts commit 50445725295a8e1720ded49b16e1420f306cbb2d. --- arch/arm/mach-snapdragon/capsule_update.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-snapdragon/capsule_update.c b/arch/arm/mach-snapdragon/capsule_update.c index 9fe951598e78..d3efba4816aa 100644 --- a/arch/arm/mach-snapdragon/capsule_update.c +++ b/arch/arm/mach-snapdragon/capsule_update.c @@ -641,8 +641,7 @@ void qcom_configure_capsule_updates(void) } memset(partitions, 0, sizeof(qcom_partitions)); - if (IS_ENABLED(CONFIG_SCSI) && !uclass_id_count(UCLASS_SCSI)) { - /* Scan for SCSI devices, unless already scanned earlier in boot */ + if (IS_ENABLED(CONFIG_SCSI)) { ret = scsi_scan(false); if (ret) { debug("Failed to scan SCSI devices: %d\n", ret); From c22b01a72d38f932b071dfa6f9b0f278647c2852 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Sun, 6 Sep 2026 13:40:50 +0530 Subject: [PATCH 03/52] scsi: Add scsi_scan_new() to scan only new devices scsi_scan() removes existing SCSI block devices before rescanning, which can invalidate existing references and requires callers to avoid redundant scans. Add scsi_scan_new() to scan only controllers without bound block devices, making repeated scans safe and eliminating the need for scan guards at individual call sites. Signed-off-by: Aswin Murugan --- drivers/scsi/scsi.c | 27 +++++++++++++++++++++++++++ include/scsi.h | 8 ++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 50e7d7499212..aed827628de7 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -638,6 +638,33 @@ int scsi_scan_dev(struct udevice *dev, bool verbose) return 0; } +int scsi_scan_new(bool verbose) +{ + struct uclass *uc; + struct udevice *dev; + int ret; + + if (verbose) + printf("scanning bus for devices...\n"); + + ret = uclass_get(UCLASS_SCSI, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + struct udevice *blk; + + if (device_find_first_child_by_uclass(dev, UCLASS_BLK, &blk) == 0) + continue; + + ret = scsi_scan_dev(dev, verbose); + if (ret) + return ret; + } + + return 0; +} + int scsi_scan(bool verbose) { struct uclass *uc; diff --git a/include/scsi.h b/include/scsi.h index 83aaf0a70f63..4355aef5f6b7 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -353,6 +353,14 @@ int scsi_scan(bool verbose); */ int scsi_scan_dev(struct udevice *dev, bool verbose); +/** + * scsi_scan_new() - Scan all SCSI controllers for new devices + * + * @verbose: true to show information about each device found + * Return: 0 if OK, -ve on error + */ +int scsi_scan_new(bool verbose); + /** * scsi_get_blk_by_uuid() - Provides SCSI partition information. * From a362d4b7ac0ce717636347a47775681060849115 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Sun, 6 Sep 2026 13:41:19 +0530 Subject: [PATCH 04/52] arm: qcom: rescan only newly added SCSI devices for capsule update Capsule update may miss newly attached SCSI storage when SCSI has already been scanned earlier in boot. Use scsi_scan_new() to detect newly added devices while avoiding rescanning controllers that already have enumerated block devices. Signed-off-by: Aswin Murugan --- arch/arm/mach-snapdragon/capsule_update.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-snapdragon/capsule_update.c b/arch/arm/mach-snapdragon/capsule_update.c index d3efba4816aa..77eae492b731 100644 --- a/arch/arm/mach-snapdragon/capsule_update.c +++ b/arch/arm/mach-snapdragon/capsule_update.c @@ -642,7 +642,8 @@ void qcom_configure_capsule_updates(void) memset(partitions, 0, sizeof(qcom_partitions)); if (IS_ENABLED(CONFIG_SCSI)) { - ret = scsi_scan(false); + /* Scan for SCSI devices, unless already scanned earlier in boot */ + ret = scsi_scan_new(false); if (ret) { debug("Failed to scan SCSI devices: %d\n", ret); return; From e7fc299feae2de1104aaa7377183b362b83e0ff4 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 2 Sep 2026 22:55:46 +0530 Subject: [PATCH 05/52] Revert "[qcom-next] SPL Lemans Fixes" (PR #85) Revert the SPL Lemans fixes merged via qualcomm-linux/u-boot PR #85 (https://github.com/qualcomm-linux/u-boot/pull/85). This reverts the following qcom-next commits: 5f0cc1dcc75 configs: lemans_spl: Remove TEXT_BASE and REMAKE_ELF configs 530ecc767c8 arm: dts: lemans-evk: Remove hardcoded memory node bede6f826e7 misc: qcom-spmi-sdam: Add PHASE_ prefix support Signed-off-by: Balaji Selvanathan --- arch/arm/dts/lemans-evk-u-boot.dtsi | 15 +++++++++++++++ configs/qcom_lemans_spl_defconfig | 3 +++ drivers/misc/Makefile | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/lemans-evk-u-boot.dtsi b/arch/arm/dts/lemans-evk-u-boot.dtsi index fd4eaa2fec81..49b95d8ba4ff 100644 --- a/arch/arm/dts/lemans-evk-u-boot.dtsi +++ b/arch/arm/dts/lemans-evk-u-boot.dtsi @@ -4,6 +4,21 @@ */ / { + /* Will be removed when bootloader updates later */ + memory@80000000 { + device_type = "memory"; + bootph-all; /* Include memory node in SPL DTB */ + reg = <0x0 0x80000000 0x0 0x3ee00000>, + <0x0 0xc0000000 0x0 0x04d00000>, + <0xd 0x00000000 0x2 0x54100000>, + <0xa 0x80000000 0x1 0x52d00000>, + <0x9 0x00000000 0x1 0x80000000>, + <0x1 0x00000000 0x2 0xf7500000>, + <0x0 0xd0000000 0x0 0x00100000>, + <0x0 0xd3500000 0x0 0x07c00000>, + <0x0 0xdb300000 0x0 0x24d00000>; + }; + clocks { /* Fixed clocks needed by GCC */ xo_board_clk { diff --git a/configs/qcom_lemans_spl_defconfig b/configs/qcom_lemans_spl_defconfig index d04397aadfd5..8b63e44d4400 100644 --- a/configs/qcom_lemans_spl_defconfig +++ b/configs/qcom_lemans_spl_defconfig @@ -5,6 +5,9 @@ #include "qcom_defconfig" +# Address where U-Boot proper will be loaded +CONFIG_TEXT_BASE=0xaf000000 +CONFIG_REMAKE_ELF=y CONFIG_FASTBOOT_BUF_ADDR=0xdb300000 CONFIG_DEFAULT_DEVICE_TREE="qcom/lemans-evk" CONFIG_ENV_IS_IN_SCSI=y diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 791ba1e1d05e..70617bc22aa6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -65,7 +65,7 @@ obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif -obj-$(CONFIG_$(PHASE_)QCOM_SPMI_SDAM) += qcom-spmi-sdam.o +obj-$(CONFIG_QCOM_SPMI_SDAM) += qcom-spmi-sdam.o obj-$(CONFIG_$(PHASE_)QCOM_GENI) += qcom_geni.o obj-$(CONFIG_QCOM_GENI_MINICORE) += qcom_geni-minicore.o obj-$(CONFIG_$(PHASE_)QCOM_HWINFO) += qcom_hwinfo.o From f458f6b9ed86fbd51d7e567ba9ba65e572f39806 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 2 Sep 2026 22:57:24 +0530 Subject: [PATCH 06/52] Revert "[qcom-next] Add U-Boot SPL support for Lemans EVK" (PR #79) Revert the Lemans EVK SPL support merged via qualcomm-linux/u-boot PR #79 (https://github.com/qualcomm-linux/u-boot/pull/79). This reverts the following qcom-next commits: 4c09f120ac0 qcom_lemans_spl: disable SPL_QCOM_BOOT_FROM_PBL for XBL boot 1d6874671a3 mach-snapdragon: spl: add SPL_QCOM_BOOT_FROM_PBL Kconfig option c910816dac9 configs: qcom: Add qcom_lemans_spl_defconfig for Lemans EVK ad30037010f arm: dts: qcom: Add Lemans EVK U-Boot DTS overlay for SPL Signed-off-by: Balaji Selvanathan --- arch/arm/dts/lemans-evk-u-boot.dtsi | 59 +++------------- arch/arm/mach-snapdragon/Kconfig | 14 ---- arch/arm/mach-snapdragon/spl.c | 105 +++++++++++---------------- configs/qcom_lemans_spl_defconfig | 106 ---------------------------- 4 files changed, 50 insertions(+), 234 deletions(-) delete mode 100644 configs/qcom_lemans_spl_defconfig diff --git a/arch/arm/dts/lemans-evk-u-boot.dtsi b/arch/arm/dts/lemans-evk-u-boot.dtsi index 49b95d8ba4ff..e07f43110cba 100644 --- a/arch/arm/dts/lemans-evk-u-boot.dtsi +++ b/arch/arm/dts/lemans-evk-u-boot.dtsi @@ -1,33 +1,20 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * Copyright (c) 2026, Qualcomm Innovation Center, Inc. All rights reserved. */ / { /* Will be removed when bootloader updates later */ memory@80000000 { device_type = "memory"; - bootph-all; /* Include memory node in SPL DTB */ reg = <0x0 0x80000000 0x0 0x3ee00000>, - <0x0 0xc0000000 0x0 0x04d00000>, - <0xd 0x00000000 0x2 0x54100000>, - <0xa 0x80000000 0x1 0x52d00000>, + <0x0 0xc0000000 0x0 0x0fd00000>, + <0xD 0x00000000 0x2 0x54100000>, + <0xA 0x80000000 0x1 0x80000000>, <0x9 0x00000000 0x1 0x80000000>, - <0x1 0x00000000 0x2 0xf7500000>, - <0x0 0xd0000000 0x0 0x00100000>, - <0x0 0xd3500000 0x0 0x07c00000>, - <0x0 0xdb300000 0x0 0x24d00000>; - }; - - clocks { - /* Fixed clocks needed by GCC */ - xo_board_clk { - bootph-all; - }; - - sleep_clk { - bootph-all; - }; + <0x1 0x00000000 0x3 0x00000000>, + <0x0 0xd0000000 0x0 0x01900000>, + <0x0 0xd3500000 0x0 0x2cb00000>; }; /* IMEM boot cookie + TCSR HW version offsets */ @@ -42,40 +29,10 @@ }; }; -&ufs_mem_hc { - bootph-all; /* Enable UFS for SPL */ -}; - -&ufs_mem_phy { - bootph-all; -}; - -&gcc { - bootph-all; /* Enable GCC for SPL */ -}; - -/* RPMH clock controller - required by GCC */ -&rpmhcc { - bootph-all; -}; - -/* Apps RSC - parent of rpmhcc and rpmhpd */ -&apps_rsc { - bootph-all; -}; - -/* UART10 - console serial port */ -&uart10 { - bootph-all; -}; - -&tlmm { - bootph-all; /* Make TLMM GPIO controller available in SPL */ -}; - /* Enter Qualcomm EDL/download mode via "reset -edl". */ &{/psci} { reboot-mode { mode-edl = <0x80000000 0x00000001>; }; }; + diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 0e1a1117ff29..8a95616a11dd 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -45,20 +45,6 @@ config SYS_CONFIG_NAME Based on this option include/configs/.h header will be used for board configuration. -config SPL_QCOM_BOOT_FROM_PBL - bool "U-Boot SPL is loaded directly by PBL" - depends on SPL - default y - help - Enable this option when U-Boot SPL is loaded directly by PBL (Primary - Boot Loader). In this case, PBL passes boot parameters via r0 register - containing a pointer to pbl_shared_data structure. - - Disable this option when U-Boot SPL is loaded by XBL or another - intermediate bootloader (e.g., PBL->XBL->U-Boot SPL). In such cases, - the r0 register won't contain valid PBL shared data, and boot device - detection will use fallback mechanisms. - config QCOM_FIT_MULTIDTB bool "Enable FIT multi-DTB selection for Qualcomm platforms" depends on FIT diff --git a/arch/arm/mach-snapdragon/spl.c b/arch/arm/mach-snapdragon/spl.c index bfe4dc8dd011..c1a7d4cb00f4 100644 --- a/arch/arm/mach-snapdragon/spl.c +++ b/arch/arm/mach-snapdragon/spl.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,8 +38,6 @@ DECLARE_GLOBAL_DATA_PTR; #define QCCONFIG "qc_config" #define QCSDI "qcsdi" -struct mm_region *mem_map = NULL; - /** * struct interface_table_entry - Meta data for blobs in QCLIB interface * @entry_name: Name of the data blob (e.g., "dcb_settings"). @@ -607,22 +605,19 @@ static struct pbl_shared_data g_psd __section(".data"); void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3) { unsigned long sctlr; + struct pbl_shared_data *psd; sctlr = get_sctlr(); set_sctlr(sctlr & ~(CR_M)); /* Disable MMU */ - /* - * When U-Boot SPL is loaded directly by PBL, r0 contains a pointer - * to pbl_shared_data structure. When loaded via XBL or another - * intermediate bootloader, r0 won't contain valid PBL data. - */ - if (CONFIG_IS_ENABLED(QCOM_BOOT_FROM_PBL)) { - struct pbl_shared_data *psd = (struct pbl_shared_data *)r0; + psd = (struct pbl_shared_data *)r0; - if (psd && psd->num_of_entries >= PBL_SHARED_DATA_PARAM_MAX) - memcpy(&g_psd, psd, sizeof(g_psd)); - } + if (!psd || psd->num_of_entries < PBL_SHARED_DATA_PARAM_MAX) + goto out; + + memcpy(&g_psd, psd, sizeof(g_psd)); +out: save_boot_params_ret(); } @@ -636,49 +631,35 @@ u32 spl_boot_device(void) { struct pbl_shared_data *psd = &g_psd; - /* - * When booted directly from PBL, use PBL shared data to determine - * boot device. When booted via XBL, fall back to compile-time config. - */ - if (CONFIG_IS_ENABLED(QCOM_BOOT_FROM_PBL)) { #ifdef DEBUG - for (int i = 0; psd && i < psd->num_of_entries; i++) { - printf("entry[0x%x] = %d 0x%08x %d\n", i, - psd->entry[i].param_id, psd->entry[i].value, - psd->entry[i].valid); - } + for (int i = 0; psd && i < psd->num_of_entries; i++) { + printf("entry[0x%x] = %d 0x%08x %d\n", i, + psd->entry[i].param_id, psd->entry[i].value, + psd->entry[i].valid); + } #endif - if (psd->entry[PSD_ID_IS_EDL_MODE].valid && - psd->entry[PSD_ID_IS_EDL_MODE].value) { - printf("Selected boot device: DFU\n"); - return BOOT_DEVICE_DFU; + if (psd->entry[PSD_ID_IS_EDL_MODE].valid && + psd->entry[PSD_ID_IS_EDL_MODE].value) { + printf("Selected boot device: DFU\n"); + return BOOT_DEVICE_DFU; + } + + if (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].valid) { + switch (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].value) { + case PSD_MMC_FLASH: + printf("Selected boot device: MMC\n"); + return BOOT_DEVICE_MMC1; + case PSD_NOR_FLASH: + printf("Selected boot device: NOR\n"); + return BOOT_DEVICE_NOR; + case PSD_NAND_FLASH: + printf("Selected boot device: NAND\n"); + return BOOT_DEVICE_NAND; + case PSD_UFS_FLASH: + printf("Selected boot device: UFS\n"); + return BOOT_DEVICE_UFS; } - - if (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].valid) { - switch (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].value) { - case PSD_MMC_FLASH: - printf("Selected boot device: MMC\n"); - return BOOT_DEVICE_MMC1; - case PSD_NOR_FLASH: - printf("Selected boot device: NOR\n"); - return BOOT_DEVICE_NOR; - case PSD_NAND_FLASH: - printf("Selected boot device: NAND\n"); - return BOOT_DEVICE_NAND; - case PSD_UFS_FLASH: - printf("Selected boot device: UFS\n"); - return BOOT_DEVICE_UFS; - } - } - } - - /* - * Fallback: Use UFS when PBL shared data is not available - */ - if (IS_ENABLED(CONFIG_SPL_UFS_QCOM)) { - printf("Selected boot device: UFS\n"); - return BOOT_DEVICE_UFS; } pr_err("No boot device configured\n"); @@ -706,18 +687,16 @@ void board_init_f(ulong dummy) preloader_console_init(); - if (CONFIG_IS_ENABLED(QCOM_BOOT_FROM_PBL)) { - ret = qcom_spl_loader_pre_ddr(spl_boot_device()); - if (ret) { - pr_debug("qcom_spl_loader_pre_ddr() failed (%d)\n", ret); - goto fail; - } + ret = qcom_spl_loader_pre_ddr(spl_boot_device()); + if (ret) { + pr_debug("qcom_spl_loader_pre_ddr() failed (%d)\n", ret); + goto fail; + } - ret = qclib_post_process_from_spl(); - if (ret) { - pr_debug("qclib_post_process_from_spl() failed (%d)\n", ret); - goto fail; - } + ret = qclib_post_process_from_spl(); + if (ret) { + pr_debug("qclib_post_process_from_spl() failed (%d)\n", ret); + goto fail; } board_init_r(NULL, 0); diff --git a/configs/qcom_lemans_spl_defconfig b/configs/qcom_lemans_spl_defconfig deleted file mode 100644 index 8b63e44d4400..000000000000 --- a/configs/qcom_lemans_spl_defconfig +++ /dev/null @@ -1,106 +0,0 @@ -# Configuration for building U-Boot to be flashed -# to the uefi partition of Lemans-EVK dev boards with -# the "Linux Embedded" partition layout (which have -# a dedicated "uefi" partition for edk2/U-Boot) - -#include "qcom_defconfig" - -# Address where U-Boot proper will be loaded -CONFIG_TEXT_BASE=0xaf000000 -CONFIG_REMAKE_ELF=y -CONFIG_FASTBOOT_BUF_ADDR=0xdb300000 -CONFIG_DEFAULT_DEVICE_TREE="qcom/lemans-evk" -CONFIG_ENV_IS_IN_SCSI=y -CONFIG_ENV_SCSI_PART_USE_TYPE_GUID=y -# SCSI partition type GUID for logfs partition -CONFIG_ENV_SCSI_PART_TYPE_GUID="bc0330eb-3410-4951-a617-03898dbe3372" -# CONFIG_ENV_IS_DEFAULT is not set -# CONFIG_ENV_IS_NOWHERE is not set - -# SPL configurations for Lemans-EVK -# Purpose: Load FIT image (containing TFA, OPTEE and U-Boot proper) -# from UFS storage and jump to next image (TFA) - -CONFIG_SPL=y -CONFIG_SPL_BUILD=y -CONFIG_SPL_FRAMEWORK=y - -CONFIG_SPL_TEXT_BASE=0x1c100000 -CONFIG_SPL_MAX_SIZE=0x60000 -CONFIG_SPL_BSS_LIMIT=y -CONFIG_SPL_BSS_MAX_SIZE=0x10000 -# CONFIG_SPL_SEPARATE_BSS is not set - -# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set -CONFIG_SPL_HAVE_INIT_STACK=y -CONFIG_SPL_STACK=0xD7300000 - -CONFIG_SPL_SYS_MALLOC_F_LEN=0x80000 -CONFIG_SPL_SYS_MALLOC=y -CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y -CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0xdb300000 -CONFIG_SPL_SYS_MALLOC_SIZE=0x10000 - -CONFIG_SPL_LIBCOMMON_SUPPORT=y -CONFIG_SPL_LIBGENERIC_SUPPORT=y - -CONFIG_SPL_DM=y -CONFIG_SPL_OF_LIBFDT=y -CONFIG_SPL_OF_CONTROL=y -CONFIG_SPL_OF_REAL=y -CONFIG_SPL_SIMPLE_BUS=y - -CONFIG_SPL_DM_RESET=y - -CONFIG_SPL_CLK=y - -CONFIG_SPL_GPIO=y -CONFIG_SPL_DM_GPIO=y - -CONFIG_SPL_UFS=y -CONFIG_SPL_UFS_QCOM=y - -CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM=4 -CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR=0x0 -CONFIG_SPL_UFS_RAW_U_BOOT_USE_PARTITION=y -CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME="uefi_a" -CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NUM=1 - -CONFIG_SPL_PARTITIONS=y -CONFIG_SPL_DOS_PARTITION=y -CONFIG_SPL_CHARSET=y - -CONFIG_SPL_PHY=y -CONFIG_SPL_PHY_QCOM_QMP_UFS=y - -CONFIG_SPL_POWER=y -CONFIG_SPL_POWER_DOMAIN=y - -CONFIG_SPL_LOAD_FIT=y - -CONFIG_SPL_ATF=y - -CONFIG_SPL_REMAKE_ELF=y - -CONFIG_COUNTER_FREQUENCY=19200000 - -# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set -# CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR is not set -CONFIG_SPL_ATF_LOAD_IMAGE_V2=y -CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y -CONFIG_SPL_HAS_LOAD_FIT_ADDRESS=y -CONFIG_SPL_LOAD_FIT_ADDRESS=0xB0800000 -CONFIG_SPL_FRAMEWORK_BOARD_INIT_F=y - -CONFIG_SPL_DRIVERS_MISC=y -CONFIG_SPL_SERIAL=y -CONFIG_SPL_MISC=y -CONFIG_SPL_QCOM_GENI=y -CONFIG_SPL_MSM_GENI_SERIAL=y - -CONFIG_SPL_BANNER_PRINT=y -CONFIG_SPL_CLK_STUB=y -CONFIG_SPL_PINCTRL=y -CONFIG_SPL_PINCTRL_QCOM_SA8775P=y -CONFIG_SPL_QCOM_SMEM=y -# CONFIG_SPL_QCOM_BOOT_FROM_PBL is not set From 49d2451347c28d3f4249671d11d976a2fa7541e1 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 2 Sep 2026 22:57:24 +0530 Subject: [PATCH 07/52] Revert "[qcom-next] Add SPL support for Qualcomm Snapdragon SoCs" (PR #77) Revert the initial SPL support for Qualcomm Snapdragon SoCs (IPQ5210 and core SPL infrastructure) merged via qualcomm-linux/u-boot PR #77 (https://github.com/qualcomm-linux/u-boot/pull/77). This reverts the following qcom-next commits: 976563d59b0 doc: board/qualcomm: Update RDP build instructions 9fa2f2729e3 configs: add qcom_ipq5210_mmc_defconfig 2bd29d62790 mach-snapdragon: Add commands to create wrapper ELF 18e16eea7b2 mach-snapdragon: spl: Update SMEM with boot details 60b1477d513 mach-snapdragon: Add initial support for QCOM SPL e3003d1678c spl: Include SMEM driver in SPL 3635906b1e2 mach-snapdragon: Add PBL shared data defines 16c3f9249d0 misc: qcom_geni: Add minicore support f460d843b62 pinctrl: qcom: Add ipq5210 pinctrl driver 945097fb64d clk/qcom: add initial clock driver for ipq5210 316563b1a79 dts: ipq5210-rdp504-u-boot: add override dtsi 3034e843062 binman: qcom: Add type definitions for Qualcomm binaries eb026ca0450 binman: Ignore noload segments for image numbering Signed-off-by: Balaji Selvanathan --- arch/arm/Kconfig | 5 +- arch/arm/dts/ipq5210-rdp504-u-boot.dtsi | 128 --- arch/arm/mach-snapdragon/Kconfig | 8 - arch/arm/mach-snapdragon/Makefile | 3 - .../mach-snapdragon/ipq5210-spl-wrap-elf.lds | 18 - arch/arm/mach-snapdragon/qcom-priv.h | 51 -- arch/arm/mach-snapdragon/spl.c | 749 ------------------ common/spl/Kconfig | 8 - configs/qcom_ipq5210_mmc_defconfig | 106 --- doc/board/qualcomm/rdp.rst | 83 +- drivers/Makefile | 1 - drivers/clk/qcom/Kconfig | 8 - drivers/clk/qcom/Makefile | 1 - drivers/clk/qcom/clock-ipq5210.c | 98 --- drivers/misc/Kconfig | 6 - drivers/misc/Makefile | 1 - drivers/misc/qcom_geni-minicore.c | 102 --- drivers/misc/qcom_geni.c | 100 +-- drivers/pinctrl/qcom/Kconfig | 8 - drivers/pinctrl/qcom/Makefile | 1 - drivers/pinctrl/qcom/pinctrl-ipq5210.c | 349 -------- include/soc/qcom/geni-se.h | 5 - include/soc/qcom/qup-fw-load.h | 12 - include/soc/qcom/smem.h | 4 - scripts/Makefile.xpl | 24 - tools/binman/elf.py | 4 +- tools/binman/etype/qcom_appsbl.py | 18 - tools/binman/etype/qcom_config.py | 21 - tools/binman/etype/qcom_lib.py | 21 - 29 files changed, 16 insertions(+), 1927 deletions(-) delete mode 100644 arch/arm/dts/ipq5210-rdp504-u-boot.dtsi delete mode 100644 arch/arm/mach-snapdragon/ipq5210-spl-wrap-elf.lds delete mode 100644 arch/arm/mach-snapdragon/spl.c delete mode 100644 configs/qcom_ipq5210_mmc_defconfig delete mode 100644 drivers/clk/qcom/clock-ipq5210.c delete mode 100644 drivers/misc/qcom_geni-minicore.c delete mode 100644 drivers/pinctrl/qcom/pinctrl-ipq5210.c delete mode 100644 tools/binman/etype/qcom_appsbl.py delete mode 100644 tools/binman/etype/qcom_config.py delete mode 100644 tools/binman/etype/qcom_lib.py diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8304c2ebb7f9..4e4d3a3e157d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1146,13 +1146,12 @@ config ARCH_SNAPDRAGON select SPMI select BOARD_LATE_INIT select OF_BOARD - select SAVE_PREV_BL_FDT_ADDR if !ENABLE_ARM_SOC_BOOT0_HOOK && !SPL - select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK && !SPL + select SAVE_PREV_BL_FDT_ADDR if !ENABLE_ARM_SOC_BOOT0_HOOK + select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK select SYSRESET select SYSRESET_PSCI if !QCOM_SNAGBOOT_MODE select ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR select MMU_PGPROT - select SUPPORT_SPL imply OF_UPSTREAM imply CMD_DM imply DM_USB_GADGET diff --git a/arch/arm/dts/ipq5210-rdp504-u-boot.dtsi b/arch/arm/dts/ipq5210-rdp504-u-boot.dtsi deleted file mode 100644 index 5f19915047b5..000000000000 --- a/arch/arm/dts/ipq5210-rdp504-u-boot.dtsi +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * IPQ5210 RDP504 board device tree source - * - * Copyright (c) 2026 The Linux Foundation. All rights reserved. - */ - -/ { - /* Will be removed when SMEM parsing is updated */ - memory@80000000 { - bootph-all; - device_type = "memory"; - reg = <0x0 0x80000000 0x0 0x20000000>; - }; - - binman: binman { - description = "IPQ5210 boot loader"; - fit { - description = "IPQ5210 Boot Loader FIT"; - fit,fdt-list = "of-list"; - fit,external-offset = <0x0>; - - images { - @qcom-config-SEQ { - fit,operation = "split-elf"; - description = "QC Config"; - type = "qcom-config"; - arch = "arm64"; - os = "elf"; - compression = "none"; - fit,load; - fit,entry; - fit,data; - - qcom-config { - }; - }; - - @qcom-lib-SEQ { - fit,operation = "split-elf"; - description = "QC Lib"; - arch = "arm64"; - os = "elf"; - type = "qcom-lib"; - compression = "none"; - fit,load; - fit,entry; - fit,data; - - qcom-lib { - }; - }; - - @atf-SEQ { - fit,operation = "split-elf"; - description = "ARM Trusted Firmware"; - type = "atf_bl31"; - arch = "arm64"; - os = "arm-trusted-firmware"; - compression = "none"; - fit,load; - fit,entry; - fit,data; - - atf-bl31 { - }; - }; - - @qcom-appsbl-SEQ { - fit,operation = "split-elf"; - type = "qcom-appsbl"; - os = "U-Boot"; - arch = "arm64"; - compression = "none"; - fit,load; - fit,entry; - fit,data; - - qcom-appsbl { - }; - }; - - @tee-SEQ { - fit,operation = "split-elf"; - description = "TEE"; - type = "tee_os"; - arch = "arm64"; - os = "tee"; - compression = "none"; - fit,load; - fit,entry; - fit,data; - - tee-os { - }; - }; - }; - - configurations { - default = "pre-ddr"; - - pre-ddr { - description = "pre-ddr"; - loadables = "qcom-config-1", - "qcom-config-2", - "qcom-config-3", - "qcom-config-4", - "qcom-lib-1", - "qcom-lib-2", - "qcom-lib-3", - "qcom-lib-4"; - }; - - post-ddr { - description = "post-ddr"; - loadables = "atf-1", - "atf-2", - "atf-3", - "atf-4", - "atf-5", - "atf-6", - "qcom-appsbl-1", - "tee-1"; - }; - }; - }; - }; -}; diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 8a95616a11dd..c808f6febca0 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -86,14 +86,6 @@ config QCOM_EL2_GUNYAH_EXIT_SUPPORT endchoice -config SPL_WRAPPER_ELF - bool "Create wrapper ELF for applicable platforms" - depends on SPL - help - Some platforms embed the U-Boot SPL binary within an ELF as a segment. - Additional tools are used to convert this ELF into an image that is - usable for the boot ROM. - config QCOM_BOOT0_SNAGBOOT_MODE bool "boot0.h initialization for Snagboot mode" help diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index c80f63e33f65..1566bbe50a1f 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -2,11 +2,8 @@ # # (C) Copyright 2015 Mateusz Kulikowski -ifndef CONFIG_XPL_BUILD obj-y += board.o dram.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o obj-$(CONFIG_QCOM_FIT_MULTIDTB) += qcom_fit_multidtb.o obj-$(CONFIG_QCOM_HWDETECT) += qcom_hwdetect.o obj-$(CONFIG_OF_LIVE) += of_fixup.o -endif -obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/arm/mach-snapdragon/ipq5210-spl-wrap-elf.lds b/arch/arm/mach-snapdragon/ipq5210-spl-wrap-elf.lds deleted file mode 100644 index 5a582e65ca02..000000000000 --- a/arch/arm/mach-snapdragon/ipq5210-spl-wrap-elf.lds +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-2.0 - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - */ -PHDRS { - ptype PT_LOAD FLAGS(0x7); -} - -ENTRY(_entry) - -SECTIONS { - . = IMAGE_TEXT_BASE; - _entry = . ; - data : { - *(.data) - . = ALIGN(4); - } :ptype -} diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h index 327e378e4fd3..39dc8fcc76ad 100644 --- a/arch/arm/mach-snapdragon/qcom-priv.h +++ b/arch/arm/mach-snapdragon/qcom-priv.h @@ -39,56 +39,5 @@ void qcom_configure_capsule_updates(void) {} #endif /* EFI_HAVE_CAPSULE_SUPPORT */ int qcom_parse_memory(const void *fdt, bool fdt_is_internal); -enum pbl_shared_data_param_id { - PSD_ID_PBL_FW_VERSION = 0x0, /* PBL firmware version */ - PSD_ID_PBL_PATCH_VERSION = 0x1, /* Patch version */ - PSD_ID_RMB_MBOX_BASE_ADDR = 0x2, /* Not used */ - PSD_ID_CPU_BOOT_SPEED_HZ = 0x3, /* CPU boot speed (Hz) */ - PSD_ID_BOOT_MEDIA_TYPE = 0x4, /* Boot media type */ - PSD_ID_IS_EDL_MODE = 0x5, /* Emergency Download mode */ - PSD_ID_DEV_PROG_ELF_ENTRY_ADDR = 0x6, /* Not used */ - PSD_ID_XBL_CONFIG_ELF_ENTRY_ADDR = 0x7, /* Not used */ - PSD_ID_XBL_SC_EXT_ELF_ENTRY_ADDR = 0x8, /* Not used */ - PSD_ID_PBL_TIMESTAMPS_BUFFER_ADDR = 0x9, /* PBL logs address */ - PSD_ID_PBL_TIMESTAMPS_BUFFER_SIZE = 0xa, /* PBL log size */ - PSD_ID_PBL_DEBUG_SHARED_INFO_ADDR = 0xb, /* Debug info address */ - PSD_ID_PBL_DEBUG_SHARED_INFO_SIZE = 0xc, /* Debug info size */ - PSD_ID_TME_CPU_PBL_ROM_BYPASS_FUSE = 0xd, /* Secure boot status */ - PSD_ID_XBL_SC_DEBUG_LOG_ADDR = 0xe, /* XBL SC debug log address */ - PSD_ID_XBL_SC_DEBUG_LOG_SIZE = 0xf, /* XBL SC debug log size */ - PSD_ID_CURRENT_IMAGE_SET = 0x10, /* Booted image set */ - PSD_ID_MEDIA_DATA_INFO_ADDR = 0x11, /* Media info pointer */ - PSD_ID_MEDIA_DATA_INFO_SIZE = 0x12, /* Media info size */ - PBL_SHARED_DATA_PARAM_MAX, - PBL_SHARED_DATA_PARAM_SIZE = 0xffffffffu, /* to force 32 bits */ -}; - -enum pbl_boot_flash_type { - PSD_NO_FLASH = 0, - PSD_NOR_FLASH = 1, - PSD_NAND_FLASH = 2, - PSD_ONENAND_FLASH = 3, - PSD_SDC_FLASH = 4, - PSD_MMC_FLASH = 5, - PSD_SPI_FLASH = 6, - PSD_PCIE_FLASH = 7, - PSD_UFS_FLASH = 8, - PSD_RSVD_1_FLASH = 9, - PSD_USB_FLASH = 10, - PSD_SPI_NAND_FLASH = 11, - PSD_SPI_FLASH_GPT = 12, -}; - -struct pbl_shared_data_entry { - u32 param_id; - ulong value; - bool valid; -}; - -struct pbl_shared_data { - u32 version; - u32 num_of_entries; - struct pbl_shared_data_entry entry[PBL_SHARED_DATA_PARAM_MAX]; -}; #endif /* __QCOM_PRIV_H__ */ diff --git a/arch/arm/mach-snapdragon/spl.c b/arch/arm/mach-snapdragon/spl.c deleted file mode 100644 index c1a7d4cb00f4..000000000000 --- a/arch/arm/mach-snapdragon/spl.c +++ /dev/null @@ -1,749 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qcom-priv.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define QCOM_SPL_TCSR_REG_ADDR 0x195c100 -#define QCOM_SPL_DLOAD_MASK BIT(4) -#define QCOM_SPL_DLOAD_SHFT 0x4 - -#define QCOM_SPL_IS_DLOAD_BIT_SET ((readl(QCOM_SPL_TCSR_REG_ADDR) & \ - QCOM_SPL_DLOAD_MASK) >> \ - QCOM_SPL_DLOAD_SHFT) - -#define QCOM_SPL_FIT_IMG_PARTITION "0:BOOTLDR" - -#define MAGIC_KEY "QCLIB_CB" -#define MAX_ENTRIES 0xF -#define IF_TABLE_VERSION 0x1 -#define QCCONFIG "qc_config" -#define QCSDI "qcsdi" - -/** - * struct interface_table_entry - Meta data for blobs in QCLIB interface - * @entry_name: Name of the data blob (e.g., "dcb_settings"). - * @address: Address of the data blob. - * @size: Size of the data blob. - * @attributes: Attributes for the blob (e.g., save to storage). - */ -struct interface_table_entry { - char entry_name[24]; - u64 address; - u32 size; - u32 attributes; -}; - -/** - * struct interface_table - QCLIB Interface table header - * @magic_key: Magic key for validation ("QCLIB_CB"). - * @version: Interface table version. - * @num_entries: Number of valid entries. - * @max_entries: Maximum allowable entries. - * @global_attributes: Flags for global attributes (e.g., SDI path). - * @reserved1: Reserved for future use. - * @reserved2: Reserved for future use. - * @if_table_entries: Array of interface table entries. - */ -struct interface_table { - char magic_key[8]; - u32 version; - u32 num_entries; - u32 max_entries; - u32 global_attributes; - u32 reserved1; - u32 reserved2; - struct interface_table_entry if_table_entries[MAX_ENTRIES]; -}; - -/** - * qcom_spl_jump_img_entry_t - Type definition for image entry point functions. - * @arg1: First argument passed to the entry point. - * @arg2: Second argument passed to the entry point. - */ -typedef void (*qcom_spl_jump_img_entry_t)(void *arg1, void *arg2); - -/* - * Global QCSDI address populated by qclib_post_process_from_spl - * Placed in .data section to ensure it persists - */ -static u64 g_qcsdi_address __section(".data"); - -/** - * lowlevel_init() - Early low-level initialization. - * - * This function performs very early hardware initialization, - * specifically disabling the MMU if enabled by PBL. - */ -void lowlevel_init(void) -{ -} - -/** - * qcom_spl_error_handler() - Centralized SPL error handler. - * @arg: Generic argument (unused). - * - * This function is invoked upon critical errors during the SPL boot process. - */ -void qcom_spl_error_handler(void *arg) -{ - pr_err("Entered the SPL Error Handler\n"); - hang(); -} - -/** - * qcom_spl_malloc_init_f() - Initialize malloc for SPL. - * - * This function initializes the malloc subsystem using the memory region - */ -void qcom_spl_malloc_init_f(void) -{ - if (!CONFIG_IS_ENABLED(SYS_MALLOC_F)) - return; - /* - * Set up by crt0.S - */ - assert(gd->malloc_base); - gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); - gd->malloc_ptr = 0; - - mem_malloc_init(gd->malloc_base, gd->malloc_limit); - gd->flags |= GD_FLG_FULL_MALLOC_INIT; -} - -/** - * qcom_spl_get_fit_img_entry_point() - Get entry point from FIT image node. - * @fit: Pointer to the FIT image blob. - * @node: Node ID within the FIT image. - * @entry_point: Pointer to store the retrieved entry point. - * - * Return: 0 on success, or a negative error code on failure. - */ -static int qcom_spl_get_fit_img_entry_point(void *fit, int node, - u64 *entry_point) -{ - int ret; - - if (!fit) { - pr_err("FIT image blob is NULL\n"); - return -EINVAL; - } - if (node <= 0) { - pr_err("Invalid FIT node ID %d\n", node); - return -EINVAL; - } - if (!entry_point) { - pr_err("Entry point pointer is NULL\n"); - return -EINVAL; - } - - ret = fit_image_get_entry(fit, node, (ulong *)entry_point); - if (ret) { - pr_debug("No entry point for node %d, trying load address\n", - node); - ret = fit_image_get_load(fit, node, (ulong *)entry_point); - if (ret) - pr_err("No load address for node %d (%d)\n", node, ret); - } - - return ret; -} - -#if IS_ENABLED(CONFIG_SPL_SMEM) -/** - * qcom_spl_populate_smem() - Populate shared memory (SMEM) information. - * @ctx: Pointer to the global SPL context. - * - * This function initializes and populates various SMEM items with boot-related - * information, such as flash type, try-mode status, and ATF enable status. - * Return: 0 on success, or a negative error code on failure. - */ -static int qcom_spl_populate_smem(void *ctx) -{ - int ret; - size_t size; - struct udevice *smem; - u32 *fltype; - - ret = uclass_get_device(UCLASS_SMEM, 0, &smem); - if (ret) { - pr_err("Failed to find SMEM node (%d)\n", ret); - return ret; - } - - size = sizeof(u32); - ret = smem_alloc(smem, -1, SMEM_BOOT_FLASH_TYPE, size); - if (ret) { - pr_err("Failed to alloc item: SMEM_BOOT_FLASH_TYPE (%d)\n", ret); - return ret; - } - - fltype = (u32 *)smem_get(smem, -1, SMEM_BOOT_FLASH_TYPE, &size); - if (!fltype) { - pr_err("Failed to get item: SMEM_BOOT_FLASH_TYPE\n"); - return -ENOENT; - } - - if (IS_ENABLED(CONFIG_SPL_MMC)) { - *fltype = SMEM_BOOT_MMC_FLASH; - return 0; - } - - pr_err("Boot medium not specified\n"); - - return -ENOENT; -} -#endif /* IS_ENABLED(CONFIG_SPL_SMEM) */ - -/** - * qcom_spl_get_iftbl_entry_by_name() - Get an interface table entry by name. - * @if_tbl: Pointer to the QCLIB interface table. - * @name: Name of the entry to find. - * @entry: Pointer to a buffer where the found entry will be copied. - * - * Return: 0 on success, or a negative error code on failure. - */ -static int qcom_spl_get_iftbl_entry_by_name(struct interface_table *if_tbl, - char *name, - struct interface_table_entry *entry) -{ - uint uc_index; - - if (!if_tbl) { - pr_err("Invalid interface table\n"); - return -EINVAL; - } - if (!name) { - pr_err("Invalid name\n"); - return -EINVAL; - } - if (!entry) { - pr_err("Invalid entry pointer\n"); - return -EINVAL; - } - - for (uc_index = 0; uc_index < if_tbl->num_entries; uc_index++) { - if (!strcmp(if_tbl->if_table_entries[uc_index].entry_name, name)) { - memcpy(entry, - &if_tbl->if_table_entries[uc_index], - sizeof(struct interface_table_entry)); - return 0; - } - } - pr_err("Interface table entry '%s' not found\n", name); - - return -ENOENT; -} - -/** - * qclib_post_process_from_spl() - Post-process QCLIB image from SPL FIT address - * - * This function performs the same operations as qclib_post_process() but - * takes no arguments. It gets the FIT image from CONFIG_SPL_LOAD_FIT_ADDRESS - * and finds the qcom-lib-1 node automatically. - * - * Return: 0 on success, or a negative error code on failure. - */ -int qclib_post_process_from_spl(void) -{ - int ret; - int entry_idx; - int images_node; - int qcconfig_node; - int qclib_node; - const void *fit; - struct interface_table if_tbl; - struct interface_table_entry qcsdi_entry; - qcom_spl_jump_img_entry_t qclib_entry; - u64 entry_point; - - /* Get FIT image from SPL load address */ - fit = (const void *)CONFIG_SPL_LOAD_FIT_ADDRESS; - - pr_debug("QCLIB post-processing from SPL: fit=%p\n", fit); - - /* - * Find "images" node in FIT (get it once and reuse) - */ - images_node = fdt_subnode_offset(fit, 0, "images"); - if (images_node < 0) { - pr_err("Failed to find images node in FIT\n"); - return -ENOENT; - } - - /* - * Find "qcom-config-1" image node - */ - qcconfig_node = fdt_subnode_offset(fit, images_node, "qcom-config-1"); - if (qcconfig_node < 0) { - pr_err("Failed to find qcom-config-1 node in FIT\n"); - return -ENOENT; - } - - /* - * Find "qcom-lib-1" image node - */ - qclib_node = fdt_subnode_offset(fit, images_node, "qcom-lib-1"); - if (qclib_node < 0) { - pr_err("Failed to find qcom-lib-1 node in FIT\n"); - return -ENOENT; - } - - /* - * Initialize the local interface table - */ - memset(&if_tbl, 0, sizeof(struct interface_table)); - memcpy(if_tbl.magic_key, MAGIC_KEY, strlen(MAGIC_KEY)); - - if_tbl.version = IF_TABLE_VERSION; - if_tbl.num_entries = 0; - if_tbl.max_entries = MAX_ENTRIES; - - /* - * Add QCCONFIG entry to the interface table - */ - entry_idx = 0; - memcpy(if_tbl.if_table_entries[entry_idx].entry_name, - QCCONFIG, strlen(QCCONFIG)); - - ret = qcom_spl_get_fit_img_entry_point((void *)fit, - qcconfig_node, - &if_tbl.if_table_entries[entry_idx].address); - if (ret) { - pr_err("Failed to get qcom-config-1 entry point (%d)\n", ret); - return ret; - } - if_tbl.if_table_entries[entry_idx].attributes = 0; - if_tbl.num_entries = entry_idx + 1; - - /* - * Add QCSDI entry to the interface table - */ - entry_idx++; - memcpy(if_tbl.if_table_entries[entry_idx].entry_name, - QCSDI, strlen(QCSDI)); - - if_tbl.if_table_entries[entry_idx].address = 0; - if_tbl.if_table_entries[entry_idx].attributes = 0; - if_tbl.num_entries = entry_idx + 1; - - /* - * Get qcom-lib-1 entry point - */ - ret = qcom_spl_get_fit_img_entry_point((void *)fit, - qclib_node, - &entry_point); - if (ret) { - pr_err("Failed to get qcom-lib-1 entry point (%d)\n", ret); - return ret; - } - - qclib_entry = (qcom_spl_jump_img_entry_t)entry_point; - - pr_info("Jumping to qcom-lib-1 at 0x%llx\n", entry_point); - qclib_entry(&if_tbl, NULL); - - /* Parse the interface table to extract QCSDI address */ - ret = qcom_spl_get_iftbl_entry_by_name(&if_tbl, QCSDI, &qcsdi_entry); - if (ret) { - pr_err("Failed to get QCSDI entry from interface table (%d)\n", ret); - return ret; - } - - g_qcsdi_address = qcsdi_entry.address; - pr_info("QCSDI address: 0x%llx\n", g_qcsdi_address); - - return 0; -} - -#if IS_ENABLED(CONFIG_SPL_SMEM) -/** - * spl_board_prepare_for_boot() - Prepare board for boot - * - * This function is called by SPL before jumping to the next stage. - * It populates SMEM during coldboot. - */ -void spl_board_prepare_for_boot(void) -{ - int ret; - - /* - * Populate SMEM in coldboot (Dload bit not set) - */ - if (!QCOM_SPL_IS_DLOAD_BIT_SET) { - ret = qcom_spl_populate_smem(NULL); - if (ret) { - pr_err("Failed to populate SMEM (%d)\n", ret); - qcom_spl_error_handler(NULL); - } - } -} -#endif /* IS_ENABLED(CONFIG_SPL_SMEM) */ - -/** - * spl_get_load_buffer() - Allocate a cache-aligned buffer for image loading. - * @offset: Offset (unused, typically 0 for SPL). - * @size: Size of the buffer to allocate. - * - * Return: Pointer to the allocated buffer, or NULL on failure. - */ -struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) -{ - return (void *)(CONFIG_SPL_LOAD_FIT_ADDRESS); -} - -/** - * board_spl_fit_buffer_addr() - Get the address of the FIT image buffer. - * @fit_size: Size of the FIT image. - * @sectors: Number of sectors. - * @bl_len: Block length. - * - * Return: Address of the FIT image buffer. - */ -void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len) -{ - return spl_get_load_buffer(0, sectors * bl_len); -} - -/** - * bl2_plat_get_bl31_params_v2() - Retrieve and fixup BL31 parameters. - * @bl32_entry: Entry point for BL32 (OP-TEE). - * @bl33_entry: Entry point for BL33 (U-Boot/kernel). - * @fdt_addr: Address of the Device Tree Blob (FDT). - * - * Return: Pointer to the populated BL31 parameters structure. - */ -struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry, - uintptr_t bl33_entry, - uintptr_t fdt_addr) -{ - struct bl_params *bl_params; - struct bl_params_node *node; - - /* - * Populate the bl31 params with default values. - */ - bl_params = bl2_plat_get_bl31_params_v2_default(bl32_entry, bl33_entry, - fdt_addr); - - /* - * Fixup the bl31 params based on platform requirements. - */ - for_each_bl_params_node(bl_params, node) { - if (node->image_id == ATF_BL31_IMAGE_ID) { - /* - * Pass QCSDI address to BL31 via arg0 - * This address was populated by qclib_post_process() - */ - if (g_qcsdi_address == 0) - pr_warn("QCSDI address not set, BL31 may not function correctly\n"); - - node->ep_info->args.arg0 = g_qcsdi_address; - pr_debug("Setting BL31 arg0 to QCSDI address: 0x%llx\n", g_qcsdi_address); - } - } - - return bl_params; -} - -/** - * qcom_spl_loader_pre_ddr() - SPL loader for pre-DDR stage. - * @boot_device: Type of boot device. - * - * Return: 0 on success, or a negative error code on failure. - */ -static int qcom_spl_loader_pre_ddr(u8 boot_device) -{ - struct spl_image_loader *loader, *drv; - struct spl_image_info spl_image = { 0 }; - struct spl_boot_device boot_dev = { .boot_device = boot_device, }; - int ret = -ENODEV, n_ents; - - drv = ll_entry_start(struct spl_image_loader, spl_image_loader); - n_ents = ll_entry_count(struct spl_image_loader, spl_image_loader); - - for (loader = drv; loader && (loader != drv + n_ents); loader++) { - if (boot_device != loader->boot_device) - continue; - - ret = loader->load_image(&spl_image, &boot_dev); - if (!ret) - break; - - printf("%s: Error: %d\n", __func__, ret); - } - - return ret; -} - -#if CONFIG_IS_ENABLED(MMC) -/** - * spl_find_partition_info() - Find partition information by name - * @uclass_id: Device class ID (UCLASS_MMC) - * @device_num: Device number within the class - * @part_name: Name of the partition to find - * @info: Pointer to store partition information - * - * This function provides partition lookup logic for MMC. - * Return: Partition number on success, negative error code on failure - */ -static int spl_find_partition_info(enum uclass_id uclass_id, int device_num, - const char *part_name, - struct disk_partition *info) -{ - int ret; - struct blk_desc *desc; - - if (!part_name || !info) { - printf("Invalid parameters for partition lookup\n"); - return -EINVAL; - } - - /* - * Get block device descriptor - */ - desc = blk_get_devnum_by_uclass_id(uclass_id, device_num); - if (!desc) { - printf("Block device not found for class %d, device %d\n", - uclass_id, device_num); - return -ENODEV; - } - - /* - * Initialize partition table if needed - */ - if (desc->part_type == PART_TYPE_UNKNOWN) { - printf("Initializing partition table\n"); - /* - * Prefer EFI/GPT - */ - desc->part_type = PART_TYPE_EFI; - } - - /* - * Find partition by name - */ - ret = part_get_info_by_name(desc, part_name, info); - if (ret < 0) { - printf("Partition '%s' not found\n", part_name); - return -ENOENT; - } - - printf("Found partition '%s' at partition number %d\n", part_name, ret); - return ret; -} - -/** - * spl_mmc_boot_mode() - Determine the boot mode for MMC - * @mmc: Pointer to the MMC device - * @boot_device: Boot device ID - * - * Return: MMCSD_MODE_RAW to use raw partition access - */ -u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) -{ - return MMCSD_MODE_RAW; -} - -/** - * spl_mmc_boot_partition() - Determine which partition to boot from - * @boot_device: Boot device ID - * - * Return: Partition number to boot from, or default partition on error - */ -int spl_mmc_boot_partition(const u32 boot_device) -{ - int ret; - struct disk_partition info; - - /* - * Use common partition lookup function - */ - ret = spl_find_partition_info(UCLASS_MMC, 0, QCOM_SPL_FIT_IMG_PARTITION, &info); - if (ret < 0) { - printf("Using default MMC partition %d\n", - CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); - return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION; - } - - return ret; -} - -/** - * spl_mmc_get_uboot_raw_sector() - Find the raw sector offset - * @mmc: Pointer to the MMC device - * @raw_sect: Sector - * - * Return: 0 if the image is at the starting of the partition without any offset. - */ -unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, ulong raw_sect) -{ - return 0; -} -#endif /* CONFIG_IS_ENABLED(MMC) */ - -static struct pbl_shared_data g_psd __section(".data"); - -void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3) -{ - unsigned long sctlr; - struct pbl_shared_data *psd; - - sctlr = get_sctlr(); - set_sctlr(sctlr & ~(CR_M)); /* Disable MMU */ - - psd = (struct pbl_shared_data *)r0; - - if (!psd || psd->num_of_entries < PBL_SHARED_DATA_PARAM_MAX) - goto out; - - memcpy(&g_psd, psd, sizeof(g_psd)); - -out: - save_boot_params_ret(); -} - -/** - * spl_boot_device() - Determine the boot device. - * - * Return: The mapped boot device type, - * or BOOT_DEVICE_NONE if the device is invalid. - */ -u32 spl_boot_device(void) -{ - struct pbl_shared_data *psd = &g_psd; - -#ifdef DEBUG - for (int i = 0; psd && i < psd->num_of_entries; i++) { - printf("entry[0x%x] = %d 0x%08x %d\n", i, - psd->entry[i].param_id, psd->entry[i].value, - psd->entry[i].valid); - } -#endif - - if (psd->entry[PSD_ID_IS_EDL_MODE].valid && - psd->entry[PSD_ID_IS_EDL_MODE].value) { - printf("Selected boot device: DFU\n"); - return BOOT_DEVICE_DFU; - } - - if (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].valid) { - switch (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].value) { - case PSD_MMC_FLASH: - printf("Selected boot device: MMC\n"); - return BOOT_DEVICE_MMC1; - case PSD_NOR_FLASH: - printf("Selected boot device: NOR\n"); - return BOOT_DEVICE_NOR; - case PSD_NAND_FLASH: - printf("Selected boot device: NAND\n"); - return BOOT_DEVICE_NAND; - case PSD_UFS_FLASH: - printf("Selected boot device: UFS\n"); - return BOOT_DEVICE_UFS; - } - } - - pr_err("No boot device configured\n"); - return BOOT_DEVICE_NONE; -} - -#if defined(CONFIG_SPL_BUILD) -/** - * board_init_f() - Main entry point for SPL. - * @dummy: Dummy argument (unused). - */ -void board_init_f(ulong dummy) -{ - int ret; - - memset(__bss_start, 0, __bss_end - __bss_start); /* Clear BSS */ - - qcom_spl_malloc_init_f(); - - ret = spl_early_init(); - if (ret) { - pr_debug("spl_early_init() failed (%d)\n", ret); - goto fail; - } - - preloader_console_init(); - - ret = qcom_spl_loader_pre_ddr(spl_boot_device()); - if (ret) { - pr_debug("qcom_spl_loader_pre_ddr() failed (%d)\n", ret); - goto fail; - } - - ret = qclib_post_process_from_spl(); - if (ret) { - pr_debug("qclib_post_process_from_spl() failed (%d)\n", ret); - goto fail; - } - - board_init_r(NULL, 0); - -fail: - if (ret) - qcom_spl_error_handler(NULL); -} -#endif /* CONFIG_SPL_BUILD */ - -int board_fit_config_name_match(const char *name) -{ - /* - * SPL loads the pre-HLOS images from bootldr FIT image - * as below - * - * In board_init_f() - Matches "pre-ddr" configuration node and - * load the images mentioned in its - * - * In board_init_r() - Matches "post-ddr" configuration node and - * load the images mentioned in its - * - */ - if (!(gd->flags & GD_FLG_SPL_INIT)) { - if (!strcmp(name, "pre-ddr")) { - printf("Selected FIT Config: %s\n", name); - return 0; - } - } else { - if (!strcmp(name, "post-ddr")) { - printf("Selected FIT Config: %s\n", name); - return 0; - } - } - - return -EINVAL; -} - -int board_fdt_blob_setup(void **fdtp) -{ - return 0; -} - -void reset_cpu(void) -{ - /* - * Empty placeholder for arch/arm/lib/reset.c:do_reset(), - * to avoid "undefined reference to `reset_cpu'" - */ -} diff --git a/common/spl/Kconfig b/common/spl/Kconfig index f3dfd029ab55..93e69f6d7c48 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1387,14 +1387,6 @@ config SPL_RAM_DEVICE be already in memory when SPL takes over, e.g. loaded by the boot ROM. -config SPL_SMEM - bool "Support SMEM (Shared Memory manager)" - depends on SMEM - help - Enable support for the Shared Memory Manager. The driver provides an - interface to items in a heap shared among all processors. This enables - the drivers in drivers/smem as part of an SPL build. - config SPL_PCI_DFU bool "PCIe boot support" depends on SPL_PCI_ENDPOINT diff --git a/configs/qcom_ipq5210_mmc_defconfig b/configs/qcom_ipq5210_mmc_defconfig deleted file mode 100644 index e903daa581cc..000000000000 --- a/configs/qcom_ipq5210_mmc_defconfig +++ /dev/null @@ -1,106 +0,0 @@ -CONFIG_ARM=y -CONFIG_SKIP_LOWLEVEL_INIT=y -CONFIG_POSITION_INDEPENDENT=y -CONFIG_SYS_INIT_SP_BSS_OFFSET=0x180000 -CONFIG_ARCH_SNAPDRAGON=y -CONFIG_TEXT_BASE=0x87980000 -CONFIG_NR_DRAM_BANKS=2 -CONFIG_ENV_SIZE=0x40000 -CONFIG_ENV_OFFSET=0 -CONFIG_DEFAULT_DEVICE_TREE="qcom/ipq5210-rdp504" -CONFIG_SYS_LOAD_ADDR=0x90000000 -CONFIG_REMAKE_ELF=y -CONFIG_FIT=y -CONFIG_FIT_VERBOSE=y -# CONFIG_BOOTSTD is not set -CONFIG_OF_BOARD_SETUP=y -CONFIG_USE_PREBOOT=y -CONFIG_SYS_PBSIZE=1024 -# CONFIG_DISPLAY_CPUINFO is not set -CONFIG_DISPLAY_BOARDINFO_LATE=y -CONFIG_HUSH_PARSER=y -CONFIG_CMD_MMC=y -CONFIG_CMD_PART=y -CONFIG_EFI_PARTITION=y -CONFIG_OF_LIVE=y -CONFIG_ENV_IS_IN_MMC=y -CONFIG_CLK=y -CONFIG_CLK_QCOM_IPQ5210=y -CONFIG_MSM_GPIO=y -# CONFIG_I2C is not set -# CONFIG_INPUT is not set -CONFIG_MISC=y -CONFIG_QCOM_GENI=y -CONFIG_QCOM_GENI_MINICORE=y -CONFIG_MMC_HS200_SUPPORT=y -CONFIG_MMC_SDHCI=y -# CONFIG_MMC_SDHCI_ADMA_HELPERS is not set -# CONFIG_MMC_SDHCI_ADMA is not set -# CONFIG_MMC_SDHCI_ADMA_FORCE_32BIT is not set -# CONFIG_MMC_SDHCI_ADMA_64BIT is not set -CONFIG_MMC_SDHCI_MSM=y -CONFIG_MTD=y -CONFIG_DM_MDIO=y -CONFIG_DM_ETH_PHY=y -CONFIG_DWC_ETH_QOS=y -CONFIG_DWC_ETH_QOS_QCOM=y -CONFIG_RGMII=y -CONFIG_PHY=y -CONFIG_PHY_QCOM_QMP_UFS=y -CONFIG_PHY_QCOM_QUSB2=y -CONFIG_PINCTRL=y -CONFIG_PINCONF=y -CONFIG_PINCTRL_QCOM_IPQ5210=y -CONFIG_DEBUG_UART_MSM_GENI=y -CONFIG_DEBUG_UART_ANNOUNCE=y -CONFIG_MSM_SERIAL=y -CONFIG_MSM_GENI_SERIAL=y -CONFIG_SOC_QCOM=y -CONFIG_SPL=y -CONFIG_SPL_FRAMEWORK=y -CONFIG_SPL_OF_CONTROL=y -CONFIG_SPL_LIBGENERIC_SUPPORT=y -CONFIG_SPL_LIBCOMMON_SUPPORT=y -CONFIG_SPL_OF_LIBFDT=y -CONFIG_SPL_DM=y -CONFIG_SPL_GPIO=y -CONFIG_SPL_DM_GPIO=y -CONFIG_SPL_DM_RESET=y -CONFIG_SPL_PINCTRL=y -CONFIG_SPL_CLK=y -CONFIG_SPL_DRIVERS_MISC=y -CONFIG_SPL_DRIVERS_MISC_SUPPORT=y -CONFIG_SPL_SERIAL=y -CONFIG_SPL_SMEM=y -CONFIG_DM_STATS=y -CONFIG_SPL_SYS_MALLOC_F=y -CONFIG_SPL_SYS_MALLOC_F_LEN=0x20000 -CONFIG_SPL_SYS_MALLOC=y -CONFIG_SYS_MALLOC_DEFAULT_TO_INIT=y -CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y -CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x80008000 -CONFIG_SPL_SYS_MALLOC_SIZE=0x20000 -# CONFIG_SPL_SEPARATE_BSS is not set -# CONFIG_SPL_USE_TINY_PRINTF is not set -CONFIG_SPL_BSS_MAX_SIZE=0x4000 -CONFIG_SPL_TEXT_BASE=0x08c24000 -CONFIG_SPL_MAX_SIZE=0x3D000 -CONFIG_SPL_MMC=y -CONFIG_SPL_MMC_SDHCI_ADMA=y -CONFIG_SPL_MMC_WRITE=y -CONFIG_SPL_SYS_MMCSD_RAW_MODE=y -CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y -CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x00 -CONFIG_COUNTER_FREQUENCY=24000000 -CONFIG_SPL_STACKPROTECTOR=y -CONFIG_SPL_LOAD_FIT=y -CONFIG_SPL_ATF=y -CONFIG_SPL_ATF_LOAD_IMAGE_V2=y -CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y -CONFIG_SPL_HAS_LOAD_FIT_ADDRESS=y -CONFIG_SPL_LOAD_FIT_ADDRESS=0x08cbe000 -# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set -CONFIG_SPL_HAVE_INIT_STACK=y -CONFIG_SPL_STACK=0x08c24000 -# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set -CONFIG_SPL_WRAPPER_ELF=y diff --git a/doc/board/qualcomm/rdp.rst b/doc/board/qualcomm/rdp.rst index 354dc9d06e11..99cf8eba57ce 100644 --- a/doc/board/qualcomm/rdp.rst +++ b/doc/board/qualcomm/rdp.rst @@ -42,98 +42,17 @@ on your device with:: U-Boot should be running after a reboot (``reset``). -Build steps for IPQ5210 based Qualcomm Dragonwing F8 & N8 Platforms: --------------------------------------------------------------------- - -Please refer to the following URLs for more details about the platforms. - - F8: https://www.qualcomm.com/networking-infrastructure/products/f-series/f8-platform - - N8: https://www.qualcomm.com/networking-infrastructure/products/n-series/n8-platform - -1. Since U-Boot SPL is enabled on these platforms, the build command generates - both the U-Boot SPL and U-Boot proper images. Assuming ${uboot_dir} is the - top of the U-Boot sources and ${out_dir} as the output directory, - - $ cd ${uboot_dir} - $ export CROSS_COMPILE= - $ make -j8 O=${out_dir} qcom_ipq5210_mmc_defconfig - $ make -j8 O=${out_dir} - - U-Boot SPL image: ${out_dir}/spl/u-boot-spl.wrap-elf - U-Boot image: ${out_dir}/u-boot.elf - -2. Convert the SPL image to multi ELF - - $ cd ${out_dir}/spl - $ python elftombn.py -f u-boot-spl.wrap-elf -o u-boot-spl.mbn -v7 - $ python `create_multielf.py` -f u-boot-spl.mbn,tmel-ipq52xx-patch.elf \ - -o u-boot-spl.melf - - This u-boot-spl.melf should be flashed into 0:SPL partition. - Please see below for the location of `tmel-ipq52xx-patch.elf` - -3. Convert the U-Boot image to bootloader image - - $ cd ${out_dir} - $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v7 - - The u-boot.mbn has to be combined with `qc_config.elf`, `QCLib.elf`, `TFA` - and `OPTEE`. Please see below for the location for these ELFs. TFA and OPTEE - can be built from the sources using the following commands - - TFA: - $ make PLAT=ipq52xx QTISECLIB_PATH=path/to/`libqtisec_dbg.a` SPD=opteed - - OPTEE: - $ make PLATFORM=qcom-ipq52xx -j16 - - These binaries can be combined into a flashable image using binman. - - Assuming all the required binaries are available in ${uboot_dir}/binman - - $ export bm=${uboot_dir}/binman - $ cd ${bm} - $ ${uboot_dir}/tools/binman/binman \ - --toolpath ${uboot_dir}/tools build \ - -u \ - -d ${out_dir}/u-boot.dtb \ - -O ${bm}.out \ - -I ${uboot_dir} \ - -I ${bm} \ - -I ${uboot_dir}/board \ - -I ${out_dir}/dts/upstream/src/arm64 \ - -a of-list="qcom/ipq5210-rdp504" \ - -a atf-bl31-path=${bm}/bl31.mbn \ - -a tee-os-path=${bm}/tee-pager_v2.mbn \ - -a qcom-config-path=${bm}/qc_config.elf \ - -a qcom-lib-path=${bm}/QCLib.elf \ - -a qcom-appsbl-path=${out_dir}/u-boot.mbn \ - -a default-dt="qcom/ipq5210-rdp504" \ - -a spl-bss-pad=1 \ - -a spl-dtb=y \ - -a of-spl-remove-props="interrupt-parent interrupts" - - This should be flashed into 0:BOOTLDR partition. - .. WARNING Boards with newer software versions would automatically go the emergency download (EDL) mode if U-Boot is not functioning as expected. If its a runtime failure at Uboot, the system will get reset (due to watchdog) and XBL will try to boot from next bank and if Bank B also doesn't have a functional image and is not booting fine, then the system will enter - EDL. A tool like bkerler's `edl` can be used for flashing with the + EDL. A tool like bkerler's `edl`_ can be used for flashing with the firehose loader binary appropriate for the board. Note that the support added is very basic. Restoring the original U-Boot on boards with older version of the software requires a debugger. -.. _create_multielf.py: https://raw.githubusercontent.com/coreboot/coreboot/refs/heads/main/util/qualcomm/create_multielf.py .. _elftombn.py: https://git.codelinaro.org/clo/qsdk/oss/system/tools/meta/-/tree/NHSS.QSDK.13.0.5.r2/scripts?ref_type=heads .. _edl: https://github.com/bkerler/edl -.. _libqtisec_dbg.a: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/WIN.TFA.1.0.R4/apss_proc/out/proprietary/qtiseclib/output/ipq52xx/release/libqtisec_dbg.a -.. _OPTEE: https://git.codelinaro.org/clo/trusted-firmware/optee_os/optee_os/-/tree/win.optee.1.0?ref_type=heads -.. _qc_config.elf: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/BOOT.MXF.2.3.1.1/boot_images/boot/QcomPkg/SocPkg/Hermosa/Bin/LC/RELEASE/qc_config.elf -.. _QCLib.elf: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/BOOT.MXF.2.3.1.1/boot_images/boot/QcomPkg/SocPkg/Hermosa/Bin/LC/RELEASE/QCLib.elf -.. _TFA: https://git.codelinaro.org/clo/trusted-firmware/tf-a/trusted-firmware-a/-/tree/win.tfa.1.0.r4?ref_type=heads -.. _tmel-ipq52xx-patch.elf: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/TMEL.WNS.2.4/tmel-ipq52xx-patch.elf diff --git a/drivers/Makefile b/drivers/Makefile index 6c1bdfefbea7..f694a18c0a43 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -74,7 +74,6 @@ obj-$(CONFIG_SPL_SATA) += ata/ scsi/ obj-$(CONFIG_SPL_LEGACY_BLOCK) += block/ obj-$(CONFIG_SPL_THERMAL) += thermal/ obj-$(CONFIG_SPL_UFS) += scsi/ ufs/ -obj-$(CONFIG_SPL_SMEM) += smem/ endif endif diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 6db258a29cec..c7fcc3fb1863 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -31,14 +31,6 @@ config CLK_QCOM_IPQ4019 on the Snapdragon IPQ4019 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. -config CLK_QCOM_IPQ5210 - bool "Qualcomm IPQ5210 GCC" - select CLK_QCOM - help - Say Y here to enable support for the Global Clock Controller - on the Qualcomm IPQ5210 SoC. This driver supports the clocks - and resets exposed by the GCC hardware block. - config CLK_QCOM_IPQ5424 bool "Qualcomm IPQ5424 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 4b4264aba9db..831f207fa4e9 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o -obj-$(CONFIG_CLK_QCOM_IPQ5210) += clock-ipq5210.o obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o obj-$(CONFIG_CLK_QCOM_MILOS) += clock-milos.o diff --git a/drivers/clk/qcom/clock-ipq5210.c b/drivers/clk/qcom/clock-ipq5210.c deleted file mode 100644 index 2e6037b64100..000000000000 --- a/drivers/clk/qcom/clock-ipq5210.c +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Clock drivers for Qualcomm IPQ5210 - * - * (C) Copyright 2024 Linaro Ltd. - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "clock-qcom.h" - -static ulong ipq5210_set_rate(struct clk *clk, ulong rate) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - /* - * Since GATE_CLK is deprecated and GATE_CLK_POLLED is being used - * use 'cbcr_reg' instead of 'reg'. - */ - switch (clk->id) { - case GCC_QUPV3_WRAP_SE1_CLK: - clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].cbcr_reg, - 0, 2, 217, CFG_CLK_SRC_GPLL0, 16); - break; - case GCC_SDCC1_AHB_CLK: - break; - case GCC_SDCC1_APPS_CLK: - clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].cbcr_reg, - 0, 6, 25, CFG_CLK_SRC_GPLL0, 16); - break; - default: - return -EINVAL; - } - - return rate; -} - -static const struct gate_clk ipq5210_clks[] = { - GATE_CLK_POLLED(GCC_QUPV3_WRAP_SE1_CLK, 0x05020, BIT(0), 0x05004), - GATE_CLK_POLLED(GCC_SDCC1_AHB_CLK, 0x3303c, BIT(0), 0x3303c), - GATE_CLK_POLLED(GCC_SDCC1_APPS_CLK, 0x3302c, BIT(0), 0x33004), - GATE_CLK_POLLED(GCC_IM_SLEEP_CLK, 0x34020, BIT(0), 0x34020), -}; - -static int ipq5210_enable(struct clk *clk) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - if (priv->data->num_clks <= clk->id) { - debug("%s: unknown clk id %lu\n", __func__, clk->id); - return -ENOENT; - } - - debug("%s: clk %s\n", __func__, ipq5210_clks[clk->id].name); - - return qcom_gate_clk_en(priv, clk->id); -} - -static const struct qcom_reset_map ipq5210_gcc_resets[] = { - [GCC_SDCC_BCR] = {0x33000, 0}, - [GCC_USB0_PHY_BCR] = {0x2c06c, 0}, - [GCC_USB3PHY_0_PHY_BCR] = {0x2c070, 0}, - [GCC_QUSB2_0_PHY_BCR] = {0x2c068, 0}, - [GCC_USB_BCR] = {0x2c000, 0}, -}; - -static struct msm_clk_data ipq5210_gcc_data = { - .resets = ipq5210_gcc_resets, - .num_resets = ARRAY_SIZE(ipq5210_gcc_resets), - .clks = ipq5210_clks, - .num_clks = ARRAY_SIZE(ipq5210_clks), - .enable = ipq5210_enable, - .set_rate = ipq5210_set_rate, -}; - -static const struct udevice_id gcc_ipq5210_of_match[] = { - { - .compatible = "qcom,ipq5210-gcc", - .data = (ulong)&ipq5210_gcc_data, - }, - { } -}; - -U_BOOT_DRIVER(gcc_ipq5210) = { - .name = "gcc_ipq5210", - .id = UCLASS_NOP, - .of_match = gcc_ipq5210_of_match, - .bind = qcom_cc_bind, - .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, -}; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 09ec40f25b0f..68a4c5d60766 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -120,12 +120,6 @@ config SPL_QCOM_GENI for providing a common interface for various peripherals like UART, I2C, SPI, etc. -config QCOM_GENI_MINICORE - bool "Support minicores in Qualcomm Generic Interface (GENI) driver" - depends on QCOM_GENI - help - Enable support for minicores in Qualcomm GENI and its peripherals. - config ROCKCHIP_EFUSE bool "Rockchip e-fuse support" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 70617bc22aa6..c1fb958261ed 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -67,7 +67,6 @@ obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif obj-$(CONFIG_QCOM_SPMI_SDAM) += qcom-spmi-sdam.o obj-$(CONFIG_$(PHASE_)QCOM_GENI) += qcom_geni.o -obj-$(CONFIG_QCOM_GENI_MINICORE) += qcom_geni-minicore.o obj-$(CONFIG_$(PHASE_)QCOM_HWINFO) += qcom_hwinfo.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o diff --git a/drivers/misc/qcom_geni-minicore.c b/drivers/misc/qcom_geni-minicore.c deleted file mode 100644 index 33bc61ddf350..000000000000 --- a/drivers/misc/qcom_geni-minicore.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include - -/* - * Register configuration for the QUP minicores to setup the corresponding - * functionality of SPI/I2C/UART. - */ -static u8 cfg_reg_idx[] = { - /* 0 to 18 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - /* 64 to 113 */ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, -}; - -static u32 spi_cfg_val[] = { - /* 0 to 18 */ - 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00240E78, 0x00011088, - 0x00240007, 0x00000000, 0x00000000, 0x0001000A, 0x00000300, 0x00000000, - 0x00000000, 0x00000000, 0x00154400, 0x001483A0, 0x00AA8128, 0x00641002, - 0x00004000, - /* 64 to 113 */ - 0x00000201, 0x0001FE05, 0x0002C2E7, 0x0A435C00, 0x0010011A, 0x08800000, - 0x00000000, 0x100CAC00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000018E4, 0x00000000, - 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0007F807, 0x000FFEFE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00200000, 0x00000004, 0x00000009, 0x0007F807, 0x000FFEFE, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00C0033F, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000055, -}; - -static u32 uart_cfg_val[] = { - /* 0 to 18 */ - 0x00000024, 0x00000000, 0x00000024, 0x00000000, 0x00019A00, 0x00400000, - 0x00E00000, 0x00010020, 0x00000000, 0x00000000, 0x00000300, 0x00000700, - 0x00000400, 0x00000000, 0x00000000, 0x00C00000, 0x00000000, 0x00C00024, - 0x00000B00, - /* 64 to 113 */ - 0x00020231, 0x0000CE05, 0x000360E7, 0x0941E6A8, 0x00100510, 0x42C01E51, - 0x00000401, 0x002E8400, 0x1694581A, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x0000031C, 0x00000000, - 0x0000000F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00081C06, 0x00004010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x0000000D, 0x00000000, 0x00081C06, 0x00004010, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00C02415, 0x0000000E, 0x00000001, - 0x00000001, 0x00000000, 0x00C00000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000055, -}; - -static u32 i2c_cfg_val[] = { - /* 0 to 18 */ - 0x00000090, 0x00000000, 0x00000090, 0x00000000, 0x00038028, 0x00084080, - 0x00000343, 0x00010000, 0x00000000, 0x00001A00, 0x00000100, 0x00000000, - 0x00000000, 0x00000000, 0x00808008, 0x001C0020, 0x00000000, 0x00020000, - 0x00000000, - /* 64 to 113 */ - 0x00000201, 0x0001FC01, 0x00036222, 0x09C01FFC, 0x00100120, 0x02C00000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000409, 0x00000003, - 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0007F8FE, 0x000FFEFE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000001, 0x0007F807, 0x000FFEFE, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00C00000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000055, -}; - -struct qup_mini_core_info qup_mini_cores[] = { - { - .serial_protocol = GENI_SE_SPI, - .fw_version = 0xb02, - .cfg_version = 0x9, - .cfg_count = ARRAY_SIZE(spi_cfg_val), - .cfg_val = spi_cfg_val, - .cfg_idx = cfg_reg_idx, - }, { - .serial_protocol = GENI_SE_UART, - .fw_version = 0x405, - .cfg_version = 0xa, - .cfg_count = ARRAY_SIZE(uart_cfg_val), - .cfg_val = uart_cfg_val, - .cfg_idx = cfg_reg_idx, - }, { - .serial_protocol = GENI_SE_I2C, - .fw_version = 0x204, - .cfg_version = 0x9, - .cfg_count = ARRAY_SIZE(i2c_cfg_val), - .cfg_val = i2c_cfg_val, - .cfg_idx = cfg_reg_idx, - }, { - .serial_protocol = GENI_SE_INVALID_PROTO, - }, -}; diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c index 40044e5d48a6..a62ae6a2478f 100644 --- a/drivers/misc/qcom_geni.c +++ b/drivers/misc/qcom_geni.c @@ -34,15 +34,8 @@ struct qup_se_rsc { struct geni_se_plat { bool need_firmware_load; -#if IS_ENABLED(CONFIG_QCOM_GENI_MINICORE) - bool is_mini_core; -#endif }; -#if IS_ENABLED(CONFIG_QCOM_GENI_MINICORE) -extern struct qup_mini_core_info qup_mini_cores[]; -#endif - /** * geni_enable_interrupts() Enable interrupts. * @rsc: Pointer to a structure representing SE-related resources. @@ -170,53 +163,16 @@ static void geni_config_common_control(struct qup_se_rsc *rsc) COMMON_CSR_SLV_CLK_CGC_ON_BMASK); } -static int load_se_firmware(struct qup_se_rsc *rsc, bool elf, void *info) +static int load_se_firmware(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr) { - struct elf_se_hdr *hdr, tmp_hdr; const u32 *fw_val_arr, *cfg_val_arr; const u8 *cfg_idx_arr; u32 i, reg_value, mask, ramn_cnt; int ret; - if (elf) { - hdr = info; - fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset); - cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset; - cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset); - } else if (IS_ENABLED(CONFIG_QCOM_GENI_MINICORE)) { - /* - * Minicore controllers come with pre-configured functionality - * and don't need a firmware download and just need the register - * configuration. Hence, skipping the firmware part and setting - * up just the register configuration related information. - */ - struct qup_mini_core_info *qmc = info; - - for (; qmc->serial_protocol != GENI_SE_INVALID_PROTO; qmc++) - if (qmc->serial_protocol == rsc->protocol) - break; - - if (qmc->serial_protocol == GENI_SE_INVALID_PROTO) { - dev_err(rsc->dev, "Invalid MINICORE protocol (%d)\n", - rsc->protocol); - return -EINVAL; - } - - tmp_hdr.magic = MAGIC_NUM_SE; - tmp_hdr.version = 1; - tmp_hdr.serial_protocol = rsc->protocol; - tmp_hdr.fw_version = qmc->fw_version; - tmp_hdr.cfg_version = qmc->cfg_version; - tmp_hdr.fw_size_in_items = qmc->cfg_ram_count; - tmp_hdr.cfg_size_in_items = qmc->cfg_count; - hdr = &tmp_hdr; - fw_val_arr = (const u32 *)qmc->cfg_ram; - cfg_idx_arr = (const u8 *)qmc->cfg_idx; - cfg_val_arr = (const u32 *)qmc->cfg_val; - } else { - dev_err(rsc->dev, "Neither fw nor register settings found\n"); - return -EINVAL; - } + fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset); + cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset; + cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset); geni_config_common_control(rsc); @@ -394,9 +350,8 @@ int qcom_geni_load_firmware(phys_addr_t qup_base, { struct qup_se_rsc rsc; struct elf_se_hdr *hdr; - bool elf; int ret; - void *fw, *info; + void *fw; rsc.dev = dev; rsc.base = qup_base; @@ -422,22 +377,15 @@ int qcom_geni_load_firmware(phys_addr_t qup_base, /* The firmware blob is the private data of the GENI wrapper (parent) */ fw = dev_get_priv(dev->parent); - if (IS_ELF(*(Elf32_Ehdr *)fw)) { - ret = read_elf(&rsc, fw, &hdr); - if (ret) { - dev_err(dev, "Failed to read ELF: %d\n", ret); - return ret; - } - elf = true; - info = hdr; - } else { - elf = false; - info = fw; + ret = read_elf(&rsc, fw, &hdr); + if (ret) { + dev_err(dev, "Failed to read ELF: %d\n", ret); + return ret; } dev_info(dev, "Loading QUP firmware...\n"); - return load_se_firmware(&rsc, elf, info); + return load_se_firmware(&rsc, hdr); } /* @@ -466,11 +414,6 @@ static int geni_se_of_to_plat(struct udevice *dev) if (proto == GENI_SE_INVALID_PROTO) plat->need_firmware_load = true; - -#if IS_ENABLED(CONFIG_QCOM_GENI_MINICORE) - if (readl(res.start + SE_HW_PARAM_2) & GENI_USE_MINICORES) - plat->is_mini_core = true; -#endif } return 0; @@ -530,7 +473,7 @@ static int probe_children_load_firmware(struct udevice *dev) ret = 0; /* Find the device for this ofnode, or bind it */ if (device_find_global_by_ofnode(child, &child_dev)) - ret = lists_bind_fdt(dev, child, &child_dev, NULL, false); + ret = lists_bind_fdt(dev, child, &child_dev, NULL, false); if (ret) { /* Skip nodes that don't have drivers */ debug("Failed to probe child %s: %d\n", ofnode_get_name(child), ret); @@ -549,7 +492,7 @@ static int probe_children_load_firmware(struct udevice *dev) * Load firmware for QCOM GENI peripherals from the dedicated partition on storage and bind/probe * all the peripheral devices that need firmware to be loaded. */ -int qcom_geni_fw_initialise(void) +static int qcom_geni_fw_initialise(void) { debug("Loading firmware for QCOM GENI SE\n"); struct udevice *geni_wrapper, *blk_dev; @@ -575,12 +518,6 @@ int qcom_geni_fw_initialise(void) return 0; } -#if IS_ENABLED(CONFIG_QCOM_GENI_MINICORE) - if (plat->is_mini_core) { - fw_buf = qup_mini_cores; - goto mini_core; - } -#endif ret = find_qupfw_part(&blk_dev, &part_info); if (ret) { pr_err("QUP firmware partition not found\n"); @@ -607,9 +544,6 @@ int qcom_geni_fw_initialise(void) return 0; } -#if IS_ENABLED(CONFIG_QCOM_GENI_MINICORE) -mini_core: -#endif /* * OK! Firmware is loaded, now bind and probe remaining children. They will attempt to load * firmware during probe. Do this for each GENI SE wrapper that needs firmware loading. @@ -629,14 +563,7 @@ int qcom_geni_fw_initialise(void) return 0; } -#if CONFIG_XPL_BUILD -int qcom_geni_fw_probe(struct udevice *dev) -{ - return qcom_geni_fw_initialise(); -} -#else EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qcom_geni_fw_initialise); -#endif static const struct udevice_id geni_ids[] = { { .compatible = "qcom,geni-se-qup" }, @@ -650,7 +577,4 @@ U_BOOT_DRIVER(geni_se_qup) = { .of_to_plat = geni_se_of_to_plat, .plat_auto = sizeof(struct geni_se_plat), .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF, -#if CONFIG_XPL_BUILD - .probe = qcom_geni_fw_probe, -#endif }; diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index ce69a1e73289..0ee100aad90f 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -76,14 +76,6 @@ config SPL_PINCTRL_QCOM_IPQ4019 SPL variant of PINCTRL_QCOM_IPQ4019. See the help of PINCTRL_QCOM_IPQ4019 for details. -config PINCTRL_QCOM_IPQ5210 - bool "Qualcomm IPQ5210 Pinctrl" - default y if PINCTRL_QCOM_GENERIC - select PINCTRL_QCOM - help - Say Y here to enable support for pinctrl on the IPQ5210 SoC, - as well as the associated GPIO driver. - config PINCTRL_QCOM_IPQ5424 bool "Qualcomm IPQ5424 Pinctrl" default y if PINCTRL_QCOM_GENERIC diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index a0781ab85290..8280f0b18bc0 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM) += pinctrl-qcom.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o -obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ5210) += pinctrl-ipq5210.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5210.c b/drivers/pinctrl/qcom/pinctrl-ipq5210.c deleted file mode 100644 index a9b435ad543a..000000000000 --- a/drivers/pinctrl/qcom/pinctrl-ipq5210.c +++ /dev/null @@ -1,349 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Qualcomm IPQ5210 pinctrl - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include - -#include "pinctrl-qcom.h" - -#define MAX_PIN_NAME_LEN 32 -static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); - -enum ipq5210_functions { - msm_mux_atest_char_start, - msm_mux_atest_char_status0, - msm_mux_atest_char_status1, - msm_mux_atest_char_status2, - msm_mux_atest_char_status3, - msm_mux_atest_tic_en, - msm_mux_audio_pri, - msm_mux_audio_pri_mclk_out0, - msm_mux_audio_pri_mclk_in0, - msm_mux_audio_pri_mclk_out1, - msm_mux_audio_pri_mclk_in1, - msm_mux_audio_pri_mclk_out2, - msm_mux_audio_pri_mclk_in2, - msm_mux_audio_pri_mclk_out3, - msm_mux_audio_pri_mclk_in3, - msm_mux_audio_sec, - msm_mux_audio_sec_mclk_out0, - msm_mux_audio_sec_mclk_in0, - msm_mux_audio_sec_mclk_out1, - msm_mux_audio_sec_mclk_in1, - msm_mux_audio_sec_mclk_out2, - msm_mux_audio_sec_mclk_in2, - msm_mux_audio_sec_mclk_out3, - msm_mux_audio_sec_mclk_in3, - msm_mux_core_voltage_0, - msm_mux_cri_trng0, - msm_mux_cri_trng1, - msm_mux_cri_trng2, - msm_mux_cri_trng3, - msm_mux_dbg_out_clk, - msm_mux_dg_out, - msm_mux_gcc_plltest_bypassnl, - msm_mux_gcc_plltest_resetn, - msm_mux_gcc_tlmm, - msm_mux_gpio, - msm_mux_led0, - msm_mux_led1, - msm_mux_led2, - msm_mux_mdc_mst, - msm_mux_mdc_slv0, - msm_mux_mdc_slv1, - msm_mux_mdc_slv2, - msm_mux_mdio_mst, - msm_mux_mdio_slv0, - msm_mux_mdio_slv1, - msm_mux_mdio_slv2, - msm_mux_mux_tod_out, - msm_mux_pcie0_clk_req_n, - msm_mux_pcie0_wake, - msm_mux_pcie1_clk_req_n, - msm_mux_pcie1_wake, - msm_mux_pll_test, - msm_mux_pon_active_led, - msm_mux_pon_mux_sel, - msm_mux_pon_rx, - msm_mux_pon_rx_los, - msm_mux_pon_tx, - msm_mux_pon_tx_burst, - msm_mux_pon_tx_dis, - msm_mux_pon_tx_fault, - msm_mux_pon_tx_sd, - msm_mux_gpn_rx_los, - msm_mux_gpn_tx_burst, - msm_mux_gpn_tx_dis, - msm_mux_gpn_tx_fault, - msm_mux_gpn_tx_sd, - msm_mux_pps, - msm_mux_pwm0, - msm_mux_pwm1, - msm_mux_pwm2, - msm_mux_pwm3, - msm_mux_qdss_cti_trig_in_a0, - msm_mux_qdss_cti_trig_in_a1, - msm_mux_qdss_cti_trig_in_b0, - msm_mux_qdss_cti_trig_in_b1, - msm_mux_qdss_cti_trig_out_a0, - msm_mux_qdss_cti_trig_out_a1, - msm_mux_qdss_cti_trig_out_b0, - msm_mux_qdss_cti_trig_out_b1, - msm_mux_qdss_traceclk_a, - msm_mux_qdss_tracectl_a, - msm_mux_qdss_tracedata_a, - msm_mux_qrng_rosc0, - msm_mux_qrng_rosc1, - msm_mux_qrng_rosc2, - msm_mux_qspi_data, - msm_mux_qspi_clk, - msm_mux_qspi_cs_n, - msm_mux_qup_se0, - msm_mux_qup_se1, - msm_mux_qup_se2, - msm_mux_qup_se3, - msm_mux_qup_se4, - msm_mux_qup_se5, - msm_mux_qup_se5_l1, - msm_mux_resout, - msm_mux_rx_los0, - msm_mux_rx_los1, - msm_mux_rx_los2, - msm_mux_sdc_clk, - msm_mux_sdc_cmd, - msm_mux_sdc_data, - msm_mux_tsens_max, - msm_mux__, -}; - -#define MSM_PIN_FUNCTION(fname) \ - [msm_mux_##fname] = {#fname, msm_mux_##fname} - -static const struct pinctrl_function msm_pinctrl_functions[] = { - MSM_PIN_FUNCTION(atest_char_start), - MSM_PIN_FUNCTION(atest_char_status0), - MSM_PIN_FUNCTION(atest_char_status1), - MSM_PIN_FUNCTION(atest_char_status2), - MSM_PIN_FUNCTION(atest_char_status3), - MSM_PIN_FUNCTION(atest_tic_en), - MSM_PIN_FUNCTION(audio_pri), - MSM_PIN_FUNCTION(audio_pri_mclk_out0), - MSM_PIN_FUNCTION(audio_pri_mclk_in0), - MSM_PIN_FUNCTION(audio_pri_mclk_out1), - MSM_PIN_FUNCTION(audio_pri_mclk_in1), - MSM_PIN_FUNCTION(audio_pri_mclk_out2), - MSM_PIN_FUNCTION(audio_pri_mclk_in2), - MSM_PIN_FUNCTION(audio_pri_mclk_out3), - MSM_PIN_FUNCTION(audio_pri_mclk_in3), - MSM_PIN_FUNCTION(audio_sec), - MSM_PIN_FUNCTION(audio_sec_mclk_out0), - MSM_PIN_FUNCTION(audio_sec_mclk_in0), - MSM_PIN_FUNCTION(audio_sec_mclk_out1), - MSM_PIN_FUNCTION(audio_sec_mclk_in1), - MSM_PIN_FUNCTION(audio_sec_mclk_out2), - MSM_PIN_FUNCTION(audio_sec_mclk_in2), - MSM_PIN_FUNCTION(audio_sec_mclk_out3), - MSM_PIN_FUNCTION(audio_sec_mclk_in3), - MSM_PIN_FUNCTION(core_voltage_0), - MSM_PIN_FUNCTION(cri_trng0), - MSM_PIN_FUNCTION(cri_trng1), - MSM_PIN_FUNCTION(cri_trng2), - MSM_PIN_FUNCTION(cri_trng3), - MSM_PIN_FUNCTION(dbg_out_clk), - MSM_PIN_FUNCTION(dg_out), - MSM_PIN_FUNCTION(gcc_plltest_bypassnl), - MSM_PIN_FUNCTION(gcc_plltest_resetn), - MSM_PIN_FUNCTION(gcc_tlmm), - MSM_PIN_FUNCTION(gpio), - MSM_PIN_FUNCTION(led0), - MSM_PIN_FUNCTION(led1), - MSM_PIN_FUNCTION(led2), - MSM_PIN_FUNCTION(mdc_mst), - MSM_PIN_FUNCTION(mdc_slv0), - MSM_PIN_FUNCTION(mdc_slv1), - MSM_PIN_FUNCTION(mdc_slv2), - MSM_PIN_FUNCTION(mdio_mst), - MSM_PIN_FUNCTION(mdio_slv0), - MSM_PIN_FUNCTION(mdio_slv1), - MSM_PIN_FUNCTION(mdio_slv2), - MSM_PIN_FUNCTION(mux_tod_out), - MSM_PIN_FUNCTION(pcie0_clk_req_n), - MSM_PIN_FUNCTION(pcie0_wake), - MSM_PIN_FUNCTION(pcie1_clk_req_n), - MSM_PIN_FUNCTION(pcie1_wake), - MSM_PIN_FUNCTION(pll_test), - MSM_PIN_FUNCTION(pon_active_led), - MSM_PIN_FUNCTION(pon_mux_sel), - MSM_PIN_FUNCTION(pon_rx), - MSM_PIN_FUNCTION(pon_rx_los), - MSM_PIN_FUNCTION(pon_tx), - MSM_PIN_FUNCTION(pon_tx_burst), - MSM_PIN_FUNCTION(pon_tx_dis), - MSM_PIN_FUNCTION(pon_tx_fault), - MSM_PIN_FUNCTION(pon_tx_sd), - MSM_PIN_FUNCTION(gpn_rx_los), - MSM_PIN_FUNCTION(gpn_tx_burst), - MSM_PIN_FUNCTION(gpn_tx_dis), - MSM_PIN_FUNCTION(gpn_tx_fault), - MSM_PIN_FUNCTION(gpn_tx_sd), - MSM_PIN_FUNCTION(pps), - MSM_PIN_FUNCTION(pwm0), - MSM_PIN_FUNCTION(pwm1), - MSM_PIN_FUNCTION(pwm2), - MSM_PIN_FUNCTION(pwm3), - MSM_PIN_FUNCTION(qdss_cti_trig_in_a0), - MSM_PIN_FUNCTION(qdss_cti_trig_in_a1), - MSM_PIN_FUNCTION(qdss_cti_trig_in_b0), - MSM_PIN_FUNCTION(qdss_cti_trig_in_b1), - MSM_PIN_FUNCTION(qdss_cti_trig_out_a0), - MSM_PIN_FUNCTION(qdss_cti_trig_out_a1), - MSM_PIN_FUNCTION(qdss_cti_trig_out_b0), - MSM_PIN_FUNCTION(qdss_cti_trig_out_b1), - MSM_PIN_FUNCTION(qdss_traceclk_a), - MSM_PIN_FUNCTION(qdss_tracectl_a), - MSM_PIN_FUNCTION(qdss_tracedata_a), - MSM_PIN_FUNCTION(qrng_rosc0), - MSM_PIN_FUNCTION(qrng_rosc1), - MSM_PIN_FUNCTION(qrng_rosc2), - MSM_PIN_FUNCTION(qspi_data), - MSM_PIN_FUNCTION(qspi_clk), - MSM_PIN_FUNCTION(qspi_cs_n), - MSM_PIN_FUNCTION(qup_se0), - MSM_PIN_FUNCTION(qup_se1), - MSM_PIN_FUNCTION(qup_se2), - MSM_PIN_FUNCTION(qup_se3), - MSM_PIN_FUNCTION(qup_se4), - MSM_PIN_FUNCTION(qup_se5), - MSM_PIN_FUNCTION(qup_se5_l1), - MSM_PIN_FUNCTION(resout), - MSM_PIN_FUNCTION(rx_los0), - MSM_PIN_FUNCTION(rx_los1), - MSM_PIN_FUNCTION(rx_los2), - MSM_PIN_FUNCTION(sdc_clk), - MSM_PIN_FUNCTION(sdc_cmd), - MSM_PIN_FUNCTION(sdc_data), - MSM_PIN_FUNCTION(tsens_max), -}; - -typedef unsigned int msm_pin_function[10]; - -#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ - [id] = { msm_mux_gpio, /* gpio mode */ \ - msm_mux_##f1, \ - msm_mux_##f2, \ - msm_mux_##f3, \ - msm_mux_##f4, \ - msm_mux_##f5, \ - msm_mux_##f6, \ - msm_mux_##f7, \ - msm_mux_##f8, \ - msm_mux_##f9, \ - } - -static const msm_pin_function ipq5210_pin_functions[] = { - PINGROUP(0, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), - PINGROUP(1, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), - PINGROUP(2, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), - PINGROUP(3, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), - PINGROUP(4, sdc_cmd, qspi_cs_n, _, _, _, _, _, _, _), - PINGROUP(5, sdc_clk, qspi_clk, _, _, _, _, _, _, _), - PINGROUP(6, qup_se0, led0, pwm1, _, cri_trng0, qdss_tracedata_a, _, _, _), - PINGROUP(7, qup_se0, led1, pwm1, _, cri_trng1, qdss_tracedata_a, _, _, _), - PINGROUP(8, qup_se0, pwm1, audio_pri_mclk_out2, audio_pri_mclk_in2, _, cri_trng2, qdss_tracedata_a, _, _), - PINGROUP(9, qup_se0, led2, pwm1, _, cri_trng3, qdss_tracedata_a, _, _, _), - PINGROUP(10, pon_rx_los, qup_se3, pwm0, _, _, qdss_tracedata_a, _, _, _), - PINGROUP(11, pon_active_led, qup_se3, pwm0, _, _, qdss_tracedata_a, _, _, _), - PINGROUP(12, pon_tx_dis, qup_se2, pwm0, audio_pri_mclk_out0, audio_pri_mclk_in0, _, qrng_rosc0, qdss_tracedata_a, _), - PINGROUP(13, gpn_tx_dis, qup_se2, pwm0, audio_pri_mclk_out3, audio_pri_mclk_in3, _, qrng_rosc1, qdss_tracedata_a, _), - PINGROUP(14, pon_tx_burst, qup_se0, _, qrng_rosc2, qdss_tracedata_a, _, _, _, _), - PINGROUP(15, pon_tx, qup_se0, _, qdss_tracedata_a, _, _, _, _, _), - PINGROUP(16, pon_tx_sd, audio_sec_mclk_out1, audio_sec_mclk_in1, qdss_cti_trig_out_b0, _, _, _, _, _), - PINGROUP(17, pon_tx_fault, audio_sec_mclk_out0, audio_sec_mclk_in0, _, _, _, _, _, _), - PINGROUP(18, pps, pll_test, _, _, _, _, _, _, _), - PINGROUP(19, mux_tod_out, audio_pri_mclk_out1, audio_pri_mclk_in1, _, _, _, _, _, _), - PINGROUP(20, qup_se2, mdc_slv1, tsens_max, qdss_tracedata_a, _, _, _, _, _), - PINGROUP(21, qup_se2, mdio_slv1, qdss_tracedata_a, _, _, _, _, _, _), - PINGROUP(22, core_voltage_0, qup_se3, pwm3, _, _, _, _, _, _), - PINGROUP(23, led0, qup_se3, dbg_out_clk, qdss_traceclk_a, _, _, _, _, _), - PINGROUP(24, _, _, _, _, _, _, _, _, _), - PINGROUP(25, _, _, _, _, _, _, _, _, _), - PINGROUP(26, mdc_mst, led2, _, qdss_tracectl_a, _, _, _, _, _), - PINGROUP(27, mdio_mst, led1, _, _, _, _, _, _, _), - PINGROUP(28, pcie1_clk_req_n, qup_se1, _, _, qdss_cti_trig_out_a0, _, _, _, _), - PINGROUP(29, _, _, _, _, _, _, _, _, _), - PINGROUP(30, pcie1_wake, qup_se1, _, _, qdss_cti_trig_in_a0, _, _, _, _), - PINGROUP(31, pcie0_clk_req_n, mdc_slv0, _, qdss_cti_trig_out_a1, _, _, _, _, _), - PINGROUP(32, _, _, _, _, _, _, _, _, _), - PINGROUP(33, pcie0_wake, mdio_slv0, qdss_cti_trig_in_a1, _, _, _, _, _, _), - PINGROUP(34, audio_pri, atest_char_status0, qdss_cti_trig_in_b0, _, _, _, _, _, _), - PINGROUP(35, audio_pri, rx_los2, atest_char_status1, qdss_cti_trig_out_b1, _, _, _, _, _), - PINGROUP(36, audio_pri, _, rx_los1, atest_char_status2, _, _, _, _, _), - PINGROUP(37, audio_pri, rx_los0, atest_char_status3, _, qdss_cti_trig_in_b1, _, _, _, _), - PINGROUP(38, qup_se1, led2, gcc_plltest_bypassnl, qdss_tracedata_a, _, _, _, _, _), - PINGROUP(39, qup_se1, led1, led0, gcc_tlmm, qdss_tracedata_a, _, _, _, _), - PINGROUP(40, qup_se4, rx_los2, audio_sec, gcc_plltest_resetn, qdss_tracedata_a, _, _, _, _), - PINGROUP(41, qup_se4, rx_los1, audio_sec, qdss_tracedata_a, _, _, _, _, _), - PINGROUP(42, qup_se4, rx_los0, audio_sec, atest_tic_en, _, _, _, _, _), - PINGROUP(43, qup_se4, audio_sec, _, _, _, _, _, _, _), - PINGROUP(44, resout, _, _, _, _, _, _, _, _), - PINGROUP(45, pon_mux_sel, _, _, _, _, _, _, _, _), - PINGROUP(46, dg_out, atest_char_start, _, _, _, _, _, _, _), - PINGROUP(47, gpn_rx_los, mdc_slv2, qup_se5, _, _, _, _, _, _), - PINGROUP(48, pon_rx, qup_se5, _, _, _, _, _, _, _), - PINGROUP(49, gpn_tx_fault, mdio_slv2, qup_se5, audio_sec_mclk_out2, audio_sec_mclk_in2, _, _, _, _), - PINGROUP(50, gpn_tx_sd, qup_se5, audio_sec_mclk_out3, audio_sec_mclk_in3, _, _, _, _, _), - PINGROUP(51, gpn_tx_burst, qup_se5, _, _, _, _, _, _, _), - PINGROUP(52, qup_se2, qup_se5, qup_se4, qup_se5_l1, _, _, _, _, _), - PINGROUP(53, qup_se2, qup_se4, qup_se5_l1, _, _, _, _, _, _), -}; - -static const char *ipq5210_get_function_name(struct udevice *dev, uint selector) -{ - return msm_pinctrl_functions[selector].name; -} - -static const char *ipq5210_get_pin_name(struct udevice *dev, uint selector) -{ - snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); - return pin_name; -} - -static int ipq5210_get_function_mux(unsigned int pin, uint selector) -{ - unsigned int i; - const msm_pin_function *func = ipq5210_pin_functions + pin; - - for (i = 0; i < 10; i++) - if ((*func)[i] == selector) - return i; - - pr_err("Can't find requested function for pin %u\n", pin); - return -EINVAL; -} - -static const struct msm_pinctrl_data ipq5210_data = { - .pin_data = { - .pin_count = 54, - .special_pins_start = 54, /* There are no special pins */ - }, - .functions_count = ARRAY_SIZE(msm_pinctrl_functions), - .get_function_name = ipq5210_get_function_name, - .get_function_mux = ipq5210_get_function_mux, - .get_pin_name = ipq5210_get_pin_name, -}; - -static const struct udevice_id msm_pinctrl_ids[] = { - { .compatible = "qcom,ipq5210-tlmm", .data = (ulong)&ipq5210_data }, - { /* Sentinal */ } -}; - -U_BOOT_DRIVER(pinctrl_ipq5210) = { - .name = "pinctrl_ipq5210", - .id = UCLASS_NOP, - .of_match = msm_pinctrl_ids, - .ops = &msm_pinctrl_ops, - .bind = msm_pinctrl_bind, - .flags = DM_FLAG_PRE_RELOC, -}; diff --git a/include/soc/qcom/geni-se.h b/include/soc/qcom/geni-se.h index 3063b37010de..fc9a8e82cd88 100644 --- a/include/soc/qcom/geni-se.h +++ b/include/soc/qcom/geni-se.h @@ -77,12 +77,8 @@ enum geni_se_protocol_type { #define SE_IRQ_EN 0xe1c #define SE_HW_PARAM_0 0xe24 #define SE_HW_PARAM_1 0xe28 -#define SE_HW_PARAM_2 0xe2c #define SE_DMA_GENERAL_CFG 0xe30 -/* SE_HW_PARAM_2 fields */ -#define GENI_USE_MINICORES BIT(12) - /* GENI_DFS_IF_CFG fields */ #define DFS_IF_EN BIT(0) @@ -252,7 +248,6 @@ enum geni_se_protocol_type { /* SE_HW_PARAM_0 fields */ #define TX_FIFO_WIDTH_MSK GENMASK(29, 24) #define TX_FIFO_WIDTH_SHFT 24 - /* * For QUP HW Version >= 3.10 Tx fifo depth support is increased * to 256bytes and corresponding bits are 16 to 23 diff --git a/include/soc/qcom/qup-fw-load.h b/include/soc/qcom/qup-fw-load.h index b329a18ef22c..a67a93c72a4b 100644 --- a/include/soc/qcom/qup-fw-load.h +++ b/include/soc/qcom/qup-fw-load.h @@ -14,7 +14,6 @@ #define GENI_INIT_CFG_REVISION 0x0 #define GENI_S_INIT_CFG_REVISION 0x4 #define GENI_FORCE_DEFAULT_REG 0x20 -#define GENI_OUTPUT_CTRL 0x24 #define GENI_CGC_CTRL 0x28 #define GENI_CFG_REG0 0x100 @@ -174,17 +173,6 @@ struct elf_se_hdr { struct udevice; -struct qup_mini_core_info { - u16 serial_protocol; - u16 fw_version; - u16 cfg_version; - u16 cfg_count; - u32 *cfg_val; - u8 *cfg_idx; - u32 *cfg_ram; - u32 cfg_ram_count; -}; - int qcom_geni_load_firmware(phys_addr_t qup_base, struct udevice *dev); #endif /* _LINUX_QCOM_QUP_FW_LOAD */ diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h index 9e50f3974a2e..586432412eb8 100644 --- a/include/soc/qcom/smem.h +++ b/include/soc/qcom/smem.h @@ -16,10 +16,6 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size); void *qcom_smem_get(unsigned host, unsigned item, size_t *size); int qcom_smem_get_free_space(unsigned host); - -#define SMEM_BOOT_FLASH_TYPE 498 -#define SMEM_BOOT_MMC_FLASH 5 - #else static int qcom_smem_init(void) { return -ENOSYS; } diff --git a/scripts/Makefile.xpl b/scripts/Makefile.xpl index 6e9f24b748a6..a3fd3e1375f7 100644 --- a/scripts/Makefile.xpl +++ b/scripts/Makefile.xpl @@ -256,26 +256,6 @@ MKIMAGEFLAGS_boot.bin = -T zynqmpimage -R $(srctree)/$(CONFIG_BOOT_INIT_FILE) \ -n "$(shell cd $(srctree); readlink -f $(CONFIG_PMUFW_INIT_FILE))" endif -ifeq ($(CONFIG_SPL_WRAPPER_ELF),y) -# Convert ELF to object file -OBJCOPYFLAGS_$(SPL_BIN).bin.o = -I binary -O elf64-littleaarch64 - -# Wrap the object file inside a ELF -QCOM_SPL_SOC = $(shell echo $(notdir "$(CONFIG_DEFAULT_DEVICE_TREE)") | cut -f1 -d-) -QCOM_SPL_WRAP_LDS = $(srctree)/arch/arm/mach-snapdragon/$(QCOM_SPL_SOC)-spl-wrap-elf.lds -LDFLAGS_$(SPL_BIN).wrap-elf = -T $(obj)/$(SPL_BIN).wrap-elf.lds - -$(obj)/$(SPL_BIN).wrap-elf.lds: $(QCOM_SPL_WRAP_LDS) FORCE - $(call if_changed_dep,cpp_lds) - -$(obj)/$(SPL_BIN).bin.o: $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).wrap-elf.lds FORCE - $(call if_changed,objcopy) - -$(obj)/$(SPL_BIN).wrap-elf: $(obj)/$(SPL_BIN).bin.o FORCE - $(call if_changed,ld) - -endif - $(obj)/$(SPL_BIN)-align.bin: $(obj)/$(SPL_BIN).bin @dd if=$< of=$@ conv=sync bs=4 2>/dev/null; @@ -322,10 +302,6 @@ INPUTS-$(CONFIG_ARCH_ZYNQMP) += $(obj)/boot.bin INPUTS-$(CONFIG_ARCH_MEDIATEK) += $(obj)/u-boot-spl-mtk.bin -ifeq ($(CONFIG_ARCH_SNAPDRAGON),y) -INPUTS-$(CONFIG_SPL_WRAPPER_ELF) += $(obj)/u-boot-spl.wrap-elf -endif - all: $(INPUTS-y) quiet_cmd_cat = CAT $@ diff --git a/tools/binman/elf.py b/tools/binman/elf.py index b43cf490b377..6ac960e04196 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -551,7 +551,6 @@ def read_loadable_segments(data): raise ValueError(err) entry = elf.header['e_entry'] segments = [] - n = 0 for i in range(elf.num_segments()): segment = elf.get_segment(i) if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']: @@ -559,8 +558,7 @@ def read_loadable_segments(data): continue start = segment['p_offset'] rend = start + segment['p_filesz'] - segments.append((n, segment['p_paddr'], data[start:rend])) - n = n + 1 + segments.append((i, segment['p_paddr'], data[start:rend])) return segments, entry def is_valid(data): diff --git a/tools/binman/etype/qcom_appsbl.py b/tools/binman/etype/qcom_appsbl.py deleted file mode 100644 index e308ebd2fca3..000000000000 --- a/tools/binman/etype/qcom_appsbl.py +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# -# Entry-type module for U-Boot MBN image -# - -from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg - -class Entry_qcom_appsbl(Entry_blob_named_by_arg): - """U-Boot mbn image - - Properties / Entry arguments: - - filename: Filename of u-boot MBN (default 'u-boot.mbn') - - This is the U-Boot MBN image. - """ - def __init__(self, section, etype, node): - super().__init__(section, etype, node, 'qcom-appsbl') diff --git a/tools/binman/etype/qcom_config.py b/tools/binman/etype/qcom_config.py deleted file mode 100644 index a1787c97b34e..000000000000 --- a/tools/binman/etype/qcom_config.py +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# -# Entry-type module for QC Config ELF -# - -from binman.entry import Entry -from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg - -class Entry_qcom_config(Entry_blob_named_by_arg): - """QC Config ELF - - Properties / Entry arguments: - - qcom-config-path: Filename of QC Config ELF (typically 'qcconfig.elf') - - This will be part of the Qualcomm SPL based bootloader image - - """ - def __init__(self, section, etype, node): - super().__init__(section, etype, node, 'qcom-config') - self.external = True diff --git a/tools/binman/etype/qcom_lib.py b/tools/binman/etype/qcom_lib.py deleted file mode 100644 index ca7666fe6e63..000000000000 --- a/tools/binman/etype/qcom_lib.py +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# -# Entry-type module for QC LIB ELF -# - -from binman.entry import Entry -from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg - -class Entry_qcom_lib(Entry_blob_named_by_arg): - """QC LIB ELF - - Properties / Entry arguments: - - qcom-lib-path: Filename of QC LIB ELF (typically 'QCLib.elf') - - This will be part of the Qualcomm SPL based bootloader image - - """ - def __init__(self, section, etype, node): - super().__init__(section, etype, node, 'qcom-lib') - self.external = True From 9bc36deeb025a956ae30a99f650963ce026284be Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:43 +0200 Subject: [PATCH 08/52] config.mk: support vendor generic includes Currently only board/vendor/$(BOARD)/config.mk is supported, add the additional usecase of having a vendor generic config.mk for adding functionality like platform-specific build targets. Additionally, fix the ifdef to correctly check for $(BOARDDIR) rather than $(BOARD) since that's what is actually used in the include path. Reviewed-by: Tom Rini Link: https://patch.msgid.link/20260511-b4-qcom-tooling-improvements-v7-1-0c06346e79a9@linaro.org Signed-off-by: Casey Connolly --- config.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/config.mk b/config.mk index abed9cb65c6f..22c21c0d3b2d 100644 --- a/config.mk +++ b/config.mk @@ -47,7 +47,7 @@ ifdef SOC sinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk # include SoC specific rules endif ifneq ($(BOARD),) -ifdef VENDOR +ifneq ($(VENDOR),) BOARDDIR = $(VENDOR)/$(BOARD) ENVDIR=${vendor}/env else @@ -55,7 +55,11 @@ BOARDDIR = $(BOARD) ENVDIR=${board}/env endif endif -ifdef BOARD + +ifneq ($(VENDOR),) +sinclude $(srctree)/board/$(VENDOR)/config.mk # include vendor specific rules +endif +ifdef BOARDDIR sinclude $(srctree)/board/$(BOARDDIR)/config.mk # include board specific rules endif From 198dbccdafcf07a220a42825e79ad6e2eef03127 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:44 +0200 Subject: [PATCH 09/52] tools: qcom: introduce mkmbn library This is a fork of qtestsign[1] with modifications to integrate with the U-Boot build system. It is pulled from f3df53a5f0e3 ("Rename "fw" to "mbn"") New Qualcomm dev boards flash U-Boot to the "uefi" partition, the format is a standard ELF file with custom program headers containing Qualcomm signatures, hashes and other metadata. Currently this is accomplished with qtestsign manually, let's instead import it so we can integrate it into the build process. This library will be used by a new mkmbn.py tool to create MBN files which can be directly flashed to the board. [1]: https://github.com/msm8916-mainline/qtestsign Link: https://patch.msgid.link/20260511-b4-qcom-tooling-improvements-v7-2-0c06346e79a9@linaro.org Signed-off-by: Casey Connolly --- tools/qcom/mkmbn/cert.py | 127 +++++++++++++ tools/qcom/mkmbn/elf.py | 205 +++++++++++++++++++++ tools/qcom/mkmbn/hashseg.py | 356 ++++++++++++++++++++++++++++++++++++ 3 files changed, 688 insertions(+) create mode 100644 tools/qcom/mkmbn/cert.py create mode 100644 tools/qcom/mkmbn/elf.py create mode 100644 tools/qcom/mkmbn/hashseg.py diff --git a/tools/qcom/mkmbn/cert.py b/tools/qcom/mkmbn/cert.py new file mode 100644 index 000000000000..e14f88746d53 --- /dev/null +++ b/tools/qcom/mkmbn/cert.py @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2021-2022 Stephan Gerhold +# See https://www.qualcomm.com/media/documents/files/secure-boot-and-image-authentication-technical-overview-v1-0.pdf +# Somewhat based on code snippets from https://cryptography.io/en/latest/x509/tutorial.html +from __future__ import annotations + +from datetime import datetime +from typing import List + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.x509.oid import NameOID + +# NOTE: The certificate chain generated by qtestsign is NOT meant +# to be secure. The private keys are listed here to make the +# resulting files reproducible. THESE KEYS SHOULD ONLY BE USED +# FOR TESTING AND NOT FOR A PROPER SECURE BOOT SETUP. + +ROOT_KEY = serialization.load_pem_private_key(b""" +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCjZqF/BwggY4Rs +Q1/wSNPLEKQEROZ9i/d+7CXZCukWph+SKHlv652oiAp+TgzIGQQXDlaA+qUoXUjp +g2KTmoulfQjrgc5CSCk6yA01VxNBqR81JorJx8aD9ApOFVoERlmWhZcR3B/LsVyd +vYgwFNNkqUh7fyywyy1Z1ijk4SyJVak1VxfdkTTeb1wr5Awjvh82PrdRQfOvctFH +mVITqdMckdRD3Sx7y8EvypAYpAUiWklNgditetXFjMoV6XyXTPCRkH9zzskrXP6i +neCyS7xUfEYPYNpabzhpdvkx9Is2PlCJA1fZ1ERZsWcag5vDZa3SHslH5Kh9+ssH +ps0Ul1j5AgMBAAECggEAHUEzOdBy+oWGwHFhnF4VmT4t91u0npawJYe3EQBckgMF +FQBtGYYoMHPG2S01KaAc9NnK0AXQCwWEl9Y/kGizhtn3fl67pG9R/mWxw7KGzpMu +dLAlWhIL7zUCoU8+UhScVpAtZ3OvN6NWDyHPX7hizptmUEIJKM//mx12LeBIvn+P +8tSiBXxoDGl0JZ+QMzmshOUXLLnxKITgBGL+G9A1qTZHIs6VV7HWH1ptfObulBZf +yEBK1YBzI6GnBGzLOWnZqGsSbQ717SObQo5rCoRDZB7z4bXNWDEvuH+rqzcs5liu +af4gmBHNOLGh+Ta5HJ0XeoqU5ANOWlUi95/n2dJufwKBgQDNaMlT1937SHPv/eBq +Be3MobllTx4vMYh6CtfP8QozTE+sTcmCyvaWVfXwLnQTl//+siefoWsvzW43LaNU +3A18nCxVFSSbWosBN+0Zo4K9bSpEFGgUrJM5O98zv4+/SzCKFe2562usDzaRiEUW +iSJkzIUnSlcNc+XCY1rhG9HLXwKBgQDLpS6ATtMDSP9p+XYVMEN2CF8M3xvL roOT +6wPYfp9fuagMgzNv9GB9SRyM/dM6mN+fkBqLp3EbDZT0UorHsg+YChoyBmctNqpW +j5/SrVyYe2xoRRgOzUbDstN44/LAhJLQnOXB7S2amo35zZ4FY6sw2w3QfkCildkB +mY3VhvESpwKBgErLtUPKfxJZN55UG7t/nS++U/wH6z3UE5YdDKizZLt5NinPyWjO +7yue8Ycb4zifSKA9zx/Zb2Zgr5l4DNmBp4eQdrQklsfbGHLBIp0LZTgE4DcaFyww +Cwv0OTpmrrlBb9NYWNAyYWqtv3kO3dlu5g8+Sd4cu8YyRZ+a/iSqNKKRAoGBAIPf +QICYCq8a60Lt5xiLe3QIsbx9EdvQ86Wqz3+3Z28uo3MO1xVNc9pNqO5oRAuzCUSj +pXz//g9duTKJ7RKp7M0w5Yu1d8TgnGeXdBCScN7RNf9DlvOm3IdH2wdy3TTr5MKw +h1wQQbLXGM9F5mlpBGeLwqNbznE6hh8yF5XJX30LAoGBAJqaa+yeZskti5ickNTF +vBBIXyYYBymdxfkf9vDSW1XcZEIVqo3+AGV+qHyTjURaty3QuEhSJEXem/obH5uE +y37+bnx8Se1IyJ/phYBLwOmtgZoBJALFhvjkFiGTF6naI8E/i4sbi5j/OEyShfWr +YFZuEKQJhiiMQznfNgthHU6H +-----END PRIVATE KEY----- +""", password=None) + +ATT_KEY = serialization.load_pem_private_key(b""" +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDT449phHltY2aV +QIvaT4PUgNS7wDybnnjVO88NGB5PjfUaWY99oDQgOLJlejyVVqRO2wHxLaUMsbuc +oe0XbgSFJgrnGvG6yPbjSXeIfV5k2dJG60S4Fg2mZ1ieSabuPVKLA03frhbATmIf +Q+VTMlWLgLVxcT04iqph6VpjehnYke0VPMuN7OM6RsIOEhLcje0bvL4YjTYXH5j4 +mPquc/ZEj/n6WJ6VsS27QygOBbaiGqHs54QnQi4gcgIgUmkR/bl2wL5s+729RBzS +v1FZfA5gdM9uEG3ogLHOC2uk+1Nuqcdk/tQxd30/2ulXubqDku/nNY2RSJrwD att +qcyCliANAgMBAAECggEAK3Z7HVbKHZENIsJZrY8v6HAAsv5ssDMicALTpsjytrjU +tPH4B/nLl2xp03zuXmemTnKIBHOrbl4qsKdaXbr4fGNgSyVwvjKoydhxB3NH4IH5 +qwhpUSVc6Ww7dkR/VFEJ1G/6Ek7AZfPuFqGzsYwalgHxtfJXb3iqGGloXA1Yrd5p +W2cTEhtSFZP/PQIEK773wYd3aYMw8OCqG2V5bw9N3xwY6KTC0Px8zyBlmAcUBPAj +QZL/DTGlMdD9+PJ3Ft3Zl2uS7ORn7xfXftvxv5IQdD+JBxV5zUIympKK/7KIVUfH +dfi93R7rqjL9EOP6bVQkg/WzYRLeVf/8km8HRGqtIQKBgQDxFxQ77t4EQqLPFofN +oRV7P3lvFqlJDTzAGBnjIT/ujT3SgoFUjRtfG27nWd1lycxv3tE0GTIw0LjJwvmg +VSFbQbPsmdp+f0jnNIiJayiG591j9Afmw06mnDodaQuSTp7K9idgpnFRGDQzwJHK +0DwSQzlzEXsPhGnXxpv+2Q+ANQKBgQDg/itVFBw3e5wC8boffi1AgnM97Qa/Y+5B +I2J9+cZD9iBkvE7kTwVUOI2Rr+XkQmSf+pT6L0yFXhQjIed004rpKVqzTvGL9VXJ +nBeADS4bxl1jsfkfvq9e6eNUK8vzyLoYQpS5/LK1oG5MPq3+30yzGIHM8JxxaOQ9 +VdKQrUdLeQKBgAh35RAN3eKMbKeVhQOmCtkfa6aJRzz3qBCfSBmAS3yXnXpNdzl/ +E10N26FouKwgoHu1eee4ktjAHB2KKbaGBvvrnORMqy4STn9AiyM4jl3euxoNslFa +vuJ/TlNGI0/qTw2WA+ATOJu+m+bNdtGG6vVBQz1VedsbrZQUt9oFydOZAoGAMlCk +4CHfLYk3GnF0bhaJiCOkIfUfzS1L2sVPAV0aOZiRJfX2rpf9WRhMkIgFoUY3uo8P +QePR+QFQ/4pVeIrWRc45ul+tJN94j92YY8qOxSdXOzRRwgeisFcdv3UL5zi8ZTB+ +khkw3e1CvUpHHvhQ7rxMSsiEM9iBMjY/IJuflgECgYEAqiN3eg8cZjVrYEMcPLGx +wXknCG0KPc8EpDi1moNwS3z/TcUbfP8vnmT2lFHTAbvVBn+4fcLffkQBoGG3AaSH +3kc0HXLdy+rFcsXpX7hk9BM/Uey9dqBOAusLS6XxYhcAJ1xOI0kYWoeOhO8fcjNa +tf26cJGzfbbwf8kfisbv4Uk= +-----END PRIVATE KEY----- +""", password=None) + + +def _begin_cert() -> x509.CertificateBuilder: + return x509.CertificateBuilder() \ + .serial_number(1) \ + .not_valid_before(datetime(2023, 1, 1)) \ + .not_valid_after(datetime(9999, 12, 31, 23, 59, 59)) # no well-defined expiration date, see RFC5280 4.1.2.5. + + +def generate_chain(ou_fields: List[str]) -> bytes: + # First, create the root CA + root_name = x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, "qtestsign Root CA - NOT SECURE"), + ]) + # only key_cert_sign=True + root_usage = x509.KeyUsage(False, False, False, False, False, True, False, False, False) + root_ski = x509.SubjectKeyIdentifier.from_public_key(ROOT_KEY.public_key()) + root_cert_der = _begin_cert() \ + .subject_name(root_name) \ + .issuer_name(root_name) \ + .public_key(ROOT_KEY.public_key()) \ + .add_extension(x509.BasicConstraints(ca=True, path_length=0), critical=True) \ + .add_extension(root_usage, critical=True) \ + .add_extension(root_ski, critical=False) \ + .sign(ROOT_KEY, hashes.SHA256()) \ + .public_bytes(serialization.Encoding.DER) + + # Now, create the attestation certificate + att_name = x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, "qtestsign Attestation CA - NOT SECURE"), + *[x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, ou) for ou in ou_fields], + ]) + # only digital_signature=True + att_usage = x509.KeyUsage(True, False, False, False, False, False, False, False, False) + att_cert_der = _begin_cert() \ + .subject_name(att_name) \ + .issuer_name(root_name) \ + .public_key(ATT_KEY.public_key()) \ + .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True) \ + .add_extension(att_usage, critical=True) \ + .add_extension(x509.SubjectKeyIdentifier.from_public_key(ATT_KEY.public_key()), critical=False) \ + .add_extension(x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(root_ski), critical=False) \ + .sign(ROOT_KEY, hashes.SHA256()) \ + .public_bytes(serialization.Encoding.DER) + + # The certificate chain is the attestation and root certificate concatenated + # in DER format. Note: The order (first attestation, then root) is important! + return att_cert_der + root_cert_der diff --git a/tools/qcom/mkmbn/elf.py b/tools/qcom/mkmbn/elf.py new file mode 100644 index 000000000000..a5c4dad5ee01 --- /dev/null +++ b/tools/qcom/mkmbn/elf.py @@ -0,0 +1,205 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2021 Stephan Gerhold +# Data classes are based on the header definitions in the ELF(5) man page. +# Also see: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +from __future__ import annotations + +import dataclasses +from dataclasses import dataclass +from struct import Struct +from typing import List, BinaryIO + + +@dataclass +class Ehdr: + ei_magic: bytes + ei_class: int + ei_data: int + ei_version: int + ei_os_abi: int + ei_abi_version: int + e_type: int + e_machine: int + e_version: int + # Address size specific part + e_entry: int = 0 + e_phoff: int = 0 + e_shoff: int = 0 + # End part + e_flags: int = 0 + e_ehsize: int = 0 + e_phentsize: int = 0 + e_phnum: int = 0 + e_shentsize: int = 0 + e_shnum: int = 0 + e_shstrndx: int = 0 + + START_FORMAT = Struct('<4s5B7xHHL') + START_COUNT = 9 + MEM_FORMAT32 = Struct(' Ehdr: + hdr_unpack = Ehdr.START_FORMAT.unpack_from(b) + hdr = Ehdr(*hdr_unpack) + assert hdr.ei_magic == b'\x7fELF', f"Invalid ELF header magic: {hdr.ei_magic}" + assert hdr.ei_data == 1, "Only little endian supported at the moment" + assert hdr.ei_version == 1, f"Unexpected ei_version: {hdr.ei_version}" + assert hdr.e_version == 1, f"Unexpected e_version: {hdr.e_version}" + + if hdr.ei_class == Ehdr.CLASS32: + mem_format = Ehdr.MEM_FORMAT32 + else: + assert hdr.ei_class == Ehdr.CLASS64, f"Unexpected ei_class: {hdr.ei_class}" + mem_format = Ehdr.MEM_FORMAT64 + + mem_unpack = mem_format.unpack_from(b, Ehdr.START_FORMAT.size) + end_unpack = Ehdr.END_FORMAT.unpack_from(b, Ehdr.START_FORMAT.size + mem_format.size) + return Ehdr(*hdr_unpack, *mem_unpack, *end_unpack) + + def save(self, f: BinaryIO) -> int: + unpack = dataclasses.astuple(self) + written = f.write(Ehdr.START_FORMAT.pack(*unpack[:Ehdr.START_COUNT])) + + if self.ei_class == Ehdr.CLASS32: + mem_format = Ehdr.MEM_FORMAT32 + else: + mem_format = Ehdr.MEM_FORMAT64 + written += f.write( + mem_format.pack(*unpack[Ehdr.START_COUNT:Ehdr.START_COUNT + Ehdr.MEM_COUNT])) + written += f.write(Ehdr.END_FORMAT.pack(*unpack[-Ehdr.END_COUNT:])) + return written + + +@dataclass +class Phdr: + p_type: int + p_offset: int + p_vaddr: int + p_paddr: int + p_filesz: int + p_memsz: int + p_flags: int + p_align: int + + data = None + + FORMAT32 = Struct('<8L') + FORMAT64 = Struct(' Phdr: + if ei_class == Ehdr.CLASS32: + unpack = list(Phdr.FORMAT32.unpack_from(b, offset)) + else: + unpack = list(Phdr.FORMAT64.unpack_from(b, offset)) + + # ELFCLASS64 has flags directly before offset for alignment + flags = unpack.pop(1) + unpack.insert(-1, flags) + + return Phdr(*unpack) + + def save(self, f: BinaryIO, ei_class: int) -> int: + unpack = dataclasses.astuple(self) + + if ei_class == Ehdr.CLASS32: + return f.write(Phdr.FORMAT32.pack(*unpack)) + else: + unpack = list(unpack) + + # ELFCLASS64 has flags directly before offset for alignment + flags = unpack.pop(-2) + unpack.insert(1, flags) + + return f.write(Phdr.FORMAT64.pack(*unpack)) + + +def _pad(f: BinaryIO, offset: int, pos: int) -> int: + assert offset >= pos, f"{offset} >= {pos}" + pad = offset - pos + if pad: + assert f.write(b'\0' * pad) == pad + return offset + + +def align(i: int, alignment: int) -> int: + mask = max(alignment - 1, 0) + return (i + mask) & ~mask + + +@dataclass +class Elf: + ehdr: Ehdr + phdrs: List[Phdr] + + def total_header_size(self): + return self.ehdr.e_phoff + len(self.phdrs) * self.ehdr.e_phentsize + + @staticmethod + def parse(b: bytes) -> Elf: + ehdr = Ehdr.parse(b) + view = memoryview(b) + + # Parse program headers + phdrs = [] + offset = ehdr.e_phoff + for i in range(ehdr.e_phnum): + phdr = Phdr.parse(b, offset, ehdr.ei_class) + phdrs.append(phdr) + + # Store data if necessary + if phdr.p_filesz and phdr.p_offset: + phdr.data = view[phdr.p_offset:phdr.p_offset + phdr.p_filesz] + + offset += ehdr.e_phentsize + + return Elf(ehdr, phdrs) + + def update(self): + # Rearrange all segments according to their alignment + pos = self.total_header_size() + for phdr in sorted(self.phdrs, key=lambda phdr: phdr.p_offset): + if phdr.p_offset and phdr.p_filesz: + phdr.p_offset = align(pos, phdr.p_align) + pos = phdr.p_offset + phdr.p_filesz + + # Ensure program header count is correct + self.ehdr.e_phnum = len(self.phdrs) + + # TODO: Clear out sections for now. Those are not read at the moment. + # Also, I don't think the Qualcomm firmware loader has any use for these. + self.ehdr.e_shoff = 0 + self.ehdr.e_shnum = 0 + self.ehdr.e_shstrndx = 0 + + def save_header(self, f: BinaryIO) -> int: + pos = self.ehdr.save(f) + pos = _pad(f, self.ehdr.e_phoff, pos) + + # Write program headers + for phdr in self.phdrs: + pos += phdr.save(f, self.ehdr.ei_class) + + return pos + + def save(self, f: BinaryIO) -> int: + pos = self.save_header(f) + + # Write segment data + for phdr in sorted(self.phdrs, key=lambda phdr: phdr.p_offset): + if phdr.data: + pos = _pad(f, phdr.p_offset, pos) + pos += f.write(phdr.data) + + return pos diff --git a/tools/qcom/mkmbn/hashseg.py b/tools/qcom/mkmbn/hashseg.py new file mode 100644 index 000000000000..fe74761ae8df --- /dev/null +++ b/tools/qcom/mkmbn/hashseg.py @@ -0,0 +1,356 @@ +# SPDX-License-Identifier: GPL-2.0-only AND BSD-3-Clause +# Copyright (C) 2021-2023 Stephan Gerhold (GPL-2.0-only) +# MBN header format adapted from: +# - signlk: https://git.linaro.org/landing-teams/working/qualcomm/signlk.git +# - coreboot (util/qualcomm/mbn_tools.py, util/cbfstool/platform_fixups.c) +# Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. (BSD-3-Clause) +# See also: +# - https://www.qualcomm.com/media/documents/files/secure-boot-and-image-authentication-technical-overview-v1-0.pdf +# - https://www.qualcomm.com/media/documents/files/secure-boot-and-image-authentication-technical-overview-v2-0.pdf +from __future__ import annotations + +import dataclasses +import hashlib +from dataclasses import dataclass +from io import BytesIO +from struct import Struct + +from . import cert +from . import elf + +# A typical Qualcomm firmware might have the following program headers: +# LOAD off 0x00000800 vaddr 0x86400000 paddr 0x86400000 align 2**11 +# filesz 0x00001000 memsz 0x00001000 flags rwx +# +# The signed version will then look like: +# NULL off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**0 +# filesz 0x000000e8 memsz 0x00000000 flags --- 7000000 +# NULL off 0x00001000 vaddr 0x86401000 paddr 0x86401000 align 2**12 +# filesz 0x00000988 memsz 0x00001000 flags --- 2200000 +# LOAD off 0x00002000 vaddr 0x86400000 paddr 0x86400000 align 2**11 +# filesz 0x00001000 memsz 0x00001000 flags rwx +# +# The second NULL program header with off 0x1000 and filesz 0x988 is the actual +# "hash table segment" or shortly "hash segment" (see Figure 2 on page 6 in the PDF). +# It contains the MBN header specified below, then a couple of hashes (e.g. SHA256): +# 1. Hash of ELF header and program headers +# 2. Empty hash for hash segment +# 3. Hashes for data of each memory segment (described by program header) +# Finally, it contains an RSA signature and the concatenated certificate chain. +# +# The first NULL program header is never loaded anywhere, because +# vaddr = paddr = memsz = 0. However, the "off" and "filesz" cover exactly +# the ELF header (including all program headers). It is a placeholder so that +# each hash covers the data of exactly one program header. + +# For definitions of the ELF PHDR flags used by Qualcomm, see: +# https://github.com/coreboot/coreboot/blob/812d0e2f626dfea7e7deb960a8dc08ff0e026bc1/util/qualcomm/mbn_tools.py#L108-L189 +PHDR_FLAGS_SEGMENT_TYPE_MASK = 0x07000000 +PHDR_FLAGS_SEGMENT_TYPE_SHIFT = 0x18 +PHDR_FLAGS_SEGMENT_TYPE_HASH = (0x2 << PHDR_FLAGS_SEGMENT_TYPE_SHIFT) +PHDR_FLAGS_SEGMENT_TYPE_HDR = (0x7 << PHDR_FLAGS_SEGMENT_TYPE_SHIFT) + +PDHR_FLAGS_ACCESS_TYPE_MASK = 0x00E00000 +PHDR_FLAGS_ACCESS_TYPE_SHIFT = 0x15 +PHDR_FLAGS_ACCESS_TYPE_RO = (0x1 << PHDR_FLAGS_ACCESS_TYPE_SHIFT) + +# Flags we use for placeholder for hash over ELF header and hash segment +PHDR_FLAGS_HDR_PLACEHOLDER = PHDR_FLAGS_SEGMENT_TYPE_HDR +PHDR_FLAGS_HASH_SEGMENT = (PHDR_FLAGS_SEGMENT_TYPE_HASH | PHDR_FLAGS_ACCESS_TYPE_RO) + +EXTRA_PHDRS = 2 # header placeholder + hash segment + +# Note: None of the alignments seem to be truly required, +# this could probably be reduced to get smaller file sizes. +HASH_SEG_ALIGN = 0x1000 +CERT_CHAIN_ALIGN = 16 + +# According to the v2.0 PDF the metadata is 128 bytes long, but this does not +# seem to work. All official firmware seems to use 120 bytes instead. +MBN_V6_METADATA_SIZE = 120 + +# See OEM Metadata 2.0 definition in coreboot source code: +# https://github.com/coreboot/coreboot/blob/812d0e2f626dfea7e7deb960a8dc08ff0e026bc1/util/qualcomm/mbn_tools.py#L506-L691 +MBN_V7_OEM_2_0_METADATA_SIZE = 224 + + +@dataclass +class _HashSegment: + image_id: int = 0 # Type of image (unused?) + version: int = 0 # Header version number + + hash_size = 0 + signature_size = 0 + cert_chain_size = 0 + total_size = 0 + + hashes = [] + signature = b'' + cert_chain = b'' + + FORMAT = Struct('<10L') + Hash = hashlib.sha256 + + @property + def size_with_header(self): + return self.FORMAT.size + self.total_size + + def update(self, dest_addr: int): + self.hash_size = len(self.hashes) * self.Hash().digest_size + self.signature_size = len(self.signature) + self.cert_chain_size = len(self.cert_chain) + self.total_size = self.hash_size + self.signature_size + self.cert_chain_size + + def check(self): + assert len(self.hashes) * self.Hash().digest_size == self.hash_size + assert len(self.signature) == self.signature_size + assert len(self.cert_chain) == self.cert_chain_size + + def pack_header(self): + self.check() + return self.FORMAT.pack(*dataclasses.astuple(self)) + + def pack(self): + return self.pack_header() \ + + b''.join(self.hashes) \ + + self.signature + self.cert_chain + + +@dataclass +class HashSegmentV3(_HashSegment): + version: int = 3 # Header version number + + flash_addr: int = 0 # Location of image in flash (historical) + dest_addr: int = 0 # Physical address of loaded hash segment data + total_size: int = 0 # = hash_size + signature_size + cert_chain_size + hash_size: int = 0 # Size of hashes for all program segments + signature_addr: int = 0 # Physical address of loaded attestation signature + signature_size: int = 0 # Size of attestation signature + cert_chain_addr: int = 0 # Physical address of loaded certificate chain + cert_chain_size: int = 0 # Size of certificate chain + + def update(self, dest_addr: int): + super().update(dest_addr) + self.dest_addr = dest_addr + self.FORMAT.size + self.signature_addr = self.dest_addr + self.hash_size + self.cert_chain_addr = self.signature_addr + self.signature_size + + +@dataclass +class HashSegmentV5(_HashSegment): + version: int = 5 # Header version number + + signature_size_qcom: int = 0 # Size of signature from Qualcomm + cert_chain_size_qcom: int = 0 # Size of certificate chain from Qualcomm + total_size: int = 0 # = hash_size + signature_size + cert_chain_size + hash_size: int = 0 # Size of hashes for all program segments + signature_addr: int = 0xffffffff # unused? + signature_size: int = 0 # Size of attestation signature + cert_chain_addr: int = 0xffffffff # unused? + cert_chain_size: int = 0 # Size of certificate chain + + signature_qcom = b'' + cert_chain_qcom = b'' + + def update(self, dest_addr: int): + super().update(dest_addr) + self.signature_size_qcom = len(self.signature_qcom) + self.cert_chain_size_qcom = len(self.cert_chain_qcom) + self.total_size += self.signature_size_qcom + self.cert_chain_size_qcom + + def check(self): + super().check() + assert len(self.signature_qcom) == self.signature_size_qcom + assert len(self.cert_chain_qcom) == self.cert_chain_size_qcom + + def pack(self): + return self.pack_header() \ + + b''.join(self.hashes) \ + + self.signature_qcom + self.cert_chain_qcom \ + + self.signature + self.cert_chain + + +@dataclass +class HashSegmentV6(HashSegmentV5): + version: int = 6 # Header version number + + metadata_size_qcom: int = 0 # Size of metadata from Qualcomm + metadata_size: int = 0 # Size of metadata + + metadata_qcom = b'' + metadata = b'' + + FORMAT = Struct('<12L') + Hash = hashlib.sha384 + + def update(self, dest_addr: int): + super().update(dest_addr) + self.metadata_size_qcom = len(self.metadata_qcom) + self.metadata_size = len(self.metadata) + self.total_size += self.metadata_size_qcom + self.metadata_size + + def check(self): + super().check() + assert len(self.metadata_qcom) == self.metadata_size_qcom + assert len(self.metadata) == self.metadata_size + + def pack(self): + return self.pack_header() \ + + self.metadata_qcom + self.metadata \ + + b''.join(self.hashes) \ + + self.signature_qcom + self.cert_chain_qcom \ + + self.signature + self.cert_chain + + +@dataclass +# Information from MBNv7 definition in Coreboot source code: +# https://github.com/coreboot/coreboot/blob/812d0e2f626dfea7e7deb960a8dc08ff0e026bc1/util/qualcomm/mbn_tools.py#L506-L691 +class HashSegmentV7(_HashSegment): + version: int = 7 # Header version number + + common_metadata_size: int = 24 # Size of "common metadata" below + metadata_size_qcom: int = 0 # Size of metadata from Qualcomm + metadata_size: int = 0 # Size of metadata from OEM + hash_size: int = 0 # Size of hashes for all program segments + signature_size_qcom: int = 0 # Size of signature from Qualcomm + cert_chain_size_qcom: int = 0 # Size of certificate chain from Qualcomm + signature_size: int = 0 # Size of attestation signature + cert_chain_size: int = 0 # Size of certificate chain + + # Common metadata, placed directly after MBNv7 header + common_metadata_major_version: int = 0 + common_metadata_minor_version: int = 0 + software_id: int = 0 # Type of software image, mandatory + secondary_software_id: int = 0 + hash_table_algorithm: int = 3 # SHA384 + measurement_register_target: int = 0 + + metadata_qcom = b'' + metadata = b'' + signature_qcom = b'' + cert_chain_qcom = b'' + + FORMAT = Struct('<16L') + Hash = hashlib.sha384 + + def update(self, dest_addr: int): + super().update(dest_addr) + self.metadata_size_qcom = len(self.metadata_qcom) + self.metadata_size = len(self.metadata) + self.signature_size_qcom = len(self.signature_qcom) + self.cert_chain_size_qcom = len(self.cert_chain_qcom) + # self.common_metadata_size is already included as part of the header + self.total_size += self.metadata_size_qcom + self.metadata_size + self.total_size += self.signature_size_qcom + self.cert_chain_size_qcom + + def check(self): + super().check() + assert len(self.metadata_qcom) == self.metadata_size_qcom + assert len(self.metadata) == self.metadata_size + assert len(self.signature_qcom) == self.signature_size_qcom + assert len(self.cert_chain_qcom) == self.cert_chain_size_qcom + + def pack(self): + return self.pack_header() \ + + self.metadata_qcom + self.metadata \ + + b''.join(self.hashes) \ + + self.signature_qcom + self.cert_chain_qcom \ + + self.signature + self.cert_chain + +HashSegment = { + 3: HashSegmentV3, + 5: HashSegmentV5, + 6: HashSegmentV6, + 7: HashSegmentV7, +} + + +def drop(elff: elf.Elf): + # Drop existing hash segments + elff.phdrs = [phdr for phdr in elff.phdrs if phdr.p_type != elf.Phdr.PT_NULL + or (phdr.p_flags & PHDR_FLAGS_SEGMENT_TYPE_MASK) not in + [PHDR_FLAGS_SEGMENT_TYPE_HASH, PHDR_FLAGS_SEGMENT_TYPE_HDR]] + + +def generate(elff: elf.Elf, version: int, sw_id: int): + drop(elff) + assert elff.phdrs, "Need at least one program header" + + hash_seg = HashSegment[version]() + + if version == 6: + # TODO: Figure out metadata format and fill this with useful data + hash_seg.metadata = b'\0' * MBN_V6_METADATA_SIZE + + # Software ID is mandatory for MBN v7 + if version == 7: + hash_seg.software_id = sw_id + # The format is documented in Coreboot util/qualcomm/mbn_tools.py + # (see class Boot_Hdr), but for simplicity we just keep this empty. + hash_seg.metadata = b'\0' * MBN_V7_OEM_2_0_METADATA_SIZE + + # Generate hash for all existing segments with data + digest_size = hash_seg.Hash().digest_size + hash_seg.hashes = [b'\0' * digest_size] * (len(elff.phdrs) + EXTRA_PHDRS) + for i, phdr in enumerate(elff.phdrs, start=EXTRA_PHDRS): + if phdr.data: + hash_seg.hashes[i] = hash_seg.Hash(phdr.data).digest() + total_hashes_size = len(hash_seg.hashes) * digest_size + + # Generate certificate chain with specified OU fields (for < v6) + # on >= v6 this is part of the metadata instead + ou_fields = [] + if version < 6: + ou_fields = [ + # Note: The SW_ID is checked by the firmware on some platforms (even if secure boot + # is disabled), so it must match the firmware type being signed. Everything else seems + # to be mostly ignored when secure boot is off and is just added here to match the + # documentation and better mimic the official firmware. + "01 %016X SW_ID" % sw_id, + "02 %016X HW_ID" % 0, + "03 %016X DEBUG" % 2, # DISABLED + "04 %04X OEM_ID" % 0, + "05 %08X SW_SIZE" % (hash_seg.FORMAT.size + total_hashes_size), + "06 %04X MODEL_ID" % 0, + "07 %04X SHA256" % 1, + ] + hash_seg.cert_chain = cert.generate_chain(ou_fields) + hash_seg.cert_chain = hash_seg.cert_chain.ljust(elf.align(len(hash_seg.cert_chain), CERT_CHAIN_ALIGN), b'\xff') + # hash_seg.cert_chain = b'' # uncomment this to omit the certificate chain in the signed image + + # TODO: Generate actual signature with our generated attestation certificate! + # There are different signature schemes that could be implemented (RSASSA-PKCS#1 v1.5 + # RSASSA-PSS, ECDSA over P-384) but it's not entirely clear yet which chipsets supports/ + # uses which. The signature does not seem to be checked on devices without secure boot, + # so just use a dummy value for now. + hash_seg.signature = b'\xff' * (cert.ATT_KEY.key_size // 8) + # hash_seg.signature = b'' # uncomment this to omit the signature in the signed image + + # Align maximum end address to get address for hash table header, then update header + hash_addr = elf.align(max(phdr.p_paddr + phdr.p_memsz for phdr in elff.phdrs), HASH_SEG_ALIGN) + hash_seg.update(hash_addr) + + # Insert new hash NULL segment + hash_phdr = elf.Phdr(elf.Phdr.PT_NULL, HASH_SEG_ALIGN, hash_addr, hash_addr, hash_seg.size_with_header, + elf.align(hash_seg.size_with_header, HASH_SEG_ALIGN), + PHDR_FLAGS_HASH_SEGMENT, HASH_SEG_ALIGN) + elff.phdrs.insert(0, hash_phdr) + + # Insert new ELF header placeholder program header + hdr_hash_phdr = elf.Phdr(elf.Phdr.PT_NULL, 0, 0, 0, 0, 0, PHDR_FLAGS_HDR_PLACEHOLDER, 0) + elff.phdrs.insert(0, hdr_hash_phdr) + + # Now determine size of ELF header (including program headers) + hdr_hash_phdr.p_filesz = elff.total_header_size() + + # Recompute attributes to match final output (e.g. adjust e_phnum) + elff.update() + + # Compute the hash for the ELF header + with BytesIO() as hdr_io: + elff.save_header(hdr_io) + hash_seg.hashes[0] = hash_seg.Hash(hdr_io.getbuffer()).digest() + + # And finally, assemble the hash segment + hash_phdr.data = hash_seg.pack() + assert len(hash_phdr.data) == hash_phdr.p_filesz \ No newline at end of file From d2668ad4a464d681995847c6c432723fb7b0e52d Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:45 +0200 Subject: [PATCH 10/52] tools: qcom: add mkmbn.py Adjust the elf class to support creating ELF files from scratch so that mkmbn can build an MBN file from the U-Boot binary image and fix some imports to work correctly in the U-Boot build system. The new tool inspects the DTB embedded in u-boot.bin and uses a lookup table to determine the appropriate configuration based on the root compatible property, effectively encoding the info that was previously kept in documentation. Link: https://patch.msgid.link/20260511-b4-qcom-tooling-improvements-v7-3-0c06346e79a9@linaro.org Signed-off-by: Casey Connolly --- tools/mkmbn | 1 + tools/qcom/mkmbn/elf.py | 38 ++++++++- tools/qcom/mkmbn/hashseg.py | 4 +- tools/qcom/mkmbn/mkmbn.py | 165 ++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 3 deletions(-) create mode 120000 tools/mkmbn create mode 100755 tools/qcom/mkmbn/mkmbn.py diff --git a/tools/mkmbn b/tools/mkmbn new file mode 120000 index 000000000000..a7b2096756f7 --- /dev/null +++ b/tools/mkmbn @@ -0,0 +1 @@ +qcom/mkmbn/mkmbn.py \ No newline at end of file diff --git a/tools/qcom/mkmbn/elf.py b/tools/qcom/mkmbn/elf.py index a5c4dad5ee01..ef83d724f855 100644 --- a/tools/qcom/mkmbn/elf.py +++ b/tools/qcom/mkmbn/elf.py @@ -45,6 +45,22 @@ class Ehdr: CLASS32 = 1 CLASS64 = 2 + # Init a qcom XBL style ELF header + def __init__(self): + self.ei_magic = b"\x7fELF" + self.ei_class = 2 + self.ei_data = 1 + self.ei_version = 1 + self.ei_os_abi = 0 + self.ei_abi_version = 0 + self.e_type = 2 + self.e_machine = 183 + self.e_version = 1 + + self.e_ehsize = 64 + self.e_phoff = 64 + self.e_phentsize = 56 + @staticmethod def parse(b: bytes) -> Ehdr: hdr_unpack = Ehdr.START_FORMAT.unpack_from(b) @@ -110,8 +126,24 @@ def parse(b: bytes, offset: int, ei_class: int) -> Phdr: return Phdr(*unpack) + @staticmethod + def from_bin(b: bytes, loadaddr: int) -> Phdr: + # p_offset is fixed later + phdr = Phdr( + p_type=1, + p_offset=0xFFFFFFFF, + p_vaddr=loadaddr, + p_paddr=loadaddr, + p_filesz=len(b), + p_memsz=len(b), + p_flags=7, + p_align=0x1000, + ) + phdr.data = memoryview(b) + return phdr + def save(self, f: BinaryIO, ei_class: int) -> int: - unpack = dataclasses.astuple(self) + unpack: tuple|list = dataclasses.astuple(self) if ei_class == Ehdr.CLASS32: return f.write(Phdr.FORMAT32.pack(*unpack)) @@ -143,6 +175,10 @@ class Elf: ehdr: Ehdr phdrs: List[Phdr] + def __init__(self, ehdr: Ehdr = Ehdr(), phdrs: List[Phdr] = []): + self.ehdr = ehdr + self.phdrs = phdrs + def total_header_size(self): return self.ehdr.e_phoff + len(self.phdrs) * self.ehdr.e_phentsize diff --git a/tools/qcom/mkmbn/hashseg.py b/tools/qcom/mkmbn/hashseg.py index fe74761ae8df..db157a23d186 100644 --- a/tools/qcom/mkmbn/hashseg.py +++ b/tools/qcom/mkmbn/hashseg.py @@ -15,8 +15,8 @@ from io import BytesIO from struct import Struct -from . import cert -from . import elf +import cert +import elf # A typical Qualcomm firmware might have the following program headers: # LOAD off 0x00000800 vaddr 0x86400000 paddr 0x86400000 align 2**11 diff --git a/tools/qcom/mkmbn/mkmbn.py b/tools/qcom/mkmbn/mkmbn.py new file mode 100755 index 000000000000..e4484b539b02 --- /dev/null +++ b/tools/qcom/mkmbn/mkmbn.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2024 Stephan Gerhold +# Copyright (C) 2026 Casey Connolly +# +# This is a port of qtestsign designed to integrate with the +# U-Boot build system. See the qtestsign repo for more information. +# https://github.com/msm8916-mainline/qtestsign +# +from __future__ import annotations + +import argparse +from pathlib import Path + +from elf import Elf, Phdr +import hashseg +import sys +from enum import Enum +import struct + +verbose = False + +def log(*args, **kwargs): + if verbose: + print(*args, *kwargs, file=sys.stderr) + +def error(*args, **kwargs): + print("mkmbn: ", file=sys.stderr, end='') + print(*args, *kwargs, file=sys.stderr) + +class SwId(Enum): + sbl1 = 0x00 + mba = 0x01 + modem = 0x02 + prog = 0x03 + adsp = 0x04 + devcfg = 0x05 + tz = 0x07 + aboot = 0x09 + uefi = 0x09 + rpm = 0x0A + tz_app = 0x0C + wcnss = 0x0D + venus = 0x0E + wlanmdsp = 0x12 + gpu = 0x14 + hyp = 0x15 + cdsp = 0x17 + slpi = 0x18 + abl = 0x1C + cmnlib = 0x1F + aop = 0x21 + qup = 0x24 + xbl_config = 0x25 + +class MbnData: + + # sw_id 0x9 is aboot/uefi, the most common + def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): + self.loadaddr = loadaddr + self.version = version + self.sw_id = sw_id + + +""" +This dictionary is used to map a board or platform to the appropriate load address and +other MBN metadata. When adding support for a new platform to U-Boot, the appropriate +data should be filled out here. The load address can typically be determined by looking +at the uefi.elf or xbl.elf for the platform. For the uefi.elf it is the load address, and +for xbl.elf it is typically the RWX section in the middle, just BEFORE the section loaded +at 0x1495xxxx or similar. Looking at similar platforms in the table below may help. +""" +boards: dict[bytes, MbnData] = { + # Exact matches for boards, these are preferred + b"qcom,qcs6490-rb3gen2\0": MbnData(0x9FC00000, 6, SwId.uefi), + b"qcom,qcs9100-ride-r3\0": MbnData(0xAF000000, 6, SwId.uefi), # Dragonwing IQ9 + b"qcom,qcs8300-ride\0": MbnData(0xAF000000, 6, SwId.uefi), # Dragonwing IQ8 + b"qcom,qcs615-ride\0": MbnData(0x9FC00000, 6, SwId.uefi), # Dragonwing IQ6 + # Fallback/generic matches since most boards for a platform will + # use the same load address + b"qcom,qcm6490\0": MbnData(0x9FC00000, 6, SwId.uefi), # rb3gen2, rubikpi3 + b"qcom,qcs9100\0": MbnData(0xAF000000, 6, SwId.uefi), # Dragonwing IQ9 + b"qcom,qcs8300\0": MbnData(0xAF000000, 6, SwId.uefi), # Dragonwing IQ8 + b"qcom,qcs8550\0": MbnData(0xA7000000, 7, SwId.uefi), # C8550 + b"qcom,sm8550\0": MbnData(0xA7000000, 7, SwId.uefi), # C8550 + b"qcom,sm8650\0": MbnData(0xA7000000, 7, SwId.uefi), # SM8650 + b"qcom,qcs615\0": MbnData(0x9FC00000, 6, SwId.uefi), # Dragonwing IQ6 + b"qcom,ipq5424\0": MbnData(0x8a380000, 6, SwId.aboot), + b"qcom,ipq9574\0": MbnData(0x4A240000, 6, SwId.aboot), + + # msm8916/apq8016 has an "aboot" partition but the process is the same + # They use header version 3. + b"qcom,apq8016\0": MbnData(0x8f600000, 3, SwId.aboot), + b"qcom,msm8916\0": MbnData(0x8f600000, 3, SwId.aboot), +} + +parser = argparse.ArgumentParser( + description=""" + Create a signed Qualcomm "uefi" ELF image +""" +) +parser.register("type", "hex", lambda s: int(s, 16)) +parser.add_argument( + "-o", "--output", type=Path, default="u-boot.mbn", help="Output file" +) +parser.add_argument( + "-v", dest="verbose", action="store_true", default=False, help="Verbose" +) +parser.add_argument( + "bin", type=argparse.FileType("rb"), help="Binary to embed (e.g. u-boot.bin)" +) +args = parser.parse_args() +verbose = args.verbose + +elf = Elf() + +data: bytes = args.bin.read() + +# dtb is at the end, so find the last match +dtb_off = 0 +off = 0 +dtb_size = 0 +while True: + off = data.find(b"\xd0\x0d\xfe\xed", dtb_off + dtb_size) + if off == -1: + break + (dtb_size,) = struct.unpack_from("I", data, offset=off) + dtb_off = off + +if not dtb_off: + print("Couldn't find DTB in provided binary!") + exit(1) + +log(f"Found FDT at {dtb_off:#x} size {dtb_size:#x}") + +mbn: MbnData|None = None + +for match, mbndata in boards.items(): + if data.find(match, dtb_off) != -1: + mbn = mbndata + break + +if not mbn: + error( + "CONFIG_QCOM_GENERATE_MBN is enabled but this platform doesn't appear to be supported\n" + "Please see tools/qcom/mkmbn/mkmbn.py for details. If you intend to chainload U-Boot\n" + "then disregard this message and disable CONFIG_QCOM_GENERATE_MBN in your defconfig." + ) + args.output.unlink(missing_ok=True) + exit(1) + +log(f"Detected board {match.decode('UTF-8')} with load address {mbn.loadaddr:#x}") + +elf.phdrs.append(Phdr.from_bin(data, mbn.loadaddr)) +elf.ehdr.e_entry = mbn.loadaddr +elf.update() + +# QLI boards use v6 sw_id is "aboot" +hashseg.generate(elf, mbn.version, mbn.sw_id.value) +# print(f"after: {elf}") + +with open(args.output, "wb") as f: + elf.save(f) + +log(f"Built signed MBN: {args.output.resolve()}") From 1d038987306f5985de5fcb23be24859575949229 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:46 +0200 Subject: [PATCH 11/52] doc: board/qualcomm: update docs for new u-boot.mbn target Update the build docs to describe building the u-boot.mbn target explicitly for some boards. Additionally add a new "signing" page to describe the purpose of mkmbn and the MBN format. Link: https://patch.msgid.link/20260511-b4-qcom-tooling-improvements-v7-4-0c06346e79a9@linaro.org Signed-off-by: Casey Connolly --- doc/board/qualcomm/board.rst | 2 +- doc/board/qualcomm/dragonboard410c.rst | 19 ++++++---------- doc/board/qualcomm/dragonwing.rst | 14 ++++-------- doc/board/qualcomm/index.rst | 1 + doc/board/qualcomm/rb3gen2.rst | 30 ++++++++++++-------------- doc/board/qualcomm/rdp.rst | 5 +++-- doc/board/qualcomm/signing.rst | 29 +++++++++++++++++++++++++ 7 files changed, 58 insertions(+), 42 deletions(-) create mode 100644 doc/board/qualcomm/signing.rst diff --git a/doc/board/qualcomm/board.rst b/doc/board/qualcomm/board.rst index eb800f8c535a..18119cec5b13 100644 --- a/doc/board/qualcomm/board.rst +++ b/doc/board/qualcomm/board.rst @@ -104,7 +104,7 @@ Use the following commands:: Or for db410c (and other boards not supported by the generic target):: - make CROSS_COMPILE=aarch64-linux-gnu- O=.output dragonboard410c_defconfig + make CROSS_COMPILE=aarch64-linux-gnu- O=.output qcom_dragonboard410c_defconfig make CROSS_COMPILE=aarch64-linux-gnu- O=.output -j$(nproc) Or for smartphones:: diff --git a/doc/board/qualcomm/dragonboard410c.rst b/doc/board/qualcomm/dragonboard410c.rst index 34629241110c..cc2d28e9dfda 100644 --- a/doc/board/qualcomm/dragonboard410c.rst +++ b/doc/board/qualcomm/dragonboard410c.rst @@ -21,27 +21,20 @@ Installation First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``dragonboard410c``:: $ export CROSS_COMPILE= - $ make dragonboard410c_defconfig + $ make qcom_dragonboard410c_defconfig $ make -This will build ``u-boot.elf`` in the configured output directory. +This will build ``u-boot.mbn`` in the configured output directory. Although the DragonBoard 410c does not have secure boot set up by default, -the firmware still expects firmware ELF images to be "signed". The signature -does not provide any security in this case, but it provides the firmware with -some required metadata. +the firmware still expects firmware ELF images to be "signed". This is +handled automatically with mkmbn (see :doc:`signing` for more details). -To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_:: - - $ ./qtestsign.py aboot u-boot.elf - -Then install the resulting ``u-boot-test-signed.mbn`` to the ``aboot`` partition -on your device, e.g. with ``fastboot flash aboot u-boot-test-signed.mbn``. +Then install the resulting ``u-boot.mbn`` to the ``aboot`` partition +on your device, e.g. with ``fastboot flash aboot u-boot.mbn``. U-Boot should be running after a reboot (``fastboot reboot``). -.. _qtestsign: https://github.com/msm8916-mainline/qtestsign - Usage ----- Press Volume Down during boot to enter Fastboot mode. diff --git a/doc/board/qualcomm/dragonwing.rst b/doc/board/qualcomm/dragonwing.rst index d48994153095..028ec340d155 100644 --- a/doc/board/qualcomm/dragonwing.rst +++ b/doc/board/qualcomm/dragonwing.rst @@ -20,18 +20,13 @@ First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``QCS615``, ` $ export CROSS_COMPILE= $ make qcom_qcs8300_defconfig - $ make -j8 u-boot.mbn + $ make -j8 Although the board does not have secure boot set up by default, -the firmware still expects firmware ELF images to be "signed". The signature -does not provide any security in this case, but it provides the firmware with -some required metadata. +the firmware still expects firmware ELF images to be "signed" in the MBN format. +This is handled automatically with mkmbn (see :doc:`signing` for more details). -To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_:: - - $ qtestsign -v6 aboot -o u-boot.mbn u-boot.elf - -Then flash the resulting ``u-boot.mbn`` to the ``uefi_a`` partition +Just flash the resulting ``u-boot.mbn`` to the ``uefi_a`` partition on your device with ``fastboot flash uefi_a u-boot.mbn``. U-Boot should be running after a reboot (``fastboot reboot``). @@ -44,6 +39,5 @@ the firehose loader can be obtained from `dragonwing IQ9 bootbinaries`.) :: $ edl.py --loader /path/to/prog_firehose_ddr.elf w uefi_a u-boot.mbn -.. _qtestsign: https://github.com/msm8916-mainline/qtestsign .. _edl: https://github.com/bkerler/edl .. _dragonwing IQ9 bootbinaries: https://artifacts.codelinaro.org/ui/native/qli-ci/flashable-binaries/qimpsdk/qcs9075-rb8-core-kit diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst index 9854896f4ec2..b7ab843b4c47 100644 --- a/doc/board/qualcomm/index.rst +++ b/doc/board/qualcomm/index.rst @@ -14,6 +14,7 @@ Qualcomm iq8 phones rdp + signing snagboot See also diff --git a/doc/board/qualcomm/rb3gen2.rst b/doc/board/qualcomm/rb3gen2.rst index 518d01c4c3a3..329baa8d1f3a 100644 --- a/doc/board/qualcomm/rb3gen2.rst +++ b/doc/board/qualcomm/rb3gen2.rst @@ -18,32 +18,30 @@ First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``qcm6490``:: $ export CROSS_COMPILE= $ make qcm6490_defconfig - $ make -j8 + $ make -j8 DEVICE_TREE=qcom/qcs6490-rb3gen2 -This will build ``u-boot.elf`` in the configured output directory. +This will build ``u-boot.mbn`` in the configured output directory. -Although the RB3 Gen 2 does not have secure boot set up by default, -the firmware still expects firmware ELF images to be "signed". The signature -does not provide any security in this case, but it provides the firmware with -some required metadata. - -To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_:: - - $ qtestsign -v6 aboot -o u-boot.mbn u-boot.elf +Although the board does not have secure boot set up by default, +the firmware still expects firmware ELF images to be "signed" in the MBN format. +This is handled automatically with mkmbn (see :doc:`signing` for more details). Then install the resulting ``u-boot.mbn`` to the ``uefi_a`` partition on your device with ``fastboot flash uefi_a u-boot.mbn``. U-Boot should be running after a reboot (``fastboot reboot``). -Note that fastboot is not yet supported in U-Boot on this board, as a result, -to flash back the original firmware, or new versoins of the U-Boot, EDL mode -must be used. This can be accessed by pressing the EDL mode button as described -in the Qualcomm Linux documentation. A tool like bkerler's `edl`_ can be used -for flashing with the firehose loader binary appropriate for the board. +Note that fastboot is not yet supported in U-Boot on this board, as a result, to flash +back the original firmware, or new versoins of the U-Boot, EDL mode must be used. This +can be accessed by holding the EDL button while powering on as described in the +Qualcomm Linux documentation. + +A tool like bkerler's `edl`_ can be used for flashing with the firehose loader from the `RB3 Gen 2 bootbinaries`. :: + + $ edl.py --loader /path/to/prog_firehose_ddr.elf w uefi_a u-boot.mbn -.. _qtestsign: https://github.com/msm8916-mainline/qtestsign .. _edl: https://github.com/bkerler/edl +.. _RB3 Gen 2 bootbinaries: https://artifacts.codelinaro.org/artifactory/qli-ci/software/chip/qualcomm_linux-spf-1-0/qualcomm-linux-spf-1-0_test_device_public/r1.0_00039.2/QCM6490.LE.1.0/common/build/ufs/bin/QCM6490_bootbinaries.zip Usage ----- diff --git a/doc/board/qualcomm/rdp.rst b/doc/board/qualcomm/rdp.rst index 99cf8eba57ce..4e63fe624b8a 100644 --- a/doc/board/qualcomm/rdp.rst +++ b/doc/board/qualcomm/rdp.rst @@ -17,9 +17,10 @@ First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``IPQ9574``:: $ export CROSS_COMPILE= $ make qcom_ipq9574_mmc_defconfig - $ make -j8 + $ make -j8 u-boot.mbn -This will build ``u-boot.elf`` in the configured output directory. +This will build the signed ``u-boot.mbn`` in the configured output directory. More information +about image signing can be found in :doc:`signing`. The firmware expects the ELF images to be in MBN format. The `elftombn.py` tool can be used to convert the ELF images to MBN format. diff --git a/doc/board/qualcomm/signing.rst b/doc/board/qualcomm/signing.rst new file mode 100644 index 000000000000..317cd57cefee --- /dev/null +++ b/doc/board/qualcomm/signing.rst @@ -0,0 +1,29 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. sectionauthor:: Casey Connolly + +Qualcomm Image Signing +====================== + +On some boards like the RB3 Gen 2 where U-Boot runs as the first stage bootloader, +it must be in a Qualcomm specific signed ELF format called ``mbn``. + +For most boards this is handled automatically with the ``mkmbn`` tool in the U-Boot +build system. If you're bringing up a new platform which will run U-Boot as the first +stage bootloader, you may need to add your board and platform compatible string and +the load address used by your board to the ``boards`` table in ``tools/qcom/mkmbn/mkmbn.py``. + +For example: + +.. code-block:: python + + boards: dict[bytes, int] = { + # Exact matches for boards, these are preferred + # Don't forget the null terminator! + b"qcom,qcs6490-rb3gen2\0": MbnData(0x9FC00000, 6, SwId.aboot), + ... + } + + +When you run make to build the ``u-boot.mbn`` target, ``mkmbn`` will inspect the DTB in your +U-Boot image and try to match the compatible to the table, then it will build an ELF image and +hash/sign it per the MBN spec. From edb6951b5395178e80f3a031ab7076082db749c8 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:47 +0200 Subject: [PATCH 12/52] mach-snapdragon: add kconfig infra for building MBN files Add a qualcomm specific Makefile fragment to make u-boot.mbn a build target and introduce a kconfig option to build it by default on relevant platforms via CONFIG_BUILD_TARGET. Link: https://patch.msgid.link/20260511-b4-qcom-tooling-improvements-v7-5-0c06346e79a9@linaro.org [casey: minor kconfig fix] Signed-off-by: Casey Connolly --- Kconfig | 1 + arch/arm/mach-snapdragon/Kconfig | 9 +++++++++ board/qualcomm/config.mk | 14 ++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 board/qualcomm/config.mk diff --git a/Kconfig b/Kconfig index 6f44e1f80466..b169c83728a4 100644 --- a/Kconfig +++ b/Kconfig @@ -580,6 +580,7 @@ config BUILD_TARGET default "u-boot.itb" if !BINMAN && SPL_LOAD_FIT && (ARCH_ROCKCHIP || \ RISCV || ARCH_ZYNQMP) default "u-boot.kwb" if (ARCH_KIRKWOOD || ARMADA_32BIT) && !SPL + default "u-boot.mbn" if ARCH_SNAPDRAGON && QCOM_GENERATE_MBN help Some SoCs need special image types (e.g. U-Boot binary with a special header) as build targets. By defining diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index c808f6febca0..a435b017b1f5 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -114,5 +114,14 @@ config QCOM_SNAGBOOT_MODE Platform-specific requirements: - Set CONFIG_COUNTER_FREQUENCY to match your platform's timer - Configure CONFIG_TEXT_BASE for U-Boot load address +config QCOM_GENERATE_MBN + bool "Generate an MBN-compatible ELF binary" + help + Enable this if you intend to flash U-Boot as a first-stage bootloader. + The build system will generate a board-specific ELF file with the appropriate + MBN hash segments and test keys. + + New platforms can be added to tools/qcom/mkmbn/mkmbn.py if they aren't already + supported. endif diff --git a/board/qualcomm/config.mk b/board/qualcomm/config.mk new file mode 100644 index 000000000000..769e4a51ca01 --- /dev/null +++ b/board/qualcomm/config.mk @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright Linaro Ltd. +# +# Qualcomm specific make target for MBN signed ELF files. +# + +# Create Qualcomm signed elf images +CMD_MKMBN = $(srctree)/tools/qcom/mkmbn/mkmbn.py +quiet_cmd_mkmbn = MBN $@ + cmd_mkmbn = $(CMD_MKMBN) $< + +u-boot.mbn: u-boot.bin FORCE + $(call if_changed,mkmbn) From 4c8505b04b5b028d3a7387cfe8a2c1e4df7d7c40 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:48 +0200 Subject: [PATCH 13/52] configs: qcom: use mkmbn and stop building ELF files With mkmbn integrated we now no longer need CONFIG_REMAKE_ELF to then run qtestsign and can instead just enable QCOM_GENERATE_MBN to have mkmbn emit an MBN file directly. While we're here, finally rename the db410c and 820c defconfigs to have the qcom_ prefix. Tested on qcs6490 and sm8550. Tested-by: Stephan Gerhold # db410c Link: https://patch.msgid.link/20260511-b4-qcom-tooling-improvements-v7-6-0c06346e79a9@linaro.org Signed-off-by: Casey Connolly --- configs/qcm6490_defconfig | 2 +- ...dragonboard410c_defconfig => qcom_dragonboard410c_defconfig} | 2 +- ...dragonboard820c_defconfig => qcom_dragonboard820c_defconfig} | 0 configs/qcom_ipq9574_mmc_defconfig | 2 +- configs/qcom_lemans_defconfig | 2 +- configs/qcom_qcs615_defconfig | 2 +- configs/qcom_qcs8300_defconfig | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename configs/{dragonboard410c_defconfig => qcom_dragonboard410c_defconfig} (98%) rename configs/{dragonboard820c_defconfig => qcom_dragonboard820c_defconfig} (100%) diff --git a/configs/qcm6490_defconfig b/configs/qcm6490_defconfig index 5d0c7e2556e4..391573db5681 100644 --- a/configs/qcm6490_defconfig +++ b/configs/qcm6490_defconfig @@ -11,7 +11,7 @@ CONFIG_ARM=y # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0x9fc00000 -CONFIG_REMAKE_ELF=y +CONFIG_QCOM_GENERATE_MBN=y CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs6490-rb3gen2" diff --git a/configs/dragonboard410c_defconfig b/configs/qcom_dragonboard410c_defconfig similarity index 98% rename from configs/dragonboard410c_defconfig rename to configs/qcom_dragonboard410c_defconfig index 645f08167010..64b8fcc7ea47 100644 --- a/configs/dragonboard410c_defconfig +++ b/configs/qcom_dragonboard410c_defconfig @@ -13,7 +13,7 @@ CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_SYS_LOAD_ADDR=0x80080000 CONFIG_BOOT0_MSM8916_PSCI_WORKAROUND=y CONFIG_IDENT_STRING="\nQualcomm-DragonBoard 410C" -CONFIG_REMAKE_ELF=y +CONFIG_QCOM_GENERATE_MBN=y CONFIG_BUTTON_CMD=y CONFIG_FIT=y CONFIG_BOOTSTD_FULL=y diff --git a/configs/dragonboard820c_defconfig b/configs/qcom_dragonboard820c_defconfig similarity index 100% rename from configs/dragonboard820c_defconfig rename to configs/qcom_dragonboard820c_defconfig diff --git a/configs/qcom_ipq9574_mmc_defconfig b/configs/qcom_ipq9574_mmc_defconfig index d1da6bc82c8b..51b703433848 100644 --- a/configs/qcom_ipq9574_mmc_defconfig +++ b/configs/qcom_ipq9574_mmc_defconfig @@ -12,7 +12,7 @@ CONFIG_SYS_LOAD_ADDR=0x50000000 CONFIG_DEBUG_UART_BASE=0x78b1000 CONFIG_DEBUG_UART_CLOCK=1843200 CONFIG_DEBUG_UART=y -CONFIG_REMAKE_ELF=y +CONFIG_QCOM_GENERATE_MBN=y # CONFIG_EFI_LOADER is not set CONFIG_FIT=y CONFIG_FIT_VERBOSE=y diff --git a/configs/qcom_lemans_defconfig b/configs/qcom_lemans_defconfig index 21d2395e63f3..6f78a6afe9fd 100644 --- a/configs/qcom_lemans_defconfig +++ b/configs/qcom_lemans_defconfig @@ -8,7 +8,7 @@ # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0xaf000000 -CONFIG_REMAKE_ELF=y +CONFIG_QCOM_GENERATE_MBN=y CONFIG_FASTBOOT_BUF_ADDR=0xdb300000 CONFIG_DEFAULT_DEVICE_TREE="qcom/lemans-evk" CONFIG_ENV_IS_IN_SCSI=y diff --git a/configs/qcom_qcs615_defconfig b/configs/qcom_qcs615_defconfig index 973cf9c9305e..1479f75e41aa 100644 --- a/configs/qcom_qcs615_defconfig +++ b/configs/qcom_qcs615_defconfig @@ -16,7 +16,7 @@ CONFIG_DEBUG_UART_CLOCK=7372800 CONFIG_DEFAULT_DEVICE_TREE="qcom/talos-evk" -CONFIG_REMAKE_ELF=y +CONFIG_QCOM_GENERATE_MBN=y # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0x9fc00000 diff --git a/configs/qcom_qcs8300_defconfig b/configs/qcom_qcs8300_defconfig index 9c357426bd1a..be86e2fae640 100644 --- a/configs/qcom_qcs8300_defconfig +++ b/configs/qcom_qcs8300_defconfig @@ -16,7 +16,7 @@ CONFIG_DEBUG_UART_CLOCK=14745600 # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0xaf000000 -CONFIG_REMAKE_ELF=y +CONFIG_QCOM_GENERATE_MBN=y CONFIG_DEFAULT_DEVICE_TREE="qcom/monaco-evk" CONFIG_PINCTRL_QCOM_QCS8300=y From 9cc5a3c95166c8cbf36aa0decb1487e53903c0c3 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:13 +0200 Subject: [PATCH 14/52] Makefile: add SPL_REMAKE_ELF_LDSCRIPT feature Some platforms (e.g. at least Qualcomm) use the ELF format in creative ways, including in the bootrom. Make SPL_REMAKE_ELF use a linker script specified in SPL_REMAKE_ELF_LDSCRIPT (with the previously hardcoded path as the default). Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-1-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- Makefile | 11 +++++++---- common/spl/Kconfig | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ae1cf241cd7e..0239203290d4 100644 --- a/Makefile +++ b/Makefile @@ -2012,15 +2012,18 @@ u-boot.elf: u-boot.bin u-boot-elf.lds FORCE quiet_cmd_u-boot-spl-elf ?= LD $@ cmd_u-boot-spl-elf ?= $(LD) spl/u-boot-spl-elf.o -o $@ \ $(if $(CONFIG_SYS_BIG_ENDIAN),-EB,-EL) \ - -T u-boot-elf.lds --defsym=$(CONFIG_PLATFORM_ELFENTRY)=$(CONFIG_SPL_TEXT_BASE) \ + -T spl/u-boot-spl-elf.lds --defsym=$(CONFIG_PLATFORM_ELFENTRY)=$(CONFIG_SPL_TEXT_BASE) \ -Ttext=$(CONFIG_SPL_TEXT_BASE) -spl/u-boot-spl.elf: spl/u-boot-spl.bin u-boot-elf.lds +spl/u-boot-spl.elf: spl/u-boot-spl.bin spl/u-boot-spl-elf.lds FORCE $(Q)$(OBJCOPY) -I binary $(PLATFORM_ELFFLAGS) $< spl/u-boot-spl-elf.o $(call if_changed,u-boot-spl-elf) -REMAKE_ELF_LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_REMAKE_ELF_LDSCRIPT:"%"=%)) +SPL_REMAKE_ELF_LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_SPL_REMAKE_ELF_LDSCRIPT:"%"=%)) -u-boot-elf.lds: $(REMAKE_ELF_LDSCRIPT) prepare FORCE +spl/u-boot-spl-elf.lds: $(SPL_REMAKE_ELF_LDSCRIPT) prepare FORCE + $(call if_changed_dep,cpp_lds) + +u-boot-elf.lds: arch/u-boot-elf.lds prepare FORCE $(call if_changed_dep,cpp_lds) PHONY += prepare0 diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 93e69f6d7c48..10b0c3d37c32 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -238,6 +238,18 @@ config SPL_HANDOFF proper. Also SPL can receive information from TPL in the same place if that is enabled. +config SPL_REMAKE_ELF_LDSCRIPT + string "Linker script for SPL ELF" + depends on SPL_REMAKE_ELF + default "arch/u-boot-elf.lds" + help + This allows specifying a linker script that will be used to re-wrap + the SPL binary into an ELF. + + Some platforms (e.g. at least Qualcomm) use the ELF format in creative + ways, including in the bootrom. For such platforms, you can change + the default linker script to a platform-specific one. + config SPL_LDSCRIPT string "Linker script for the SPL stage" default "arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds" if MACH_SUNIV From d76f2af342cb210831a65c507670ce8ab10dfdbb Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:14 +0200 Subject: [PATCH 15/52] of_live: support in SPL Add CONFIG_SPL_OF_LIVE and if set, initialize of_live in spl.c Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-2-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- common/spl/spl.c | 9 +++++++++ dts/Kconfig | 8 ++++++++ lib/Makefile | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/common/spl/spl.c b/common/spl/spl.c index 722b18c98edc..6c9a1a1cbcc3 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -510,6 +511,14 @@ static int spl_common_init(bool setup_malloc) return ret; } } + if (CONFIG_IS_ENABLED(OF_LIVE)) { + bootstage_start(BOOTSTAGE_ID_ACCUM_OF_LIVE, "of_live"); + ret = of_live_build(gd->fdt_blob, + (struct device_node **)gd_of_root_ptr()); + bootstage_accum(BOOTSTAGE_ID_ACCUM_OF_LIVE); + if (ret) + return ret; + } if (CONFIG_IS_ENABLED(DM)) { bootstage_start(BOOTSTAGE_ID_ACCUM_DM_SPL, xpl_phase() == PHASE_TPL ? "dm tpl" : "dm_spl"); diff --git a/dts/Kconfig b/dts/Kconfig index dcabe33c1c1a..d56d94679f5d 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -86,6 +86,14 @@ config OF_LIVE enables a live tree which is available after relocation, and can be adjusted as needed. +config SPL_OF_LIVE + bool "Enable use of a live tree in SPL" + depends on SPL_DM && SPL_OF_CONTROL + help + This option enables a live tree in SPL, allowing the sharing + of OF fixup code between U-Boot proper and SPL. + See also OF_LIVE. + config OF_UPSTREAM bool "Enable use of devicetree imported from Linux kernel release" depends on !COMPILE_TEST && !SANDBOX diff --git a/lib/Makefile b/lib/Makefile index bef575e9199c..d25b5b4b8a9c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_updates/ obj-$(CONFIG_LZMA) += lzma/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_FIT) += libfdt/ -obj-$(CONFIG_OF_LIVE) += of_live.o obj-$(CONFIG_CMD_DHRYSTONE) += dhry/ obj-$(CONFIG_ARCH_AT91) += at91/ obj-$(CONFIG_OPTEE_LIB) += optee/ @@ -56,6 +55,7 @@ obj-y += list_sort.o obj-$(CONFIG_PMBUS) += pmbus.o endif +obj-$(CONFIG_$(PHASE_)OF_LIVE) += of_live.o obj-$(CONFIG_$(PHASE_)TPM) += tpm-common.o ifeq ($(CONFIG_$(PHASE_)TPM),y) obj-$(CONFIG_TPM) += tpm_api.o From ffa858607cb336a394dfe2c53db11d57e5356fb4 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:15 +0200 Subject: [PATCH 16/52] drivers: allow clk_stub and spmi in SPL Only Makefile and Kconfig changes necessary. Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-3-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- drivers/Makefile | 2 +- drivers/clk/Kconfig | 6 +++--- drivers/spmi/Kconfig | 13 +++++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/Makefile b/drivers/Makefile index f694a18c0a43..1cc23adf35f1 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_$(PHASE_)RAM) += ram/ obj-$(CONFIG_$(PHASE_)RTC) += rtc/ obj-$(CONFIG_$(PHASE_)SERIAL) += serial/ obj-$(CONFIG_$(PHASE_)SPI) += spi/ +obj-$(CONFIG_$(PHASE_)SPMI) += spmi/ obj-$(CONFIG_$(PHASE_)TIMER) += timer/ obj-$(CONFIG_$(PHASE_)VIRTIO) += virtio/ obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox/ @@ -106,7 +107,6 @@ obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode/ obj-y += rtc/ obj-y += scsi/ obj-y += sound/ -obj-y += spmi/ obj-y += watchdog/ obj-$(CONFIG_QE) += qe/ obj-$(CONFIG_U_QE) += qe/ diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 03f285652fb8..c97083a5252d 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -115,11 +115,11 @@ config CLK_STUB controllers. config SPL_CLK_STUB - bool "Stub clock driver in SPL" + bool "Stub clock driver" depends on SPL_CLK help - Enable this to provide a stub clock driver for non-essential clock - controllers in U-Boot SPL. + Enable this to provide a stub clock driver in SPL for non-essential + clock controllers config CLK_BCM6345 bool "Clock controller driver for BCM6345" diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index e28fd9af1d02..f89723711501 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -8,12 +8,25 @@ config SPMI SPMI (System Power Management Interface) bus is used to connect PMIC devices on various SoCs. +config SPL_SPMI + bool "Enable SPMI bus support in SPL" + depends on SPL_DM + help + Select this to enable SPMI bus support in SPL + config SPMI_MSM bool "Support Qualcomm SPMI bus" depends on SPMI help Support SPMI bus implementation found on Qualcomm Snapdragon SoCs. +config SPL_SPMI_MSM + bool "Support Qualcomm SPMI bus" + depends on SPL_SPMI + help + Support SPMI bus implementation found on Qualcomm Snapdragon SoCs + in SPL. + config SPMI_SANDBOX bool "Support for Sandbox SPMI bus" depends on SPMI From d3d83999c47682d3c2ad94969614e99c955887ae Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:16 +0200 Subject: [PATCH 17/52] mach-snapdragon: boot0.h: split out msm8916_boot0.h Prepare for supporting alternative boot0.h per-SoC by splitting out the existing msm8916-specific code. There is now a selection mechanism to choose a specific boot0.h in the Kconfig. BOOT0_MSM8916_PSCI_WORKAROUND is the only option right now, but more can be added. The toplevel boot0.h additionally enables conditionally performing the include only in u-boot proper, or only in SPL. Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-4-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/Kconfig | 17 +++++++++++++++++ configs/hmibsc_defconfig | 1 + 2 files changed, 18 insertions(+) diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index a435b017b1f5..0a060e337264 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -124,4 +124,21 @@ config QCOM_GENERATE_MBN New platforms can be added to tools/qcom/mkmbn/mkmbn.py if they aren't already supported. +choice + prompt "Qualcomm boot0.h workaround" + optional + help + While U-Boot on Qualcomm platforms doesn't generally need compile-time + adjustments based on the target SoC, workarounds in boot0.h can't + practically detect the SoC at runtime. Enable one of these workarounds + if you know you need it. + +config BOOT0_MSM8916_PSCI_WORKAROUND + bool "boot0.h workaround for buggy PSCI on the msm8916 SoC" + help + Select this if you are building U-Boot proper for an msm8916 board that + uses the buggy PSCI implementation. + +endchoice + endif diff --git a/configs/hmibsc_defconfig b/configs/hmibsc_defconfig index c8fad154e315..a0d501e70718 100644 --- a/configs/hmibsc_defconfig +++ b/configs/hmibsc_defconfig @@ -12,6 +12,7 @@ CONFIG_ENV_OFFSET=0x0 CONFIG_DEFAULT_DEVICE_TREE="apq8016-schneider-hmibsc" CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_SYS_LOAD_ADDR=0x80080000 +CONFIG_BOOT0_MSM8916_PSCI_WORKAROUND=y CONFIG_IDENT_STRING="\nSchneider Electric-HMIBSC" CONFIG_REMAKE_ELF=y # CONFIG_ANDROID_BOOT_IMAGE is not set From 65cacef9d1e2af1edb50f835c579a6a8d5dbdb9d Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:17 +0200 Subject: [PATCH 18/52] qualcomm: add u-boot-spl-elf-sdm845.lds This custom linker script is required to produce a bootable ELF for the sdm845 SoC. An xbl_sec.elf must be provided, which will be put in a section in the ELF as required by the boot rom. Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-5-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- .../sdm845_spl/u-boot-spl-elf-sdm845.lds | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 board/qualcomm/sdm845_spl/u-boot-spl-elf-sdm845.lds diff --git a/board/qualcomm/sdm845_spl/u-boot-spl-elf-sdm845.lds b/board/qualcomm/sdm845_spl/u-boot-spl-elf-sdm845.lds new file mode 100644 index 000000000000..3740209d4995 --- /dev/null +++ b/board/qualcomm/sdm845_spl/u-boot-spl-elf-sdm845.lds @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * The boot rom uses the segment type to identify the xbl_sec program header. + * See https://github.com/coreboot/coreboot/blob/643efabd2af9f7ac/util/qualcomm/mbn_tools.py#L143. + */ +#define PF_SEGMENT_TYPE_XBL_SEC 5 + +/* + * The boot rom expects this to be equal to a seemingly magic value possibly specific + * to a particular xbl_sec.elf. If you're extracting your xbl_sec.elf from an xbl elf, + * you can just reuse the value; otherwise you can either compute it yourself or use + * coreboot's tool. + * See https://github.com/coreboot/coreboot/blob/643efabd2af9f7ac/util/qualcomm/createxbl.py#L638. + */ +#define XLB_SEC_SEGMENT_ADDR 0x0000000014699000 + + +TARGET("binary") +INPUT("./xbl_sec.elf") + +OUTPUT_FORMAT("default") + +ENTRY(CONFIG_PLATFORM_ELFENTRY) +PHDRS +{ + data PT_LOAD FLAGS(7); + xbl_sec PT_LOAD FLAGS(5 | (PF_SEGMENT_TYPE_XBL_SEC << 24)); +} +SECTIONS +{ + + . = XLB_SEC_SEGMENT_ADDR; + .xbl_sec : { // XBL_SEC nested ELF + . = .; + "./xbl_sec.elf" + } :xbl_sec + + . = CONFIG_PLATFORM_ELFENTRY; + + .data : { + *(.data*) + } :data +} From e40f45c19c8ccbbe6ec5277d7637a2993706144a Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:18 +0200 Subject: [PATCH 19/52] mach-snapdragon: Kconfig: fix duplicate SYS_MALLOC_LEN Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-6-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 0a060e337264..4609fcc9a02c 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -11,9 +11,6 @@ config SYS_VENDOR Based on this option board// will be used as the custom board directory. -config SYS_MALLOC_LEN - default 0x10000000 - config SYS_MALLOC_F_LEN default 0x2000 From ca723b1732131958400a3c14d90deae426a8fef1 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:19 +0200 Subject: [PATCH 20/52] mach-snapdragon: Kconfig: changes / additions to support SPL Select SUPPORT_SPL so SPL build can be enabled, disable SYSRESET_PSCI in SPL. (SPL runs in EL3, so if SPL itself doesn't provide PSCI, nothing else will.) Also select (SPL_)OF_LIVE and (SPL_)EVENT, which are needed to fix up upstream dt to make usb work, and in general don't make sense to disable in SPL as long as we're not running out of SRAM. Mirror u-boot proper selections like GPIO and pinctrl to ensure consistent behavior, and select SPL_SPRINTF, SPL_LIBCOMMON_SUPPORT etc for similar reasons. Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-7-c108ebe8ff4e@seznam.cz [casey: kconfig fix missing "if SPL"] Signed-off-by: Casey Connolly --- arch/arm/Kconfig | 33 ++++++++++++++++++++++++++++- arch/arm/mach-snapdragon/Kconfig | 10 +++++++++ arch/arm/mach-snapdragon/of_fixup.c | 2 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4e4d3a3e157d..725ca04f3b3f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1139,6 +1139,7 @@ config ARCH_SNAPDRAGON select DM_GPIO select DM_SERIAL select DM_RESET + select EVENT select POWER_DOMAIN select GPIO_EXTRA_HEADER select OF_CONTROL @@ -1149,9 +1150,39 @@ config ARCH_SNAPDRAGON select SAVE_PREV_BL_FDT_ADDR if !ENABLE_ARM_SOC_BOOT0_HOOK select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK select SYSRESET - select SYSRESET_PSCI if !QCOM_SNAGBOOT_MODE + select SYSRESET_PSCI if !QCOM_SNAGBOOT_MODE || !SPL select ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR select MMU_PGPROT + select SUPPORT_SPL + + select OF_LIVE + select SPL_OF_LIVE if SPL + select ARMV8_SPL_EXCEPTION_VECTORS if SPL + select ENABLE_ARM_SOC_BOOT0_HOOK if SPL + select SPL_DM if SPL + select SPL_DM_GPIO if SPL + select SPL_DM_PMIC if SPL + select SPL_DM_USB_GADGET if SPL + select SPL_ENV_SUPPORT if SPL + select SPL_EVENT if SPL + select SPL_GPIO if SPL + select SPL_HAS_BSS_LINKER_SECTION if SPL + select SPL_LIBCOMMON_SUPPORT if SPL + select SPL_LIBDISK_SUPPORT if SPL + select SPL_LIBGENERIC_SUPPORT if SPL + select SPL_OF_CONTROL if SPL + select SPL_PINCONF if SPL + select SPL_PINCTRL if SPL + select SPL_PINCTRL_FULL if SPL + select SPL_PINCTRL_GENERIC if SPL + select SPL_PINCONF_RECURSIVE if SPL + select SPL_PINMUX if SPL + select SPL_SPMI if SPL + select SPL_SPMI_MSM if SPL + select SPL_SPRINTF if SPL + select SPL_STRTO if SPL + select SPL_USB_GADGET if SPL + imply SPL_MMC if SPL imply OF_UPSTREAM imply CMD_DM imply DM_USB_GADGET diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 4609fcc9a02c..21e1da4dc4c0 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -14,6 +14,9 @@ config SYS_VENDOR config SYS_MALLOC_F_LEN default 0x2000 +config SPL_SYS_MALLOC_F + default y + config SPL_SYS_MALLOC_F_LEN default 0x2000 @@ -26,6 +29,13 @@ config LNX_KRNL_IMG_TEXT_OFFSET_BASE config REMAKE_ELF_LDSCRIPT default "arch/arm/mach-snapdragon/u-boot-elf-snapdragon.lds" +config SPL_SHARES_INIT_SP_ADDR + # override the default from common/spl/Kconfig + default n + +config SPL_HAVE_INIT_STACK + default y + config SYS_BOARD string "Snapdragon SoCs based board" help diff --git a/arch/arm/mach-snapdragon/of_fixup.c b/arch/arm/mach-snapdragon/of_fixup.c index 57f10d2f4428..4420b8fa8af6 100644 --- a/arch/arm/mach-snapdragon/of_fixup.c +++ b/arch/arm/mach-snapdragon/of_fixup.c @@ -281,7 +281,7 @@ static int qcom_of_fixup_nodes(void * __maybe_unused ctx, struct event *event) EVENT_SPY_FULL(EVT_OF_LIVE_BUILT, qcom_of_fixup_nodes); -int ft_board_setup(void *blob, struct bd_info __maybe_unused *bd) +int __weak ft_board_setup(void __maybe_unused *blob, struct bd_info __maybe_unused *bd) { struct device_node *uboot_parent_np, *uboot_node_np; int kernel_parent, ret; From 5ca4990d45797d0d6eb6a86d10ff5b9126786fe5 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:20 +0200 Subject: [PATCH 21/52] mach-snapdragon: boot0.h: add sdm845_spl_boot0.h On sdm845, running u-boot SPL in EL3 requires escalting by using an unintentional feature in old builds of xbl_sec.elf. We do this in boot0.h so the rest of U-Boot can stay blissfully unaware of XBL_SEC. If we are already in EL3 for whatever reason, the code is skipped. Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-8-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/Kconfig | 6 + arch/arm/mach-snapdragon/include/mach/boot0.h | 4 + .../include/mach/sdm845_spl_boot0.h | 121 ++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 arch/arm/mach-snapdragon/include/mach/sdm845_spl_boot0.h diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 21e1da4dc4c0..8c3e563dfa84 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -146,6 +146,12 @@ config BOOT0_MSM8916_PSCI_WORKAROUND Select this if you are building U-Boot proper for an msm8916 board that uses the buggy PSCI implementation. +config BOOT0_SDM845_WORKAROUND + bool "boot0.h workaround for SPL on the sdm845 SoC" + depends on SPL + help + Select this if you are building U-Boot SPL for sdm845. + endchoice endif diff --git a/arch/arm/mach-snapdragon/include/mach/boot0.h b/arch/arm/mach-snapdragon/include/mach/boot0.h index 99ab97881558..8fd9d3ea5d6b 100644 --- a/arch/arm/mach-snapdragon/include/mach/boot0.h +++ b/arch/arm/mach-snapdragon/include/mach/boot0.h @@ -1,7 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0+ */ #if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_BOOT0_SDM845_WORKAROUND) +#include "sdm845_spl_boot0.h" +#else b reset +#endif #else #if defined(CONFIG_BOOT0_MSM8916_PSCI_WORKAROUND) #include "msm8916_boot0.h" diff --git a/arch/arm/mach-snapdragon/include/mach/sdm845_spl_boot0.h b/arch/arm/mach-snapdragon/include/mach/sdm845_spl_boot0.h new file mode 100644 index 000000000000..11fe229ef56b --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/sdm845_spl_boot0.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Workaround for non-qcom-signed code being entered in EL1 on sdm845 + * Copyright (C) 2026 Michael Srba + * + * This code uses an unintentional ownership enhancing feature in older builds of XBL_SEC + * in order to elevate our privileges to EL3 as soon as possible after a system reset. + * This allows for a very close approximation of a clean state. + * + * Do note that you still need to own the device in the sense that you control the code that + * XBL_SEC jumps to in EL1, which is sadly not a level of ownership commonly afforded to you + * by the device manufacturer. On such devices, CVE-2021-30327 could help, but it's not documented + * and there is no PoC available utilizing it + * + */ +#include + +#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) + +#define ARM_SMCCC_SIP32_FAST_CALL \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, ARM_SMCCC_OWNER_SIP, 0) + +/* same as with qcom's TZ */ +#define QCOM_SCM_SVC_MEM_DUMP 0x03 +/* unlike the TZ counterpart, in XBL_SEC this simply unlocks the XPUs */ +#define QCOM_SCM_MEM_DUMP_UNLOCK_SECURE_REGIONS 0x10 + +/* + * We put our payload in place of some SCM call, the important thing is that it's hopefully + * in a memory region that is not in cache. + * + * It would be cleaner to just put our code at the scm entry point in the vector table, + * however it seems that we can't force cache coherency from EL1 if EL3 doesn't have + * any reason to care about that. + */ +#define QCOM_SCM_SVC_DONOR 0x01 +#define QCOM_SCM_DONOR 0x16 +/* we replace the instructions at this address with a jump to the start of u-boot */ +/* NOTE: this address is specific to a particular XBL_SEC elf */ +#define XBL_SEC_DONOR_SCM_ADDR 0x146a0ce0 + +/* gnu as doesn't implement these useful pseudoinstructions */ +.macro movq Xn, imm + movz \Xn, \imm & 0xFFFF + movk \Xn, (\imm >> 16) & 0xFFFF, lsl 16 + movk \Xn, (\imm >> 32) & 0xFFFF, lsl 32 + movk \Xn, (\imm >> 48) & 0xFFFF, lsl 48 +.endm + +.macro movl Wn, imm + movz \Wn, \imm & 0xFFFF + movk \Wn, (\imm >> 16) & 0xFFFF, lsl 16 +.endm + +/* copy 32 bits to an address from a label */ +.macro copy32 addr, text_base, addrofval, offset + movl x0, \addr + add x0, x0, \offset + movq x1, \text_base + add x1, x1, \addrofval + add x1, x1, \offset + ldr w2, [x1] + str w2, [x0] + dc cvau, x0 // flush cache to RAM straight away, we need to do it by address anyway +.endm + +.macro copy_instructions addr, text_base, start_addr, num_bytes // num_bytes must be a multiple of 4 + mov x3, #0x0 // x0, x1 and w2 used by copy32 +1: + copy32 \addr, \text_base, \start_addr, x3 + add x3, x3, #0x4 // i+=4 + cmp x3, \num_bytes + blo 1b +.endm + + /* If we're already in EL3 for some reason, skip this whole thing */ + mrs x0, CurrentEL + cmp x0, #(3 << 2) /* EL3 */ + beq reset + + /* disable the mmu */ + mrs x0, sctlr_el1 + and x0, x0, #~(1 << 0) // CTRL_M + msr sctlr_el1, x0 + + mov x0, #ARM_SMCCC_SIP32_FAST_CALL + movk x0, #SCM_SMC_FNID(QCOM_SCM_SVC_MEM_DUMP, QCOM_SCM_MEM_DUMP_UNLOCK_SECURE_REGIONS) + mov x1, #0x0 /* no params */ + mov x6, #0x0 + + smc #0 /* unlock XBL_SEC code area for writing (assuming old enough XBL_SEC build) */ + + /* this will also flush the writes from cache */ + copy_instructions XBL_SEC_DONOR_SCM_ADDR, CONFIG_SPL_TEXT_BASE, el3_payload, #((el3_payload_end - el3_payload)) + + /* this probably doesn't affect EL3, but it doesn't hurt */ + dsb ish /* block until cache is flushed */ + ic iallu /* force re-fetch of our shiny new instructions */ + dsb ish /* block until invalidation is finished */ + isb sy /* unify here ? */ + + mov x0, #ARM_SMCCC_SIP32_FAST_CALL + movk x0, #SCM_SMC_FNID(QCOM_SCM_SVC_DONOR, QCOM_SCM_DONOR) + mov x1, #0x0 /* no params */ + smc #0 /* call the payload */ + +el3_ret_point: + b reset + +el3_payload: + /* disable the mmu for EL3 too */ + mrs x0, sctlr_el3 + and x0, x0, #~(1 << 0) // CTRL_M + msr sctlr_el3, x0 + isb + + /* jump back to our code, but now in EL3 */ + movl x0, CONFIG_SPL_TEXT_BASE + add x0, x0, (el3_ret_point - _start) + br x0 +el3_payload_end: From e7d20c849a7e2dd0d83cc34e6d3ce47166bfadf1 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:21 +0200 Subject: [PATCH 22/52] mach-snapdragon: move board_usb_init to dragonboard410c.c This function is currently only really needed on db410c, move it to the board-specific .c file ahead of introducing board_spl.c to simplify things. If db410c is to ever be converted to not use board-spefific funtions, the generic solution replacing this function should probably not be Qualcomm-specific anyway. Signed-off-by: Michael Srba Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-9-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/board.c | 45 +------------------ .../dragonboard410c/dragonboard410c.c | 41 +++++++++++++++++ 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index 8cdfe206387f..801bda0a4bd8 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -10,15 +10,11 @@ #define pr_fmt(fmt) "QCOM: " fmt #include -#include #include #include #include #include -#include -#include -#include -#include +#include #include #include #include @@ -33,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -173,44 +168,6 @@ int board_fdt_blob_setup(void **fdtp) return ret; } -/* - * Some Qualcomm boards require GPIO configuration when switching USB modes. - * Support setting this configuration via pinctrl state. - */ -int board_usb_init(int index, enum usb_init_type init) -{ - struct udevice *usb; - int ret = 0; - - /* USB device */ - ret = uclass_find_device_by_seq(UCLASS_USB, index, &usb); - if (ret) { - printf("Cannot find USB device\n"); - return ret; - } - - ret = dev_read_stringlist_search(usb, "pinctrl-names", - "device"); - /* No "device" pinctrl state, so just bail */ - if (ret < 0) - return 0; - - /* Select "default" or "device" pinctrl */ - switch (init) { - case USB_INIT_HOST: - pinctrl_select_state(usb, "default"); - break; - case USB_INIT_DEVICE: - pinctrl_select_state(usb, "device"); - break; - default: - debug("Unknown usb_init_type %d\n", init); - break; - } - - return 0; -} - /* * Some boards still need board specific init code, they can implement that by * overriding this function. diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c index 36e4d49046e3..3c0d1cbb2d80 100644 --- a/board/qualcomm/dragonboard410c/dragonboard410c.c +++ b/board/qualcomm/dragonboard410c/dragonboard410c.c @@ -8,7 +8,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -19,6 +22,44 @@ #include #include +/* + * db410c requires GPIO configuration when switching USB modes. + * Support setting this configuration via pinctrl state. + */ +int board_usb_init(int index, enum usb_init_type init) +{ + struct udevice *usb; + int ret = 0; + + /* USB device */ + ret = uclass_find_device_by_seq(UCLASS_USB, index, &usb); + if (ret) { + printf("Cannot find USB device\n"); + return ret; + } + + ret = dev_read_stringlist_search(usb, "pinctrl-names", + "device"); + /* No "device" pinctrl state, so just bail */ + if (ret < 0) + return 0; + + /* Select "default" or "device" pinctrl */ + switch (init) { + case USB_INIT_HOST: + pinctrl_select_state(usb, "default"); + break; + case USB_INIT_DEVICE: + pinctrl_select_state(usb, "device"); + break; + default: + debug("Unknown usb_init_type %d\n", init); + break; + } + + return 0; +} + static u32 msm_board_serial(void) { struct mmc *mmc_dev; From c3a7e8bfe2c6b62146da5503fcc6893c42c68276 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:22 +0200 Subject: [PATCH 23/52] mach-snapdragon: add board_spl.c and split out common code Code in board.c will now only be compiled into U-Boot proper, and the new board_spl.c will only be built into SPL. Code in mem_map.c is common to both phases since it seems to not cause issues in SPL. The existing dram.c is also common to both phases with similar reasoning. In the future memory map related code should probably behave differenly in SPL, especially if dram initialization is supported. Signed-off-by: Michael Srba Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-10-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/Makefile | 10 +- arch/arm/mach-snapdragon/board.c | 263 +-------------------------- arch/arm/mach-snapdragon/board_spl.c | 30 +++ arch/arm/mach-snapdragon/mem_map.c | 226 +++++++++++++++++++++++ arch/arm/mach-snapdragon/qcom-priv.h | 2 +- 5 files changed, 274 insertions(+), 257 deletions(-) create mode 100644 arch/arm/mach-snapdragon/board_spl.c create mode 100644 arch/arm/mach-snapdragon/mem_map.c diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index 1566bbe50a1f..331212fe2616 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -2,8 +2,16 @@ # # (C) Copyright 2015 Mateusz Kulikowski -obj-y += board.o dram.o +obj-y += dram.o +obj-y += mem_map.o + +ifeq ($(CONFIG_SPL_BUILD),y) +obj-y += board_spl.o +else +obj-y += board.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o +endif + obj-$(CONFIG_QCOM_FIT_MULTIDTB) += qcom_fit_multidtb.o obj-$(CONFIG_QCOM_HWDETECT) += qcom_hwdetect.o obj-$(CONFIG_OF_LIVE) += of_fixup.o diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index 801bda0a4bd8..60b8bc935fa8 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Common initialisation for Qualcomm Snapdragon boards. + * U-Boot proper only, see mem_map.c and dram.c for parts shared with SPL * * Copyright (c) 2024 Linaro Ltd. * Author: Casey Connolly @@ -9,35 +10,28 @@ #define LOG_CATEGORY LOGC_BOARD #define pr_fmt(fmt) "QCOM: " fmt -#include -#include #include -#include #include #include -#include #include #include #include #include #include -#include #include +#include #include #include #include #include -#include #include #include #include -#include #include #include "qcom-priv.h" #include "qcom_fit_multidtb.h" -DECLARE_GLOBAL_DATA_PTR; enum qcom_boot_source qcom_boot_source __section(".data") = 0; enum qcom_memmap_source qcom_memmap_source __section(".data") = 0; @@ -48,15 +42,7 @@ enum qcom_memmap_source qcom_memmap_source __section(".data") = 0; DIV_ROUND_UP(CONFIG_EFI_PARTITION_ENTRIES_NUMBERS * GPT_ENTRY_SIZE, \ GPT_PTE_SECTOR_SIZE) -/* - * +2 for the peripheral block entry and the terminator, and another - * +CONFIG_NR_DRAM_BANKS so each inter-bank gap can get its own entry - * (see build_mem_map()). - */ -static struct mm_region rbx_mem_map[2 * CONFIG_NR_DRAM_BANKS + 2] = { { 0 } }; - -struct mm_region *mem_map = rbx_mem_map; - +#if CONFIG_IS_ENABLED(SYSRESET_PSCI) static void show_psci_version(void) { struct arm_smccc_res res; @@ -104,6 +90,7 @@ static void qcom_psci_fixup(void *fdt) if (ret) log_err("Failed to delete /psci node: %d\n", ret); } +#endif /* We support booting U-Boot with an internal DT when running as a first-stage bootloader * or for supporting quirky devices where it's easier to leave the downstream DT in place @@ -163,7 +150,9 @@ int board_fdt_blob_setup(void **fdtp) ret = 0; } +#if CONFIG_IS_ENABLED(SYSRESET_PSCI) qcom_psci_fixup(*fdtp); +#endif return ret; } @@ -180,7 +169,9 @@ void __weak qcom_board_init(void) int board_init(void) { +#if CONFIG_IS_ENABLED(SYSRESET_PSCI) show_psci_version(); +#endif /* * Default cache only covers 8 blocks, too small for the GPT * partition-entry array, so it's never cached and gets re-read @@ -486,241 +477,3 @@ int board_late_init(void) return 0; } - -static void build_mem_map(void) -{ - int i, j; - phys_addr_t prev_end; - - /* - * Ensure the peripheral block is sized to correctly cover the address range - * up to the first memory bank. - * Don't map the first page to ensure that we actually trigger an abort on a - * null pointer access rather than just hanging. - * FIXME: we should probably split this into more precise regions - */ - mem_map[0].phys = 0x1000; - mem_map[0].virt = mem_map[0].phys; - mem_map[0].size = gd->dram[0].start - mem_map[0].phys; - mem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | - PTE_BLOCK_NON_SHARE | - PTE_BLOCK_PXN | PTE_BLOCK_UXN; - - /* - * Emit each DRAM bank, plus a device-memory entry for any gap between - * it and the previous bank. Gaps are firmware-carved regions not - * reported in the SMEM usable-RAM table, so they must not be folded - * into a NORMAL/cacheable bank entry: treating them as MT_DEVICE_NGNRNE - * (matching the pre-DRAM peripheral entry above) stops speculative - * accesses instead of silently reading/caching whatever firmware left - * there. - */ - i = 1; - prev_end = gd->dram[0].start; - for (j = 0; i < ARRAY_SIZE(rbx_mem_map) - 1 && gd->dram[j].size; j++) { - if (gd->dram[j].start > prev_end) { - mem_map[i].phys = prev_end; - mem_map[i].virt = mem_map[i].phys; - mem_map[i].size = gd->dram[j].start - prev_end; - mem_map[i].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | - PTE_BLOCK_NON_SHARE | - PTE_BLOCK_PXN | PTE_BLOCK_UXN | - PTE_BLOCK_RO; - i++; - if (i >= ARRAY_SIZE(rbx_mem_map) - 1) - break; - } - - mem_map[i].phys = gd->dram[j].start; - mem_map[i].virt = mem_map[i].phys; - mem_map[i].size = gd->dram[j].size; - mem_map[i].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | \ - PTE_BLOCK_INNER_SHARE; - prev_end = gd->dram[j].start + gd->dram[j].size; - i++; - } - - mem_map[i].phys = UINT64_MAX; - mem_map[i].size = 0; - -#ifdef DEBUG - debug("Configured memory map:\n"); - for (i = 0; mem_map[i].size; i++) - debug(" 0x%016llx - 0x%016llx: entry %d\n", - mem_map[i].phys, mem_map[i].phys + mem_map[i].size, i); -#endif -} - -u64 get_page_table_size(void) -{ - return SZ_1M; -} - -struct mem_resource_attrs { - fdt_addr_t start; - fdt_addr_t size; - u64 attrs; -}; - -static int fdt_cmp_res(const void *v1, const void *v2) -{ - const struct mem_resource_attrs *res1 = v1, *res2 = v2; - - return res1->start - res2->start; -} - -#define N_RESERVED_REGIONS 256 - -/* Map and unmap reserved memory regions as appropriate. - * Mark all no-map regions as PTE_TYPE_FAULT to prevent speculative access. - * On some platforms this is enough to trigger a security violation and trap - * to EL3. - * Regions that may be accessed by drivers get mapped explicitly. - */ -static void configure_reserved_memory(void) -{ - static struct mem_resource_attrs res[N_RESERVED_REGIONS] = { 0 }; - int parent, rmem, count, i = 0; - phys_addr_t start; - size_t size; - u64 attrs; - - /* Some reserved nodes must be carved out, as the cache-prefetcher may otherwise - * attempt to access them, causing a security exception. - */ - parent = fdt_path_offset(gd->fdt_blob, "/reserved-memory"); - if (parent <= 0) { - log_err("No reserved memory regions found\n"); - return; - } - - /* Collect the reserved memory regions and appropriate attrs */ - fdt_for_each_subnode(rmem, gd->fdt_blob, parent) { - const fdt32_t *ptr; - attrs = PTE_TYPE_FAULT; - /* If the no-map property isn't set then the region is valid */ - if (!fdt_getprop(gd->fdt_blob, rmem, "no-map", NULL)) - attrs = PTE_TYPE_VALID | PTE_BLOCK_MEMTYPE(MT_NORMAL); - /* If the compatible property is set then this region may be accessed by drivers and should - * be marked valid too. */ - if (fdt_getprop(gd->fdt_blob, rmem, "compatible", NULL)) - attrs = PTE_TYPE_VALID | PTE_BLOCK_MEMTYPE(MT_NORMAL); - - if (i == N_RESERVED_REGIONS) { - log_err("Too many reserved regions!\n"); - break; - } - - /* Read the address and size out from the reg property. Doing this "properly" with - * fdt_get_resource() takes ~70ms on SDM845, but open-coding the happy path here - * takes <1ms... Oh the woes of no dcache. - */ - ptr = fdt_getprop(gd->fdt_blob, rmem, "reg", NULL); - if (ptr) { - u64 rstart, rend; - - /* Qualcomm devices use #address/size-cells = <2>. Reserved regions - * are within the 32-bit space, so the low cells hold addr/size. - */ - rstart = fdt32_to_cpu(ptr[1]); - rend = rstart + fdt32_to_cpu(ptr[3]); - - /* The MMU works at page (4K) granularity: mmu_change_region_attr_nobreak() - * cannot map a sub-page region and would spin forever on one (e.g. the - * 0x80-byte SCMI shmem mailboxes two-to-a-page at 0x87608000/0x87608180). - * Page-align every region here so we protect the pages *containing* each - * carveout. All sub-page reserved regions on Qualcomm SoCs seen so far are - * driver-accessible (VALID), so rounding the enclosing page to VALID is - * safe; a sub-page no-map (FAULT) region sharing a page with usable RAM - * would need VALID-wins precedence handling — none exist on this SoC. - */ - res[i].start = rstart & ~((u64)SZ_4K - 1); - res[i].size = ALIGN(rend, SZ_4K) - res[i].start; - res[i].attrs = attrs; - i++; - } - } - - /* Sort the reserved memory regions by address */ - count = i; - qsort(res, count, sizeof(res[0]), fdt_cmp_res); - debug("Mapping %d regions!\n", count); - - /* Now set the right attributes for them. Often a lot of the regions are tightly packed together - * so we can optimise the number of calls to mmu_change_region_attr_nobreak() by combining adjacent - * regions. - */ - start = res[0].start; - size = res[0].size; - attrs = res[0].attrs; - /* For each region after the first one, either increase the `size` to eventually be mapped or - * map the region we have and start a new one, this allows us to reduce the number of calls to - * mmu_map_region(). The loop is therefore "lagging" behind by one iteration. */ - for (i = 1; i <= count; i++) { - /* If i == count we are done, just map the last region. If the last region is - * too far away or the attrs don't match then map the meta-region we have and - * start a new one. */ - if (i == count || start + size < res[i].start - SZ_8K || attrs != res[i].attrs) { - debug(" 0x%016llx - 0x%016llx: %s\n", - start, start + size, attrs == PTE_TYPE_FAULT ? "FAULT" : "VALID"); - /* No need to break-before-make since dcache is disabled */ - mmu_change_region_attr_nobreak(start, size, attrs); - /* We have now mapped all the regions */ - if (i == count) - break; - /* Start a new meta-region */ - start = res[i].start; - size = res[i].size; - attrs = res[i].attrs; - } else { - /* This region is next to (<8K) the previous one so combine them. - * Accounting for any small (<8K) gap. */ - size = (res[i].start - start) + res[i].size; - } - } -} - -/* This function open-codes setup_all_pgtables() so that we can - * insert additional mappings *before* turning on the MMU. - */ -void enable_caches(void) -{ - u64 tlb_addr = gd->arch.tlb_addr; - u64 tlb_size = gd->arch.tlb_size; - u64 pt_size; - ulong carveout_start; - - gd->arch.tlb_fillptr = tlb_addr; - - build_mem_map(); - - icache_enable(); - - /* Create normal system page tables */ - setup_pgtables(); - - pt_size = (uintptr_t)gd->arch.tlb_fillptr - - (uintptr_t)gd->arch.tlb_addr; - debug("Primary pagetable size: %lluKiB\n", pt_size / 1024); - - /* Create emergency page tables */ - gd->arch.tlb_size -= pt_size; - gd->arch.tlb_addr = gd->arch.tlb_fillptr; - setup_pgtables(); - gd->arch.tlb_emerg = gd->arch.tlb_addr; - gd->arch.tlb_addr = tlb_addr; - gd->arch.tlb_size = tlb_size; - - /* - * On some boards speculative access may trigger a NOC or XPU violation so explicitly mark - * reserved regions as inacessible (PTE_TYPE_FAULT) - */ - if (qcom_memmap_source == QCOM_MEMMAP_SOURCE_SMEM || - fdt_node_check_compatible(gd->fdt_blob, 0, "qcom,qcs404") == 0) { - carveout_start = get_timer(0); - /* Takes ~20-50ms on SDM845 */ - configure_reserved_memory(); - debug("carveout time: %lums\n", get_timer(carveout_start)); - } - dcache_enable(); -} diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c new file mode 100644 index 000000000000..7aaa461ee74a --- /dev/null +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Common SPL code for Qualcomm Snapdragon boards. + * + * Copyright (c) 2026 Michael Srba + */ + +#include +#include + +/* in SPL, we always use internal DT */ +int board_fdt_blob_setup(void **fdtp) +{ + return -EEXIST; +} + +__weak void reset_cpu(void) +{ + /* This should currently not get called in non-error paths, so just hang */ + printf("reset_cpu called, going to hang()\n"); + hang(); +} + +u32 spl_boot_device(void) +{ + /* TODO: check boot reason to support UFS and sdcard */ + u32 boot_device = BOOT_DEVICE_DFU; + + return boot_device; +} \ No newline at end of file diff --git a/arch/arm/mach-snapdragon/mem_map.c b/arch/arm/mach-snapdragon/mem_map.c new file mode 100644 index 000000000000..17c18e5096a5 --- /dev/null +++ b/arch/arm/mach-snapdragon/mem_map.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Common initialisation for Qualcomm Snapdragon boards. + * + * Copyright (c) 2024 Linaro Ltd. + * Author: Casey Connolly + */ + +#define LOG_CATEGORY LOGC_BOARD +#define pr_fmt(fmt) "QCOM: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qcom-priv.h" + +DECLARE_GLOBAL_DATA_PTR; + +static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } }; + +struct mm_region *mem_map = rbx_mem_map; + +static void build_mem_map(void) +{ + int i, j; + + /* + * Ensure the peripheral block is sized to correctly cover the address range + * up to the first memory bank. + * Don't map the first page to ensure that we actually trigger an abort on a + * null pointer access rather than just hanging. + * FIXME: we should probably split this into more precise regions + */ + mem_map[0].phys = 0x1000; + mem_map[0].virt = mem_map[0].phys; + mem_map[0].size = gd->dram[0].start - mem_map[0].phys; + mem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN; + + for (i = 1, j = 0; i < ARRAY_SIZE(rbx_mem_map) - 1 && gd->dram[j].size; i++, j++) { + mem_map[i].phys = gd->dram[j].start; + mem_map[i].virt = mem_map[i].phys; + mem_map[i].size = gd->dram[j].size; + mem_map[i].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | \ + PTE_BLOCK_INNER_SHARE; + } + + mem_map[i].phys = UINT64_MAX; + mem_map[i].size = 0; + +#ifdef DEBUG + debug("Configured memory map:\n"); + for (i = 0; mem_map[i].size; i++) + debug(" 0x%016llx - 0x%016llx: entry %d\n", + mem_map[i].phys, mem_map[i].phys + mem_map[i].size, i); +#endif +} + +u64 get_page_table_size(void) +{ + return SZ_1M; +} + +struct mem_resource_attrs { + fdt_addr_t start; + fdt_addr_t size; + u64 attrs; +}; + +static int fdt_cmp_res(const void *v1, const void *v2) +{ + const struct mem_resource_attrs *res1 = v1, *res2 = v2; + + return res1->start - res2->start; +} + +#define N_RESERVED_REGIONS 64 + +/* Map and unmap reserved memory regions as appropriate. + * Mark all no-map regions as PTE_TYPE_FAULT to prevent speculative access. + * On some platforms this is enough to trigger a security violation and trap + * to EL3. + * Regions that may be accessed by drivers get mapped explicitly. + */ +static void configure_reserved_memory(void) +{ + static struct mem_resource_attrs res[N_RESERVED_REGIONS] = { 0 }; + int parent, rmem, count, i = 0; + phys_addr_t start; + size_t size; + u64 attrs; + + /* Some reserved nodes must be carved out, as the cache-prefetcher may otherwise + * attempt to access them, causing a security exception. + */ + parent = fdt_path_offset(gd->fdt_blob, "/reserved-memory"); + if (parent <= 0) { + log_err("No reserved memory regions found\n"); + return; + } + + /* Collect the reserved memory regions and appropriate attrs */ + fdt_for_each_subnode(rmem, gd->fdt_blob, parent) { + const fdt32_t *ptr; + attrs = PTE_TYPE_FAULT; + /* If the no-map property isn't set then the region is valid */ + if (!fdt_getprop(gd->fdt_blob, rmem, "no-map", NULL)) + attrs = PTE_TYPE_VALID | PTE_BLOCK_MEMTYPE(MT_NORMAL); + /* If the compatible property is set then this region may be accessed by drivers and should + * be marked valid too. */ + if (fdt_getprop(gd->fdt_blob, rmem, "compatible", NULL)) + attrs = PTE_TYPE_VALID | PTE_BLOCK_MEMTYPE(MT_NORMAL); + + if (i == N_RESERVED_REGIONS) { + log_err("Too many reserved regions!\n"); + break; + } + + /* Read the address and size out from the reg property. Doing this "properly" with + * fdt_get_resource() takes ~70ms on SDM845, but open-coding the happy path here + * takes <1ms... Oh the woes of no dcache. + */ + ptr = fdt_getprop(gd->fdt_blob, rmem, "reg", NULL); + if (ptr) { + /* Qualcomm devices use #address/size-cells = <2> but all reserved regions are within + * the 32-bit address space. So we can cheat here for speed. + */ + res[i].start = fdt32_to_cpu(ptr[1]); + res[i].size = fdt32_to_cpu(ptr[3]); + res[i].attrs = attrs; + i++; + } + } + + /* Sort the reserved memory regions by address */ + count = i; + qsort(res, count, sizeof(res[0]), fdt_cmp_res); + debug("Mapping %d regions!\n", count); + + /* Now set the right attributes for them. Often a lot of the regions are tightly packed together + * so we can optimise the number of calls to mmu_change_region_attr_nobreak() by combining adjacent + * regions. + */ + start = res[0].start; + size = res[0].size; + attrs = res[0].attrs; + /* For each region after the first one, either increase the `size` to eventually be mapped or + * map the region we have and start a new one, this allows us to reduce the number of calls to + * mmu_map_region(). The loop is therefore "lagging" behind by one iteration. */ + for (i = 1; i <= count; i++) { + /* If i == count we are done, just map the last region. If the last region is + * too far away or the attrs don't match then map the meta-region we have and + * start a new one. */ + if (i == count || start + size < res[i].start - SZ_8K || attrs != res[i].attrs) { + debug(" 0x%016llx - 0x%016llx: %s\n", + start, start + size, attrs == PTE_TYPE_FAULT ? "FAULT" : "VALID"); + /* No need to break-before-make since dcache is disabled */ + mmu_change_region_attr_nobreak(start, size, attrs); + /* We have now mapped all the regions */ + if (i == count) + break; + /* Start a new meta-region */ + start = res[i].start; + size = res[i].size; + attrs = res[i].attrs; + } else { + /* This region is next to (<8K) the previous one so combine them. + * Accounting for any small (<8K) gap. */ + size = (res[i].start - start) + res[i].size; + } + } +} + +/* This function open-codes setup_all_pgtables() so that we can + * insert additional mappings *before* turning on the MMU. + */ +void enable_caches(void) +{ + u64 tlb_addr = gd->arch.tlb_addr; + u64 tlb_size = gd->arch.tlb_size; + u64 pt_size; + ulong carveout_start; + + gd->arch.tlb_fillptr = tlb_addr; + + build_mem_map(); + + icache_enable(); + + /* Create normal system page tables */ + setup_pgtables(); + + pt_size = (uintptr_t)gd->arch.tlb_fillptr - + (uintptr_t)gd->arch.tlb_addr; + debug("Primary pagetable size: %lluKiB\n", pt_size / 1024); + + /* Create emergency page tables */ + gd->arch.tlb_size -= pt_size; + gd->arch.tlb_addr = gd->arch.tlb_fillptr; + setup_pgtables(); + gd->arch.tlb_emerg = gd->arch.tlb_addr; + gd->arch.tlb_addr = tlb_addr; + gd->arch.tlb_size = tlb_size; + + /* + * On some boards speculative access may trigger a NOC or XPU violation so explicitly mark + * reserved regions as inacessible (PTE_TYPE_FAULT) + */ + if (qcom_memmap_source == QCOM_MEMMAP_SOURCE_SMEM || + fdt_node_check_compatible(gd->fdt_blob, 0, "qcom,qcs404") == 0) { + carveout_start = get_timer(0); + /* Takes ~20-50ms on SDM845 */ + configure_reserved_memory(); + debug("carveout time: %lums\n", get_timer(carveout_start)); + } + dcache_enable(); +} \ No newline at end of file diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h index 39dc8fcc76ad..27e5c54e5128 100644 --- a/arch/arm/mach-snapdragon/qcom-priv.h +++ b/arch/arm/mach-snapdragon/qcom-priv.h @@ -35,7 +35,7 @@ extern enum qcom_memmap_source qcom_memmap_source; #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) void qcom_configure_capsule_updates(void); #else -void qcom_configure_capsule_updates(void) {} +static inline void qcom_configure_capsule_updates(void) {} #endif /* EFI_HAVE_CAPSULE_SUPPORT */ int qcom_parse_memory(const void *fdt, bool fdt_is_internal); From 246b6fc31c29ed9ba39c37fddc29119abf1d051e Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:23 +0200 Subject: [PATCH 24/52] qualcomm: add defconfig, env and docs for SPL on sdm845 The defconfig should in principle be board-agnostic. Environment simply contains a dfu env specifying where to load u-boot proper (TEXT_BASE - 64). Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-11-c108ebe8ff4e@seznam.cz [casey: add missing default devicetree] Signed-off-by: Casey Connolly --- board/qualcomm/sdm845_spl/sdm845_spl.env | 2 + configs/qcom_sdm845_spl_defconfig | 137 +++++++++++++++++++++++ doc/board/qualcomm/index.rst | 1 + doc/board/qualcomm/spl.rst | 91 +++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 board/qualcomm/sdm845_spl/sdm845_spl.env create mode 100644 configs/qcom_sdm845_spl_defconfig create mode 100644 doc/board/qualcomm/spl.rst diff --git a/board/qualcomm/sdm845_spl/sdm845_spl.env b/board/qualcomm/sdm845_spl/sdm845_spl.env new file mode 100644 index 000000000000..2396d003b0c0 --- /dev/null +++ b/board/qualcomm/sdm845_spl/sdm845_spl.env @@ -0,0 +1,2 @@ +# U-Boot proper text base - 64 +dfu_alt_info_ram=uboot.bin ram 0x1487FFC0 0x180000 diff --git a/configs/qcom_sdm845_spl_defconfig b/configs/qcom_sdm845_spl_defconfig new file mode 100644 index 000000000000..375647e71bae --- /dev/null +++ b/configs/qcom_sdm845_spl_defconfig @@ -0,0 +1,137 @@ +CONFIG_ARM=y +CONFIG_SKIP_LOWLEVEL_INIT=y +CONFIG_COUNTER_FREQUENCY=19200000 +CONFIG_POSITION_INDEPENDENT=y +# CONFIG_INIT_SP_RELATIVE is not set +CONFIG_ARCH_SNAPDRAGON=y +CONFIG_TEXT_BASE=0x14880000 +CONFIG_SYS_MALLOC_LEN=0x20000 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x146bffff +CONFIG_DEFAULT_DEVICE_TREE="qcom/sdm845-shift-axolotl" +CONFIG_SPL_SYS_MALLOC_F_LEN=0x20000 +CONFIG_SPL_SERIAL=y +CONFIG_SPL_DRIVERS_MISC=y +CONFIG_SPL_STACK=0x146bffff +CONFIG_SPL_TEXT_BASE=0x1483f000 +CONFIG_SPL_BSS_START_ADDR=0x14680000 +CONFIG_SPL_BSS_MAX_SIZE=0x2000 +CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_SYS_LOAD_ADDR=0x0 +CONFIG_WATCHDOG_TIMEOUT_MSECS=60000 +CONFIG_BOOT0_SDM845_WORKAROUND=y +CONFIG_SPL=y +CONFIG_SPL_PAYLOAD="u-boot.img" +CONFIG_SKIP_RELOCATE=y +# CONFIG_EFI_LOADER is not set +CONFIG_OF_BOARD_SETUP=y +CONFIG_USE_PREBOOT=y +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0xA000 +CONFIG_CONSOLE_RECORD_OUT_SIZE_F=0xA000 +CONFIG_LOGLEVEL=9 +CONFIG_SYS_STDIO_DEREGISTER=y +CONFIG_LOG_MAX_LEVEL=9 +CONFIG_SPL_LOG=y +CONFIG_SPL_LOG_MAX_LEVEL=9 +# CONFIG_DISPLAY_CPUINFO is not set +CONFIG_SPL_MAX_SIZE=0x7ffc0 +CONFIG_SPL_PAD_TO=0x0 +CONFIG_SPL_REMAKE_ELF_LDSCRIPT="board/qualcomm/sdm845_spl/u-boot-spl-elf-sdm845.lds" +CONFIG_SPL_DMA=y +CONFIG_SPL_REMAKE_ELF=y +CONFIG_SPL_DM_RESET=y +CONFIG_SPL_POWER_DOMAIN=y +CONFIG_BOOTM_NETBSD=y +CONFIG_CMD_CLK=y +CONFIG_CMD_DFU=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_UFS=y +CONFIG_CMD_CAT=y +CONFIG_CMD_RNG=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_LOG=y +CONFIG_OF_UPSTREAM_BUILD_VENDOR=y +CONFIG_ENV_USE_DEFAULT_ENV_TEXT_FILE=y +CONFIG_ENV_DEFAULT_ENV_TEXT_FILE="board/qualcomm/sdm845_spl/sdm845_spl.env" +CONFIG_NET_RANDOM_ETHADDR=y +# CONFIG_OFNODE_MULTI_TREE is not set +CONFIG_BUTTON_QCOM_PMIC=y +CONFIG_CLK=y +CONFIG_SPL_CLK=y +CONFIG_CLK_STUB=y +CONFIG_SPL_CLK_STUB=y +CONFIG_CLK_QCOM_SDM845=y +CONFIG_DFU_MMC=y +CONFIG_DFU_RAM=y +CONFIG_DFU_SCSI=y +CONFIG_SYS_DFU_DATA_BUF_SIZE=0x5000 +CONFIG_DMA=y +CONFIG_DMA_CHANNELS=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0xdeadbeef +CONFIG_MSM_GPIO=y +CONFIG_QCOM_PMIC_GPIO=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_QUP=y +CONFIG_I2C_MUX=y +CONFIG_IOMMU=y +CONFIG_QCOM_HYP_SMMU=y +CONFIG_MISC=y +CONFIG_NVMEM=y +CONFIG_I2C_EEPROM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ADMA=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_DM_ETH_PHY=y +CONFIG_PHY=y +CONFIG_SPL_PHY=y +CONFIG_PHY_QCOM_QMP_UFS=y +CONFIG_PHY_QCOM_QUSB2=y +CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y +CONFIG_PHY_QCOM_SNPS_EUSB2=y +CONFIG_PHY_QCOM_USB_HS_28NM=y +CONFIG_PHY_QCOM_USB_SS=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_QCOM_APQ8016=y +CONFIG_PINCTRL_QCOM_APQ8096=y +CONFIG_PINCTRL_QCOM_QCM2290=y +CONFIG_PINCTRL_QCOM_QCS404=y +CONFIG_PINCTRL_QCOM_SDM845=y +CONFIG_PINCTRL_QCOM_SM6115=y +CONFIG_PINCTRL_QCOM_SM8250=y +CONFIG_PINCTRL_QCOM_SM8550=y +CONFIG_PINCTRL_QCOM_SM8650=y +CONFIG_PINCTRL_QCOM_X1E80100=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_QCOM=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_QCOM_RPMH=y +CONFIG_DM_RNG=y +CONFIG_RNG_MSM=y +CONFIG_SCSI=y +CONFIG_MSM_SERIAL=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_RPMH=y +CONFIG_SPMI_MSM=y +CONFIG_SYSINFO=y +CONFIG_SYSINFO_SMBIOS=y +CONFIG_SYSRESET_QCOM_PSHOLD=y +CONFIG_USB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_GENERIC=y +CONFIG_SPL_USB_DWC3_GENERIC=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VENDOR_NUM=0x0525 +CONFIG_USB_GADGET_PRODUCT_NUM=0xb4a4 +CONFIG_USB_ETHER=y +CONFIG_USB_ETH_CDC=y +CONFIG_SPL_DFU=y +CONFIG_SPL_USB_SDP_SUPPORT=y +CONFIG_UFS=y +# CONFIG_SPL_USE_TINY_PRINTF is not set +CONFIG_CIRCBUF=y diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst index b7ab843b4c47..5ef4be8483f7 100644 --- a/doc/board/qualcomm/index.rst +++ b/doc/board/qualcomm/index.rst @@ -16,6 +16,7 @@ Qualcomm rdp signing snagboot + spl See also -------- diff --git a/doc/board/qualcomm/spl.rst b/doc/board/qualcomm/spl.rst new file mode 100644 index 000000000000..7d333194949f --- /dev/null +++ b/doc/board/qualcomm/spl.rst @@ -0,0 +1,91 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. sectionauthor:: Michael Srba + +=================================== +Booting U-Boot SPL on Qualcomm SoCs +=================================== + +Overview +-------- +The boot process on sdm845 (and some other Qualcomm SoCs) starts with the bootrom +of the Application Processor, which executes XBL_SEC, which jumps to "OEM" code +in EL1. Production devices are typically "fused", with a hash of the OEM's signing +key burnt into one of the "QFUSE" banks on the SoC making it impossible to run +custom bootloader code. As a result U-Boot SPL is only supported on unfused +("secureboot off") devices. XBL_SEC is always signed by Qualcomm, and the fuses +to disable turning off signature verification for it are always burnt at the +factory, so replacing XBL_SEC is impossible without using JTAG. Of course JTAG +is typically disabled on devices that have secure boot enabled, or at minimum +greatly neutered. + +U-Boot SPL for Qualcomm platforms uses a custom linker script (per SoC) to build a bootable ELF. +For sdm845 (and some other platforms) this has two sections, u-boot code and an embedded +xbl_sec elf (signed by Qualcomm). To boot on an unfused SoC, the elf additionally +needs to have hash sections added, which can be accomplished with qtestsign. + +Currently, sdm845 is supported. You need a device with secure boot disabled +(or with secure boot enabled if you enabled it yourself and have the private key, +though for full security you'd also want to disable JTAG which will remove your ability +to mess with the control flow in the bootrom (immutable) and in XBL_SEC (signed)). + +Building +-------- +First, obtain an xbl_sec that includes the EL3 privilege escalation feature +and place it at .output/xbl_sec.elf. You can extract it from an xbl elf. +If you're unable to find one, you can also use JTAG/SWD to break at the SMC +entry and use gdb to jump to the u-boot entry point in EL3. + +To build a bootable image, you need to use a defconfig specific to your SoC. +This is because the ELF has to specify where in the address space to put u-boot SPL, +and this may differ per SoC. There may be other SoC-dependent build time choices, +though in principle those could be made at runtime. + +First run ``make qcom_sdm845_spl_defconfig``:: + + make CROSS_COMPILE=aarch64-suse-linux- O=.output DEVICE_TREE=qcom/sdm845-shift-axolotl qcom_sdm845_spl_defconfig + +Then compile u-boot and specify the dts for your board (technically nothing about the resulting +SPL image should be board-specific, but there are no non-board-specific device trees in Linux):: + + make CROSS_COMPILE=aarch64-suse-linux- O=.output DEVICE_TREE=qcom/sdm845-shift-axolotl + +Finally, use ``qtestsign`` to add the hash segments required by PBL:: + + qtestsign -v 5 -o .output/spl/u-boot-spl_signed.elf prog .output/spl/u-boot-spl.elf + +Running +------- +Currently, U-Boot SPL for Qualcomm platforms expects to be booted via EDL:: + + edl.py --loader=$PWD/.output/spl/u-boot-spl_signed.elf + +SPL will then launch the DFU gadget and wait for you to upload u-boot proper:: + + dfu-util -RD .output/u-boot.img + +u-boot proper will then likely crash, since SPL currently doesn't init DRAM on Qualcomm platforms +and u-boot proper currently doesn't support running from SRAM. The latter should be an easy fix. + +Notes on memory map +------------------- +| There are various banks of SRAM on a Qualcomm SoC that we can use prior to DRAM init. +| For example: +| msm8916 - 512K L2-as-TCM (at ``0x08000000``), 16K OCIMEM (at ``0x08600000``) +| msm8998 - 1M L2-as-TCM (at ``0x14000000``), 256K OCIMEM (at ``0x14680000``) +| sdm845 - 1.5M BOOT_IMEM (at ``0x14800000``), 256K OCIMEM (at ``0x14680000``) + +There's also RPM code/data RAM and hexagon TCMs, but unless we want to boot dram-less Linux +we can probably safely ignore those. On msm8916 they may come in handy though. + +sdm845 can also have 8M LLCC-as-TCM in theory, but this appears to be broken. +L2-as-TCM is no longer present. + +Since a limited amount of not necessarily continuous SRAM is available, we need to manually +specify where .text, .bss, the malloc pool and the stack go. The Kconfig contains reasonable +defaults per SoC. + +On sdm845, we by default put U-Boot SPL in BOOT_IMEM, with .bss, malloc pool and the stack +filling OCIMEM. We can also fit U-Boot proper in BOOT_IMEM, for dram-less DFU or peek/poke +with a shell. To that end, we set ``CONFIG_TEXT_BASE`` at 512K into BOOT_IMEM, and set +``CONFIG_SPL_MAX_SIZE`` to 512K - 64. We also configure dfu to load U-Boot proper +to ``CONFIG_TEXT_BASE`` - 64. (64 bytes is the size of u-boot legacy header) From ea50dba888b12c7a7b3c01507e48db7aa37fa023 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:24 +0200 Subject: [PATCH 25/52] dts: add u-boot specific sdm845 .dtsi and a .dtsi for shift-axolotl The board .dtsi just includes the SoC-specific .dtsi, which adds bootph-all markings to upstream dts nodes which are needed in SPL. Signed-off-by: Michael Srba Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260521-qcom_spl-v9-12-c108ebe8ff4e@seznam.cz Signed-off-by: Casey Connolly --- arch/arm/dts/sdm845-shift-axolotl-u-boot.dtsi | 2 ++ arch/arm/dts/sdm845-u-boot.dtsi | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 arch/arm/dts/sdm845-shift-axolotl-u-boot.dtsi create mode 100644 arch/arm/dts/sdm845-u-boot.dtsi diff --git a/arch/arm/dts/sdm845-shift-axolotl-u-boot.dtsi b/arch/arm/dts/sdm845-shift-axolotl-u-boot.dtsi new file mode 100644 index 000000000000..d41210ab23a2 --- /dev/null +++ b/arch/arm/dts/sdm845-shift-axolotl-u-boot.dtsi @@ -0,0 +1,2 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "sdm845-u-boot.dtsi" diff --git a/arch/arm/dts/sdm845-u-boot.dtsi b/arch/arm/dts/sdm845-u-boot.dtsi new file mode 100644 index 000000000000..b029264555b9 --- /dev/null +++ b/arch/arm/dts/sdm845-u-boot.dtsi @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +&gcc { + bootph-all; +}; + +&usb_1_hsphy { + bootph-all; +}; + +&usb_1_dwc3 { + bootph-all; +}; + +&rpmhcc { + bootph-all; +}; From da54e12c756ae3a4f7833cbf976cba046a12e4d7 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 14:15:51 +0530 Subject: [PATCH 26/52] misc: qcom_geni: Add minicore support The qcom_geni driver reads an ELF from storage and configures a set of registers and programs the firmware to the GENI Serial Engine (GENI-SE) wrapper device for the expected functionality. Unlike the GENI-SE wrapper found in MSM SoCs, the IPQ5210's GENI-SE wrapper is pre-configured for one of the functions defined in 'enum geni_se_protocol_type'. Hence, the firmware download is not needed. Only the register configuration part is needed. Earlier, the boot stages before U-Boot would configure the GENI-SE (to access UART/SPI etc). Since for IPQ5210 U-Boot SPL, the previous stage (i.e. boot ROM) doesn't do that modify the driver to do the register configuration part alone without reading an ELF from the storage. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- drivers/misc/Kconfig | 5 ++ drivers/misc/Makefile | 2 + drivers/misc/qcom_geni-minicore.c | 103 ++++++++++++++++++++++++++++++ drivers/misc/qcom_geni.c | 85 ++++++++++++++++++++---- include/soc/qcom/geni-se.h | 5 ++ include/soc/qcom/minicore.h | 25 ++++++++ include/soc/qcom/qup-fw-load.h | 1 + 7 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 drivers/misc/qcom_geni-minicore.c create mode 100644 include/soc/qcom/minicore.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 68a4c5d60766..baba41ee2517 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -119,6 +119,11 @@ config SPL_QCOM_GENI Enable support for Qualcomm GENI and it's peripherals in SPL. GENI is responseible for providing a common interface for various peripherals like UART, I2C, SPI, etc. +config QCOM_GENI_MINICORE + bool "Support minicores in Qualcomm Generic Interface (GENI) driver" + depends on QCOM_GENI + help + Enable support for minicores in Qualcomm GENI and its peripherals. config ROCKCHIP_EFUSE bool "Rockchip e-fuse support" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c1fb958261ed..49466d93f53e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -68,6 +68,8 @@ endif obj-$(CONFIG_QCOM_SPMI_SDAM) += qcom-spmi-sdam.o obj-$(CONFIG_$(PHASE_)QCOM_GENI) += qcom_geni.o obj-$(CONFIG_$(PHASE_)QCOM_HWINFO) += qcom_hwinfo.o +obj-$(CONFIG_QCOM_GENI) += qcom_geni.o +obj-$(CONFIG_QCOM_GENI_MINICORE) += qcom_geni-minicore.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o diff --git a/drivers/misc/qcom_geni-minicore.c b/drivers/misc/qcom_geni-minicore.c new file mode 100644 index 000000000000..12c57bdd8b24 --- /dev/null +++ b/drivers/misc/qcom_geni-minicore.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include + +/* + * Register configuration for the QUP minicores to setup the corresponding + * functionality of SPI/I2C/UART. + */ +static u8 cfg_reg_idx[] = { + /* 0 to 18 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + /* 64 to 113 */ + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, +}; + +static u32 spi_cfg_val[] = { + /* 0 to 18 */ + 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00240E78, 0x00011088, + 0x00240007, 0x00000000, 0x00000000, 0x0001000A, 0x00000300, 0x00000000, + 0x00000000, 0x00000000, 0x00154400, 0x001483A0, 0x00AA8128, 0x00641002, + 0x00004000, + /* 64 to 113 */ + 0x00000201, 0x0001FE05, 0x0002C2E7, 0x0A435C00, 0x0010011A, 0x08800000, + 0x00000000, 0x100CAC00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000018E4, 0x00000000, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0007F807, 0x000FFEFE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00200000, 0x00000004, 0x00000009, 0x0007F807, 0x000FFEFE, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00C0033F, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000055, +}; + +static u32 uart_cfg_val[] = { + /* 0 to 18 */ + 0x00000024, 0x00000000, 0x00000024, 0x00000000, 0x00019A00, 0x00400000, + 0x00E00000, 0x00010020, 0x00000000, 0x00000000, 0x00000300, 0x00000700, + 0x00000400, 0x00000000, 0x00000000, 0x00C00000, 0x00000000, 0x00C00024, + 0x00000B00, + /* 64 to 113 */ + 0x00020231, 0x0000CE05, 0x000360E7, 0x0941E6A8, 0x00100510, 0x42C01E51, + 0x00000401, 0x002E8400, 0x1694581A, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x0000031C, 0x00000000, + 0x0000000F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00081C06, 0x00004010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0000000D, 0x00000000, 0x00081C06, 0x00004010, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00C02415, 0x0000000E, 0x00000001, + 0x00000001, 0x00000000, 0x00C00000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000055, +}; + +static u32 i2c_cfg_val[] = { + /* 0 to 18 */ + 0x00000090, 0x00000000, 0x00000090, 0x00000000, 0x00038028, 0x00084080, + 0x00000343, 0x00010000, 0x00000000, 0x00001A00, 0x00000100, 0x00000000, + 0x00000000, 0x00000000, 0x00808008, 0x001C0020, 0x00000000, 0x00020000, + 0x00000000, + /* 64 to 113 */ + 0x00000201, 0x0001FC01, 0x00036222, 0x09C01FFC, 0x00100120, 0x02C00000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000409, 0x00000003, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0007F8FE, 0x000FFEFE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x0007F807, 0x000FFEFE, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00C00000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000055, +}; + +struct qup_mini_core_info qup_mini_cores[] = { + { + .serial_protocol = GENI_SE_SPI, + .fw_version = 0xb02, + .cfg_version = 0x9, + .cfg_count = ARRAY_SIZE(spi_cfg_val), + .cfg_val = spi_cfg_val, + .cfg_idx = cfg_reg_idx, + }, { + .serial_protocol = GENI_SE_UART, + .fw_version = 0x405, + .cfg_version = 0xa, + .cfg_count = ARRAY_SIZE(uart_cfg_val), + .cfg_val = uart_cfg_val, + .cfg_idx = cfg_reg_idx, + }, { + .serial_protocol = GENI_SE_I2C, + .fw_version = 0x204, + .cfg_version = 0x9, + .cfg_count = ARRAY_SIZE(i2c_cfg_val), + .cfg_val = i2c_cfg_val, + .cfg_idx = cfg_reg_idx, + }, { + .serial_protocol = GENI_SE_INVALID_PROTO, + }, +}; diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c index a62ae6a2478f..f3133f858858 100644 --- a/drivers/misc/qcom_geni.c +++ b/drivers/misc/qcom_geni.c @@ -21,6 +21,7 @@ #include #include #include +#include #include struct qup_se_rsc { @@ -34,8 +35,11 @@ struct qup_se_rsc { struct geni_se_plat { bool need_firmware_load; + bool is_mini_core; }; +static int qcom_geni_fw_initialise(void); + /** * geni_enable_interrupts() Enable interrupts. * @rsc: Pointer to a structure representing SE-related resources. @@ -163,16 +167,54 @@ static void geni_config_common_control(struct qup_se_rsc *rsc) COMMON_CSR_SLV_CLK_CGC_ON_BMASK); } -static int load_se_firmware(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr) +static int load_se_firmware(struct qup_se_rsc *rsc, bool elf, void *info) { + struct geni_se_plat *plat = dev_get_plat(rsc->dev->parent); + struct elf_se_hdr *hdr, tmp_hdr; const u32 *fw_val_arr, *cfg_val_arr; const u8 *cfg_idx_arr; u32 i, reg_value, mask, ramn_cnt; int ret; - fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset); - cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset; - cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset); + if (elf) { + hdr = info; + fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset); + cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset; + cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset); + } else if (plat->is_mini_core) { + /* + * Minicore controllers come with pre-configured functionality + * and don't need a firmware download and just need the register + * configuration. Hence, skipping the firmware part and setting + * up just the register configuration related information. + */ + struct qup_mini_core_info *qmc = info; + + for (; qmc->serial_protocol != GENI_SE_INVALID_PROTO; qmc++) + if (qmc->serial_protocol == rsc->protocol) + break; + + if (qmc->serial_protocol == GENI_SE_INVALID_PROTO) { + dev_err(rsc->dev, "Invalid MINICORE protocol (%d)\n", + rsc->protocol); + return -EINVAL; + } + + tmp_hdr.magic = MAGIC_NUM_SE; + tmp_hdr.version = 1; + tmp_hdr.serial_protocol = rsc->protocol; + tmp_hdr.fw_version = qmc->fw_version; + tmp_hdr.cfg_version = qmc->cfg_version; + tmp_hdr.fw_size_in_items = qmc->cfg_ram_count; + tmp_hdr.cfg_size_in_items = qmc->cfg_count; + hdr = &tmp_hdr; + fw_val_arr = (const u32 *)qmc->cfg_ram; + cfg_idx_arr = (const u8 *)qmc->cfg_idx; + cfg_val_arr = (const u32 *)qmc->cfg_val; + } else { + dev_err(rsc->dev, "Neither fw nor register settings found\n"); + return -EINVAL; + } geni_config_common_control(rsc); @@ -350,8 +392,9 @@ int qcom_geni_load_firmware(phys_addr_t qup_base, { struct qup_se_rsc rsc; struct elf_se_hdr *hdr; + bool elf; int ret; - void *fw; + void *fw, *info; rsc.dev = dev; rsc.base = qup_base; @@ -377,15 +420,26 @@ int qcom_geni_load_firmware(phys_addr_t qup_base, /* The firmware blob is the private data of the GENI wrapper (parent) */ fw = dev_get_priv(dev->parent); - ret = read_elf(&rsc, fw, &hdr); - if (ret) { - dev_err(dev, "Failed to read ELF: %d\n", ret); - return ret; + if (IS_ELF(*(Elf32_Ehdr *)fw)) { + ret = read_elf(&rsc, fw, &hdr); + if (ret) { + dev_err(dev, "Failed to read ELF: %d\n", ret); + return ret; + } + elf = true; + info = hdr; + } else { + elf = false; + info = fw; + if (!IS_ENABLED(CONFIG_QCOM_GENI_MINICORE)) { + dev_err(dev, "Error: f/w ELF not found and minicore support disabled\n"); + return -EINVAL; + } } dev_info(dev, "Loading QUP firmware...\n"); - return load_se_firmware(&rsc, hdr); + return load_se_firmware(&rsc, elf, info); } /* @@ -414,6 +468,9 @@ static int geni_se_of_to_plat(struct udevice *dev) if (proto == GENI_SE_INVALID_PROTO) plat->need_firmware_load = true; + + if (readl(res.start + SE_HW_PARAM_2) & GENI_USE_MINICORES) + plat->is_mini_core = true; } return 0; @@ -473,7 +530,7 @@ static int probe_children_load_firmware(struct udevice *dev) ret = 0; /* Find the device for this ofnode, or bind it */ if (device_find_global_by_ofnode(child, &child_dev)) - ret = lists_bind_fdt(dev, child, &child_dev, NULL, false); + ret = lists_bind_fdt(dev, child, &child_dev, NULL, false); if (ret) { /* Skip nodes that don't have drivers */ debug("Failed to probe child %s: %d\n", ofnode_get_name(child), ret); @@ -518,6 +575,11 @@ static int qcom_geni_fw_initialise(void) return 0; } + if (plat->is_mini_core) { + fw_buf = qup_mini_cores; + goto mini_core; + } + ret = find_qupfw_part(&blk_dev, &part_info); if (ret) { pr_err("QUP firmware partition not found\n"); @@ -544,6 +606,7 @@ static int qcom_geni_fw_initialise(void) return 0; } +mini_core: /* * OK! Firmware is loaded, now bind and probe remaining children. They will attempt to load * firmware during probe. Do this for each GENI SE wrapper that needs firmware loading. diff --git a/include/soc/qcom/geni-se.h b/include/soc/qcom/geni-se.h index fc9a8e82cd88..3063b37010de 100644 --- a/include/soc/qcom/geni-se.h +++ b/include/soc/qcom/geni-se.h @@ -77,8 +77,12 @@ enum geni_se_protocol_type { #define SE_IRQ_EN 0xe1c #define SE_HW_PARAM_0 0xe24 #define SE_HW_PARAM_1 0xe28 +#define SE_HW_PARAM_2 0xe2c #define SE_DMA_GENERAL_CFG 0xe30 +/* SE_HW_PARAM_2 fields */ +#define GENI_USE_MINICORES BIT(12) + /* GENI_DFS_IF_CFG fields */ #define DFS_IF_EN BIT(0) @@ -248,6 +252,7 @@ enum geni_se_protocol_type { /* SE_HW_PARAM_0 fields */ #define TX_FIFO_WIDTH_MSK GENMASK(29, 24) #define TX_FIFO_WIDTH_SHFT 24 + /* * For QUP HW Version >= 3.10 Tx fifo depth support is increased * to 256bytes and corresponding bits are 16 to 23 diff --git a/include/soc/qcom/minicore.h b/include/soc/qcom/minicore.h new file mode 100644 index 000000000000..9f2071ed86ba --- /dev/null +++ b/include/soc/qcom/minicore.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef _SOC_QCOM_MINI_CORE +#define _SOC_QCOM_MINI_CORE + +struct qup_mini_core_info { + u16 serial_protocol; + u16 fw_version; + u16 cfg_version; + u16 cfg_count; + u32 *cfg_val; + u8 *cfg_idx; + u32 *cfg_ram; + u32 cfg_ram_count; +}; + +#if IS_ENABLED(CONFIG_QCOM_GENI_MINICORE) +extern struct qup_mini_core_info qup_mini_cores[]; +#else +struct qup_mini_core_info *qup_mini_cores; +#endif + +#endif /* _SOC_QCOM_MINI_CORE */ diff --git a/include/soc/qcom/qup-fw-load.h b/include/soc/qcom/qup-fw-load.h index a67a93c72a4b..df8a615b46bf 100644 --- a/include/soc/qcom/qup-fw-load.h +++ b/include/soc/qcom/qup-fw-load.h @@ -14,6 +14,7 @@ #define GENI_INIT_CFG_REVISION 0x0 #define GENI_S_INIT_CFG_REVISION 0x4 #define GENI_FORCE_DEFAULT_REG 0x20 +#define GENI_OUTPUT_CTRL 0x24 #define GENI_CGC_CTRL 0x28 #define GENI_CFG_REG0 0x100 From 57ff847f21f3168a16854ce33f05ee4570b9059b Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 14:49:18 +0530 Subject: [PATCH 27/52] mach-snapdragon: Kconfig: Auto select options based on configs The commit d38787bb5dafa ("mach-snapdragon: Kconfig: changes / additions to support SPL") auto selects options that may not be applicable to all platforms. This results in warning messages during make xxx_defconfig and/or waiting for user input for on/off or values for certain configs. So auto select options based on the enabled configs in xxx_defconfig. Fixes: d38787bb5dafa ("mach-snapdragon: Kconfig: changes / additions to support SPL") Signed-off-by: Varadarajan Narayanan --- arch/arm/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 725ca04f3b3f..736a83acf13a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1147,8 +1147,8 @@ config ARCH_SNAPDRAGON select SPMI select BOARD_LATE_INIT select OF_BOARD - select SAVE_PREV_BL_FDT_ADDR if !ENABLE_ARM_SOC_BOOT0_HOOK - select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK + select SAVE_PREV_BL_FDT_ADDR if !ENABLE_ARM_SOC_BOOT0_HOOK && !SPL + select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK && !SPL select SYSRESET select SYSRESET_PSCI if !QCOM_SNAGBOOT_MODE || !SPL select ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR @@ -1161,12 +1161,12 @@ config ARCH_SNAPDRAGON select ENABLE_ARM_SOC_BOOT0_HOOK if SPL select SPL_DM if SPL select SPL_DM_GPIO if SPL - select SPL_DM_PMIC if SPL - select SPL_DM_USB_GADGET if SPL + select SPL_DM_PMIC if SPL && DM_PMIC + select SPL_DM_USB_GADGET if SPL && USB select SPL_ENV_SUPPORT if SPL select SPL_EVENT if SPL select SPL_GPIO if SPL - select SPL_HAS_BSS_LINKER_SECTION if SPL + select SPL_HAS_BSS_LINKER_SECTION if SPL && SPL_SEPARATE_BSS select SPL_LIBCOMMON_SUPPORT if SPL select SPL_LIBDISK_SUPPORT if SPL select SPL_LIBGENERIC_SUPPORT if SPL @@ -1181,7 +1181,7 @@ config ARCH_SNAPDRAGON select SPL_SPMI_MSM if SPL select SPL_SPRINTF if SPL select SPL_STRTO if SPL - select SPL_USB_GADGET if SPL + select SPL_USB_GADGET if SPL && USB imply SPL_MMC if SPL imply OF_UPSTREAM imply CMD_DM From 2cbd836982d5d42315ae7cc61f79a16bfbefc1d3 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Tue, 30 Jun 2026 13:38:27 +0530 Subject: [PATCH 28/52] mach-snapdragon: Add PBL shared data defines Add structure and enum definitions to be able to parse the information that is passed from PBL. This will be used to identify the boot medium. Since the PBL shared data defines are private, move spl_boot_device() from board_spl.c to pbl-shared-data.c to parse the shared data and identify the boot medium Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/Makefile | 1 + arch/arm/mach-snapdragon/board_spl.c | 9 +- arch/arm/mach-snapdragon/pbl-shared-data.c | 125 +++++++++++++++++++++ 3 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-snapdragon/pbl-shared-data.c diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index 331212fe2616..a8f662e56ecc 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -7,6 +7,7 @@ obj-y += mem_map.o ifeq ($(CONFIG_SPL_BUILD),y) obj-y += board_spl.o +obj-y += pbl-shared-data.o else obj-y += board.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 7aaa461ee74a..660450943cea 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -7,6 +7,7 @@ #include #include +#include /* in SPL, we always use internal DT */ int board_fdt_blob_setup(void **fdtp) @@ -19,12 +20,4 @@ __weak void reset_cpu(void) /* This should currently not get called in non-error paths, so just hang */ printf("reset_cpu called, going to hang()\n"); hang(); -} - -u32 spl_boot_device(void) -{ - /* TODO: check boot reason to support UFS and sdcard */ - u32 boot_device = BOOT_DEVICE_DFU; - - return boot_device; } \ No newline at end of file diff --git a/arch/arm/mach-snapdragon/pbl-shared-data.c b/arch/arm/mach-snapdragon/pbl-shared-data.c new file mode 100644 index 000000000000..b9dce22c4171 --- /dev/null +++ b/arch/arm/mach-snapdragon/pbl-shared-data.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +enum pbl_shared_data_param_id { + PSD_ID_PBL_FW_VERSION = 0x0, /* PBL firmware version */ + PSD_ID_PBL_PATCH_VERSION = 0x1, /* Patch version */ + PSD_ID_RMB_MBOX_BASE_ADDR = 0x2, /* Not used */ + PSD_ID_CPU_BOOT_SPEED_HZ = 0x3, /* CPU boot speed (Hz) */ + PSD_ID_BOOT_MEDIA_TYPE = 0x4, /* Boot media type */ + PSD_ID_IS_EDL_MODE = 0x5, /* Emergency Download mode */ + PSD_ID_DEV_PROG_ELF_ENTRY_ADDR = 0x6, /* Not used */ + PSD_ID_XBL_CONFIG_ELF_ENTRY_ADDR = 0x7, /* Not used */ + PSD_ID_XBL_SC_EXT_ELF_ENTRY_ADDR = 0x8, /* Not used */ + PSD_ID_PBL_TIMESTAMPS_BUFFER_ADDR = 0x9, /* PBL logs address */ + PSD_ID_PBL_TIMESTAMPS_BUFFER_SIZE = 0xa, /* PBL log size */ + PSD_ID_PBL_DEBUG_SHARED_INFO_ADDR = 0xb, /* Debug info address */ + PSD_ID_PBL_DEBUG_SHARED_INFO_SIZE = 0xc, /* Debug info size */ + PSD_ID_TME_CPU_PBL_ROM_BYPASS_FUSE = 0xd, /* Secure boot status */ + PSD_ID_XBL_SC_DEBUG_LOG_ADDR = 0xe, /* XBL SC debug log address */ + PSD_ID_XBL_SC_DEBUG_LOG_SIZE = 0xf, /* XBL SC debug log size */ + PSD_ID_CURRENT_IMAGE_SET = 0x10, /* Booted image set */ + PSD_ID_MEDIA_DATA_INFO_ADDR = 0x11, /* Media info pointer */ + PSD_ID_MEDIA_DATA_INFO_SIZE = 0x12, /* Media info size */ + PBL_SHARED_DATA_PARAM_MAX, +}; + +enum pbl_boot_flash_type { + PSD_NO_FLASH = 0, + PSD_NOR_FLASH = 1, + PSD_NAND_FLASH = 2, + PSD_ONENAND_FLASH = 3, + PSD_SDC_FLASH = 4, + PSD_MMC_FLASH = 5, + PSD_SPI_FLASH = 6, + PSD_PCIE_FLASH = 7, + PSD_UFS_FLASH = 8, + PSD_RSVD_1_FLASH = 9, + PSD_USB_FLASH = 10, + PSD_SPI_NAND_FLASH = 11, + PSD_SPI_FLASH_GPT = 12, +}; + +enum pbl_shared_data_version { + PSD_VERSION_1 = 0x00010000, // IPQ 5332, 9574 + PSD_VERSION_2 = 0x00020000, // IPQ 5210, 5424, 5610, 9650 +}; + +struct pbl_shared_data_entry { + u32 param_id; + ulong value; + bool valid; +}; + +struct pbl_shared_data { + u32 version; + u32 num_of_entries; + struct pbl_shared_data_entry entry[PBL_SHARED_DATA_PARAM_MAX]; +}; + +static struct pbl_shared_data g_psd __section(".data"); + +void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3) +{ + unsigned long sctlr; + struct pbl_shared_data *psd; + + sctlr = get_sctlr(); + set_sctlr(sctlr & ~(CR_M)); /* Disable MMU */ + + psd = (struct pbl_shared_data *)r0; + + if (!psd || psd->num_of_entries < PBL_SHARED_DATA_PARAM_MAX || + psd->version != PSD_VERSION_2) + goto out; + + memcpy(&g_psd, psd, sizeof(g_psd)); + +out: + save_boot_params_ret(); +} + +u32 __weak spl_boot_device(void) +{ + struct pbl_shared_data *psd = &g_psd; + +#ifdef DEBUG + for (int i = 0; psd && i < psd->num_of_entries; i++) { + printf("entry[0x%x] = %d 0x%08x %d\n", i, + psd->entry[i].param_id, psd->entry[i].value, + psd->entry[i].valid); + } +#endif + if (psd->version != PSD_VERSION_2) { + pr_err("Unknown PBL shared data version\n"); + goto out; + } + + if (psd->entry[PSD_ID_IS_EDL_MODE].valid && + psd->entry[PSD_ID_IS_EDL_MODE].value) { + printf("Selected boot device: DFU\n"); + return BOOT_DEVICE_DFU; + } + + if (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].valid) { + switch (psd->entry[PSD_ID_BOOT_MEDIA_TYPE].value) { + case PSD_MMC_FLASH: + printf("Selected boot device: MMC\n"); + return BOOT_DEVICE_MMC1; + case PSD_NOR_FLASH: + printf("Selected boot device: NOR\n"); + return BOOT_DEVICE_NOR; + case PSD_NAND_FLASH: + printf("Selected boot device: NAND\n"); + return BOOT_DEVICE_NAND; + case PSD_UFS_FLASH: + printf("Selected boot device: UFS\n"); + return BOOT_DEVICE_UFS; + } + } + +out: + pr_err("No boot device configured\n"); + return BOOT_DEVICE_NONE; +} From 54bac9aec3a1c2afb44ead81ce219de067aeb271 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 15:20:08 +0530 Subject: [PATCH 29/52] mach-snapdragon: spl: Update boot device information in SMEM Update the SMEM with the boot device information got from the boot rom. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/board_spl.c | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 660450943cea..460d07ef0a36 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -20,4 +20,46 @@ __weak void reset_cpu(void) /* This should currently not get called in non-error paths, so just hang */ printf("reset_cpu called, going to hang()\n"); hang(); -} \ No newline at end of file +} + +#if IS_ENABLED(CONFIG_SPL_SMEM) +/** + * qcom_spl_populate_smem() - Populate shared memory (SMEM) information. + * @ctx: Pointer to the global SPL context. + * + * This function initializes and populates various SMEM items with boot-related + * information, such as flash type. + * Return: 0 on success, or a negative error code on failure. + */ +static int qcom_spl_populate_smem(void *ctx) +{ + int ret; + size_t size; + struct udevice *smem; + u32 *fltype; + + ret = qcom_smem_init(); + if (ret) { + pr_err("Failed init SMEM (%d)\n", ret); + return ret; + } + + size = sizeof(u32); + + fltype = (u32 *)smem_get(-1, SMEM_BOOT_FLASH_TYPE, &size); + if (!fltype) { + pr_err("Failed to get item: SMEM_BOOT_FLASH_TYPE\n"); + return -ENOENT; + } + + if (IS_ENABLED(CONFIG_SPL_MMC)) { + *fltype = SMEM_BOOT_MMC_FLASH; + wmb(); + return 0; + } + + pr_err("Boot medium not specified\n"); + + return -ENOENT; +} +#endif /* IS_ENABLED(CONFIG_SPL_SMEM) */ From 8dc38c8ff120525817312884dfb31af4439b6bb4 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 15:21:38 +0530 Subject: [PATCH 30/52] mach-snapdragon: spl: Add support for MMC booting in SPL Add routines to enable U-Boot SPL to be able to proceed with the boot from MMC partitions. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/board_spl.c | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 460d07ef0a36..2445ae8b17da 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -63,3 +63,60 @@ static int qcom_spl_populate_smem(void *ctx) return -ENOENT; } #endif /* IS_ENABLED(CONFIG_SPL_SMEM) */ + +#if CONFIG_IS_ENABLED(MMC) + +#define QCOM_SPL_FIT_IMG_PARTITION "0:BOOTLDR" + +/** + * spl_mmc_boot_mode() - Determine the boot mode for MMC + * @mmc: Pointer to the MMC device + * @boot_device: Boot device ID + * + * Return: MMCSD_MODE_RAW to use raw partition access + */ +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) +{ + return MMCSD_MODE_RAW; +} + +/** + * spl_mmc_boot_partition() - Determine which partition to boot from + * @boot_device: Boot device ID + * + * Return: Partition number to boot from, or default partition on error + */ +int spl_mmc_boot_partition(const u32 boot_device) +{ + int p_no; + struct blk_desc *desc; + struct disk_partition info; + + desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + if (!desc) { + pr_err("%s: Block device not found\n", __func__); + return -ENODEV; + } + + p_no = part_get_info_by_name(desc, QCOM_SPL_FIT_IMG_PARTITION, &info); + if (p_no < 0) { + pr_err("Partition " QCOM_SPL_FIT_IMG_PARTITION " not found\n"); + return -ENOENT; + } + + pr_debug("Found " QCOM_SPL_FIT_IMG_PARTITION " at %d\n", p_no); + + if (p_no < 0) { + printf("Using default MMC partition %d\n", + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); + return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION; + } + + return p_no; +} + +unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, ulong raw_sect) +{ + return 0; +} +#endif /* CONFIG_IS_ENABLED(MMC) */ From d3f7a0f82cbefddc107bae0235ed1bef3a911a98 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 15 Jul 2026 11:20:15 +0530 Subject: [PATCH 31/52] mach-snapdragon: Kconfig: Add rules to create SPL images The boot rom expects the secondary boot loader in MBN format followed by the TME executable. Add rules to board/qualcomm/config.mk to create u-boot-spl.mbn and u-boot-spl.melf. u-boot-spl.melf is the combined multi-elf file that has u-boot-spl.mbn followed by the TME executable. Additionally, this patch adds a config option to specify the path of the TME executable to be used to create u-boot-spl.melf. Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/Kconfig | 7 +++++++ board/qualcomm/config.mk | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 8c3e563dfa84..d85cfbcb4833 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -131,6 +131,13 @@ config QCOM_GENERATE_MBN New platforms can be added to tools/qcom/mkmbn/mkmbn.py if they aren't already supported. +config QCOM_TMEL_ELF + string "TME Elf to concatenate with U-Boot SPL MBN image" + depends on SPL && QCOM_GENERATE_MBN + help + Path of the TME Elf file to be concatenated to u-boot.mbn to create + boot rom expected multi-elf image + choice prompt "Qualcomm boot0.h workaround" optional diff --git a/board/qualcomm/config.mk b/board/qualcomm/config.mk index 769e4a51ca01..48560f195121 100644 --- a/board/qualcomm/config.mk +++ b/board/qualcomm/config.mk @@ -12,3 +12,26 @@ quiet_cmd_mkmbn = MBN $@ u-boot.mbn: u-boot.bin FORCE $(call if_changed,mkmbn) + +ifeq ($(CONFIG_QCOM_GENERATE_MBN),y) + +quiet_cmd_mksplmbn = SPLMBN $@ + cmd_mksplmbn = $(CMD_MKMBN) -o spl/u-boot-spl.mbn -l $(CONFIG_SPL_TEXT_BASE) -s 4 $< + +INPUTS-$(CONFIG_SPL) += spl/u-boot-spl.mbn + +spl/u-boot-spl.mbn: spl/u-boot-spl.bin FORCE + $(call if_changed,mksplmbn) + +ifneq ($(wildcard $(CONFIG_QCOM_TMEL_ELF)),) + +quiet_cmd_mksplmelf = SPLMELF $@ + cmd_mksplmelf = $(CMD_MKMBN) -o spl/u-boot-spl.melf -m spl/u-boot-spl.mbn,$(CONFIG_QCOM_TMEL_ELF) -s 4 + +INPUTS-$(CONFIG_SPL) += spl/u-boot-spl.melf + +spl/u-boot-spl.melf: spl/u-boot-spl.mbn FORCE + $(call if_changed,mksplmelf) +endif # CONFIG_QCOM_TMEL_ELF + +endif # CONFIG_QCOM_GENERATE_MBN From 70c1d0a253b9641920b5a6e8f4b17f1ef1d001db Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 15:48:38 +0530 Subject: [PATCH 32/52] mach-snapdragon: spl: Load next stage FIT image Identify the boot media loader driver and load the FIT image that has the binaries to initialize the DDR, U-Boot proper etc. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/board_spl.c | 155 ++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 2445ae8b17da..2655803b31e2 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -5,12 +5,15 @@ * Copyright (c) 2026 Michael Srba */ +#include #include +#include +#include #include #include /* in SPL, we always use internal DT */ -int board_fdt_blob_setup(void **fdtp) +int __weak board_fdt_blob_setup(void **fdtp) { return -EEXIST; } @@ -86,7 +89,7 @@ u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) * * Return: Partition number to boot from, or default partition on error */ -int spl_mmc_boot_partition(const u32 boot_device) +int __weak spl_mmc_boot_partition(const u32 boot_device) { int p_no; struct blk_desc *desc; @@ -120,3 +123,151 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, ulong raw_sect) return 0; } #endif /* CONFIG_IS_ENABLED(MMC) */ + +void qcom_spl_malloc_init_f(void) +{ + if (!CONFIG_IS_ENABLED(SYS_MALLOC_F)) + return; + /* + * Set up by crt0.S + */ + assert(gd->malloc_base); + gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); + gd->malloc_ptr = 0; + + mem_malloc_init(gd->malloc_base, gd->malloc_limit); + gd->flags |= GD_FLG_FULL_MALLOC_INIT; +} + +/** + * spl_get_load_buffer() - Allocate a cache-aligned buffer for image loading. + * @offset: Offset (unused, typically 0 for SPL). + * @size: Size of the buffer to allocate. + * + * Return: Pointer to the allocated buffer, or NULL on failure. + */ +struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) +{ +#ifdef CONFIG_SPL_LOAD_FIT_ADDRESS + return (void *)CONFIG_SPL_LOAD_FIT_ADDRESS; +#else + return NULL; +#endif +} + +/** + * board_spl_fit_buffer_addr() - Get the address of the FIT image buffer. + * @fit_size: Size of the FIT image. + * @sectors: Number of sectors. + * @bl_len: Block length. + * + * Return: Address of the FIT image buffer. + */ +void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len) +{ + return spl_get_load_buffer(0, sectors * bl_len); +} + +/** + * qcom_spl_loader_pre_ddr() - SPL loader for pre-DDR stage. + * @boot_device: Type of boot device. + * + * Return: 0 on success, or a negative error code on failure. + */ +int qcom_spl_loader_pre_ddr(u8 boot_device) +{ + struct spl_image_loader *loader, *drv; + struct spl_image_info spl_image = { 0 }; + struct spl_boot_device boot_dev = { .boot_device = boot_device, }; + int ret = -ENODEV, n_ents; + + drv = ll_entry_start(struct spl_image_loader, spl_image_loader); + n_ents = ll_entry_count(struct spl_image_loader, spl_image_loader); + + for (loader = drv; loader && (loader != drv + n_ents); loader++) { + if (boot_device != loader->boot_device) + continue; + + ret = loader->load_image(&spl_image, &boot_dev); + if (!ret) + break; + + printf("%s: Error: %d\n", __func__, ret); + } + + return ret; +} + +/** + * board_fit_config_name_match() - Select the FIT config for the current + * boot stage. + * @name: Candidate FIT config name. + * + * Generic default: match "pre-ddr" before DRAM is up, "post-ddr" after. + * A SoC with additional/different FIT configs should provide a strong + * override. + * + * Return: 0 on match, -EINVAL otherwise. + */ +int __weak board_fit_config_name_match(const char *name) +{ + if (!(gd->flags & GD_FLG_SPL_INIT)) { + if (!strcmp(name, "pre-ddr")) { + printf("Selected FIT Config: %s\n", name); + return 0; + } + } else { + if (!strcmp(name, "post-ddr")) { + printf("Selected FIT Config: %s\n", name); + return 0; + } + } + + return -EINVAL; +} + +/** + * board_init_f() - Generic SPL entry point. + * @dummy: Unused. + * + * Generic default: clear BSS, set up malloc, run early init, load the + * pre-DDR image and invoke QCLIB when booting from PBL, then hand off to + * board_init_r(). A SoC with additional bring-up steps should provide a + * strong override. + */ +void __weak board_init_f(ulong dummy) +{ + int ret = 0; + + memset(__bss_start, 0, __bss_end - __bss_start); /* Clear BSS */ + + qcom_spl_malloc_init_f(); + + ret = spl_early_init(); + if (ret) { + pr_debug("spl_early_init() failed (%d)\n", ret); + goto fail; + } + + event_notify_null(EVT_LAST_STAGE_INIT); + + preloader_console_init(); + + ret = qcom_spl_loader_pre_ddr(spl_boot_device()); + if (ret) { + pr_debug("qcom_spl_loader_pre_ddr() failed (%d)\n", ret); + goto fail; + } + + ret = qcom_spl_invoke_qclib(); + if (ret) { + pr_debug("qcom_spl_invoke_qclib() failed (%d)\n", ret); + goto fail; + } + + board_init_r(NULL, 0); + +fail: + if (ret) + reset_cpu(); +} From ad563a697fc8da881e4f3305bf3e99cb29fbe896 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 16:28:22 +0530 Subject: [PATCH 33/52] mach-snapdragon: spl: Add DDR initialization support The U-Boot SPL loads the next stage FIT image into internal SRAM. The binaries are 'external' in this FIT image. The SPL has to load the DDR init binary, i.e. qclib and the DDR parameters i.e. qcconfig used by qclib and invoke the qclib. SPL and qclib exchange information using the interface table described in doc/board/qualcomm/interface-table.rst. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/Makefile | 1 + arch/arm/mach-snapdragon/fit-handler.c | 131 +++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 arch/arm/mach-snapdragon/fit-handler.c diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index a8f662e56ecc..523b89b86767 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -7,6 +7,7 @@ obj-y += mem_map.o ifeq ($(CONFIG_SPL_BUILD),y) obj-y += board_spl.o +obj-y += fit-handler.o obj-y += pbl-shared-data.o else obj-y += board.o diff --git a/arch/arm/mach-snapdragon/fit-handler.c b/arch/arm/mach-snapdragon/fit-handler.c new file mode 100644 index 000000000000..fc419bd3f008 --- /dev/null +++ b/arch/arm/mach-snapdragon/fit-handler.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +#include +#include +#include +#include +#include +#include +#include + +/** + * qcom_spl_get_fit_img_entry_point() - Get entry point from FIT image node. + * @fit: Pointer to the FIT image blob. + * @node: Node ID within the FIT image. + * @entry_point: Pointer to store the retrieved entry point. + * + * Return: 0 on success, or a negative error code on failure. + */ +int qcom_spl_get_fit_img_entry_point(void *fit, int node, + u64 *entry_point) +{ + int ret; + + if (!fit) { + pr_err("FIT image blob is NULL\n"); + return -EINVAL; + } + if (node <= 0) { + pr_err("Invalid FIT node ID %d\n", node); + return -EINVAL; + } + if (!entry_point) { + pr_err("Entry point pointer is NULL\n"); + return -EINVAL; + } + + ret = fit_image_get_entry(fit, node, (ulong *)entry_point); + if (ret) { + pr_debug("No entry point for node %d, trying load address\n", + node); + ret = fit_image_get_load(fit, node, (ulong *)entry_point); + if (ret) + pr_err("No load address for node %d (%d)\n", node, ret); + } + + return ret; +} + +/** + * qcom_spl_get_iftbl_entry_by_name() - Get an interface table entry by name. + * @if_tbl: Pointer to the QCLIB interface table. + * @name: Name of the entry to find. + * @entry: Pointer to a buffer where the found entry will be copied. + * + * Return: 0 on success, or a negative error code on failure. + */ +int qcom_spl_get_iftbl_entry_by_name(struct interface_table *if_tbl, + char *name, + struct interface_table_entry *entry) +{ + uint uc_index; + + if (!if_tbl) { + pr_err("Invalid interface table\n"); + return -EINVAL; + } + if (!name) { + pr_err("Invalid name\n"); + return -EINVAL; + } + if (!entry) { + pr_err("Invalid entry pointer\n"); + return -EINVAL; + } + + for (uc_index = 0; uc_index < if_tbl->num_entries; uc_index++) { + if (!strcmp(if_tbl->if_table_entries[uc_index].entry_name, name)) { + memcpy(entry, + &if_tbl->if_table_entries[uc_index], + sizeof(struct interface_table_entry)); + return 0; + } + } + pr_err("Interface table entry '%s' not found\n", name); + + return -ENOENT; +} + +/** + * bl2_plat_get_bl31_params_v2() - Retrieve and fixup BL31 parameters. + * @bl32_entry: Entry point for BL32 (OP-TEE). + * @bl33_entry: Entry point for BL33 (U-Boot/kernel). + * @fdt_addr: Address of the Device Tree Blob (FDT). + * + * Return: Pointer to the populated BL31 parameters structure. + */ +struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry, + uintptr_t bl33_entry, + uintptr_t fdt_addr) +{ + struct bl_params *bl_params; + struct bl_params_node *node; + u64 qcsdi_address = qclib_get_qcsdi_address(); + + /* + * Populate the bl31 params with default values. + */ + bl_params = bl2_plat_get_bl31_params_v2_default(bl32_entry, bl33_entry, + fdt_addr); + + /* + * Fixup the bl31 params based on platform requirements. + */ + for_each_bl_params_node(bl_params, node) { + if (node->image_id == ATF_BL31_IMAGE_ID) { + /* + * Pass QCSDI address to BL31 via arg0 + * This address was populated by qcom_spl_invoke_qclib() + */ + if (qcsdi_address == 0) + pr_warn("QCSDI address not set, BL31 may not function correctly\n"); + + node->ep_info->args.arg0 = qcsdi_address; + pr_debug("Setting BL31 arg0 to QCSDI address: 0x%llx\n", qcsdi_address); + } + } + + return bl_params; +} From 43cbce2cc279b3cec3e859af42aa824bafd18bf6 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Tue, 25 Aug 2026 13:05:50 +0530 Subject: [PATCH 34/52] mach-snapdragon: Add Qclib handling support Add functions that handle loading the FIT image nodes having the Qclib executable and executing it. Also provides 'weak' hooks that can be overridden by SoC specific implementations. Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/Makefile | 1 + arch/arm/mach-snapdragon/include/mach/qclib.h | 82 +++++++++ arch/arm/mach-snapdragon/qclib.c | 160 ++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 arch/arm/mach-snapdragon/include/mach/qclib.h create mode 100644 arch/arm/mach-snapdragon/qclib.c diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index 523b89b86767..20a3e40d0992 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -9,6 +9,7 @@ ifeq ($(CONFIG_SPL_BUILD),y) obj-y += board_spl.o obj-y += fit-handler.o obj-y += pbl-shared-data.o +obj-y += qclib.o else obj-y += board.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o diff --git a/arch/arm/mach-snapdragon/include/mach/qclib.h b/arch/arm/mach-snapdragon/include/mach/qclib.h new file mode 100644 index 000000000000..b44874c514e8 --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/qclib.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QCLIB_H__ +#define __QCLIB_H__ + +#include +#include + +#define MAGIC_KEY "QCLIB_CB" +#define MAX_ENTRIES 0xF +#define IF_TABLE_VERSION 0x1 +#define QCSDI "qcsdi" +#define QCLIB_LOG_BUFFER "qclib_log_buffer" + +/* interface_table.global_attributes bits */ +#define QCLIB_GA_ENABLE_UART_LOGGING BIT(0) + +/** + * struct interface_table_entry - Meta data for blobs in QCLIB interface + * @entry_name: Name of the data blob (e.g., "dcb_settings"). + * @address: Address of the data blob. + * @size: Size of the data blob. + * @attributes: Attributes for the blob (e.g., save to storage). + */ +struct interface_table_entry { + char entry_name[24]; + u64 address; + u32 size; + u32 attributes; +}; + +/** + * struct interface_table - QCLIB Interface table header + * @magic_key: Magic key for validation ("QCLIB_CB"). + * @version: Interface table version. + * @num_entries: Number of valid entries. + * @max_entries: Maximum allowable entries. + * @global_attributes: Flags for global attributes (e.g., SDI path). + * @reserved1: Reserved for future use. + * @reserved2: Reserved for future use. + * @if_table_entries: Array of interface table entries. + */ +struct interface_table { + char magic_key[8]; + u32 version; + u32 num_entries; + u32 max_entries; + u32 global_attributes; + u32 reserved1; + u32 reserved2; + struct interface_table_entry if_table_entries[MAX_ENTRIES]; +}; + +/* Exported by fit-handler.c */ +int qcom_spl_get_fit_img_entry_point(void *fit, int node, u64 *entry_point); +int qcom_spl_get_iftbl_entry_by_name(struct interface_table *if_tbl, + char *name, + struct interface_table_entry *entry); + +/* QCSDI address accessors, populated post-QCLIB, consumed by fit-handler.c */ +u64 qclib_get_qcsdi_address(void); +void qclib_set_qcsdi_address(u64 address); + +/* qclib_log_buffer address accessors, populated post-QCLIB */ +u64 qclib_get_log_buffer_entry(void); +void qclib_set_log_buffer_entry(u64 address); + +/* + * __weak SoC extension points. A board's spl-.c may provide a strong + * override for any of these; the defaults in qclib.c are all no-ops. + */ +bool qcom_spl_soc_check_dload_mode(void); +int qcom_spl_soc_pre_qclib_routine(void); +int qcom_spl_soc_qclib_override(struct interface_table *table, const void *fit, + int images_node); +int qcom_spl_soc_post_qclib_routine(struct interface_table *if_tbl); + +int qclib_populate_interface_table(struct interface_table *if_tbl, + const void *fit, int images_node); +int qcom_spl_invoke_qclib(void); + +#endif /* __QCLIB_H__ */ diff --git a/arch/arm/mach-snapdragon/qclib.c b/arch/arm/mach-snapdragon/qclib.c new file mode 100644 index 000000000000..7f25f37b5d92 --- /dev/null +++ b/arch/arm/mach-snapdragon/qclib.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * QCLIB interface-table protocol: generic, SoC-agnostic orchestration of the + * hand-off to the QCLIB firmware image, plus __weak extension points a + * per-board spl-.c may override to populate SoC-specific table entries. + */ + +#include +#include +#include +#include +#include +#include +#include + +static u64 g_qcsdi_address __section(".data"); +static u64 g_log_buffer_entry __section(".data"); + +u64 qclib_get_qcsdi_address(void) +{ + return g_qcsdi_address; +} + +void qclib_set_qcsdi_address(u64 addr) +{ + g_qcsdi_address = addr; +} + +u64 qclib_get_log_buffer_entry(void) +{ + return g_log_buffer_entry; +} + +void qclib_set_log_buffer_entry(u64 address) +{ + g_log_buffer_entry = address; +} + +bool __weak qcom_spl_soc_check_dload_mode(void) +{ + return false; +} + +int __weak qcom_spl_soc_pre_qclib_routine(void) +{ + return 0; +} + +int __weak qcom_spl_soc_qclib_override(struct interface_table *table, + const void *fit, int images_node) +{ + return 0; +} + +int __weak qcom_spl_soc_post_qclib_routine(struct interface_table *if_tbl) +{ + return 0; +} + +int __weak qclib_populate_interface_table(struct interface_table *if_tbl, + const void *fit, int images_node) +{ + struct interface_table_entry *log_buffer_entry; + + memset(if_tbl, 0, sizeof(struct interface_table)); + memcpy(if_tbl->magic_key, MAGIC_KEY, strlen(MAGIC_KEY)); + if_tbl->version = IF_TABLE_VERSION; + if_tbl->num_entries = 0; + if_tbl->max_entries = MAX_ENTRIES; + + /* + * Reserve the "qclib_log_buffer" slot — common to every SoC. + * QCLIB fills in the address itself; SPL just allocates the entry. + */ + log_buffer_entry = &if_tbl->if_table_entries[if_tbl->num_entries]; + memcpy(log_buffer_entry->entry_name, QCLIB_LOG_BUFFER, + strlen(QCLIB_LOG_BUFFER)); + log_buffer_entry->address = 0; + log_buffer_entry->size = 0; + log_buffer_entry->attributes = 0; + if_tbl->num_entries++; + + return qcom_spl_soc_qclib_override(if_tbl, fit, images_node); +} + +static int qclib_find_fit_nodes(const void *fit, int *images_node, + int *qclib_node) +{ + *images_node = fdt_subnode_offset(fit, 0, "images"); + if (*images_node < 0) { + pr_err("Failed to find images node in FIT\n"); + return -ENOENT; + } + + *qclib_node = fdt_subnode_offset(fit, *images_node, "qclib_1"); + if (*qclib_node < 0) { + pr_err("Failed to find qclib_1 node in FIT\n"); + return -ENOENT; + } + + return 0; +} + +int qcom_spl_invoke_qclib(void) +{ + int ret; + int images_node; + int qclib_node; + const void *fit; + struct interface_table if_tbl; + u64 entry_point; + + /* Get FIT image from SPL load address */ + fit = (const void *)CONFIG_SPL_LOAD_FIT_ADDRESS; + + pr_debug("QCLIB invoke: fit=%p\n", fit); + + ret = qclib_find_fit_nodes(fit, &images_node, &qclib_node); + if (ret) + return ret; + + ret = qcom_spl_soc_pre_qclib_routine(); + if (ret) + return ret; + + ret = qclib_populate_interface_table(&if_tbl, fit, images_node); + if (ret) + return ret; + + ret = qcom_spl_get_fit_img_entry_point((void *)fit, qclib_node, &entry_point); + if (ret) { + pr_err("Failed to get qcom-lib-1 entry point (%d)\n", ret); + return ret; + } + + pr_info("Jumping to qcom-lib-1 at 0x%llx\n", entry_point); + + /* + * QCLIB is a separately-linked firmware image, not an AAPCS64 + * callee - a plain C function-pointer call risks the compiler + * caching a live value in a callee-saved register across the jump. + * Pin the args/target to fixed registers and clobber everything the + * ABI doesn't guarantee QCLIB will preserve. + */ + { + register void *x0 asm("x0") = &if_tbl; + register void *x1 asm("x1") = NULL; + register u64 x8 asm("x8") = entry_point; + + asm volatile ("blr x8" + : "+r" (x0) + : "r" (x1), "r" (x8) + : "x2", "x3", "x4", "x5", "x6", "x7", "x9", "x10", + "x11", "x12", "x13", "x14", "x15", "x16", "x17", + "x19", "x20", "x21", "x22", "x23", "x24", "x25", + "x26", "x27", "x28", "x30", "cc", "memory"); + } + + return qcom_spl_soc_post_qclib_routine(&if_tbl); +} From def85c61c437ba2d8783ae0c0dcd25e060bf75cc Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Tue, 30 Jun 2026 13:38:23 +0530 Subject: [PATCH 35/52] dts: ipq5210-rdp504-u-boot: add override dtsi * Add initial support for the IPQ5210 MMC based RDP platforms. * Define memory layout statically. * Mark the nodes that would be needed for SPL. Reviewed-by: Simon Glass Reviewed-by: Sumit Garg Signed-off-by: Varadarajan Narayanan --- arch/arm/dts/ipq5210-rdp504-u-boot.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 arch/arm/dts/ipq5210-rdp504-u-boot.dtsi diff --git a/arch/arm/dts/ipq5210-rdp504-u-boot.dtsi b/arch/arm/dts/ipq5210-rdp504-u-boot.dtsi new file mode 100644 index 000000000000..5582de9bebb8 --- /dev/null +++ b/arch/arm/dts/ipq5210-rdp504-u-boot.dtsi @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IPQ5210 RDP504 board device tree source + * + * Copyright (c) 2026 The Linux Foundation. All rights reserved. + */ + +/ { + reserved-memory { + /delete-node/ bootloader@87800000; + }; +}; From 49e9b6af6dc7b8188c04a2495c5d112ac9b13010 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Tue, 30 Jun 2026 13:38:24 +0530 Subject: [PATCH 36/52] clk/qcom: add clock driver for ipq5210 Add clocks and resets for enabling U-Boot on ipq5210 based RDP platforms. Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- drivers/clk/qcom/Kconfig | 8 +++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clock-ipq5210.c | 93 ++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 drivers/clk/qcom/clock-ipq5210.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index c7fcc3fb1863..6db258a29cec 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -31,6 +31,14 @@ config CLK_QCOM_IPQ4019 on the Snapdragon IPQ4019 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_IPQ5210 + bool "Qualcomm IPQ5210 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Qualcomm IPQ5210 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_IPQ5424 bool "Qualcomm IPQ5424 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 831f207fa4e9..4b4264aba9db 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o +obj-$(CONFIG_CLK_QCOM_IPQ5210) += clock-ipq5210.o obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o obj-$(CONFIG_CLK_QCOM_MILOS) += clock-milos.o diff --git a/drivers/clk/qcom/clock-ipq5210.c b/drivers/clk/qcom/clock-ipq5210.c new file mode 100644 index 000000000000..cd82b238bea9 --- /dev/null +++ b/drivers/clk/qcom/clock-ipq5210.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock drivers for Qualcomm IPQ5210 + * + * (C) Copyright 2024 Linaro Ltd. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clock-qcom.h" + +static ulong ipq5210_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_QUPV3_WRAP_SE1_CLK: + clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].cbcr_reg, + 0, 2, 217, CFG_CLK_SRC_GPLL0, 16); + break; + case GCC_SDCC1_AHB_CLK: + break; + case GCC_SDCC1_APPS_CLK: + clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].cbcr_reg, + 0, 6, 25, CFG_CLK_SRC_GPLL0, 16); + break; + default: + return -EINVAL; + } + + return rate; +} + +static const struct gate_clk ipq5210_clks[] = { + GATE_CLK_POLLED(GCC_QUPV3_WRAP_SE1_CLK, 0x05020, BIT(0), 0x05004), + GATE_CLK_POLLED(GCC_SDCC1_AHB_CLK, 0x3303c, BIT(0), 0x3303c), + GATE_CLK_POLLED(GCC_SDCC1_APPS_CLK, 0x3302c, BIT(0), 0x33004), +}; + +static int ipq5210_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks <= clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return -ENOENT; + } + + debug("%s: clk %s\n", __func__, ipq5210_clks[clk->id].name); + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map ipq5210_gcc_resets[] = { + [GCC_SDCC_BCR] = {0x33000, 0}, + [GCC_USB0_PHY_BCR] = {0x2c06c, 0}, + [GCC_USB3PHY_0_PHY_BCR] = {0x2c070, 0}, + [GCC_QUSB2_0_PHY_BCR] = {0x2c068, 0}, + [GCC_USB_BCR] = {0x2c000, 0}, +}; + +static struct msm_clk_data ipq5210_gcc_data = { + .resets = ipq5210_gcc_resets, + .num_resets = ARRAY_SIZE(ipq5210_gcc_resets), + .clks = ipq5210_clks, + .num_clks = ARRAY_SIZE(ipq5210_clks), + .enable = ipq5210_enable, + .set_rate = ipq5210_set_rate, +}; + +static const struct udevice_id gcc_ipq5210_of_match[] = { + { + .compatible = "qcom,ipq5210-gcc", + .data = (ulong)&ipq5210_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_ipq5210) = { + .name = "gcc_ipq5210", + .id = UCLASS_NOP, + .of_match = gcc_ipq5210_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; From e9e4027643567ecfffdd32c6357cd5e4e868cb76 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Tue, 30 Jun 2026 13:38:25 +0530 Subject: [PATCH 37/52] pinctrl: qcom: Add ipq5210 pinctrl driver Add pinctrl driver for the TLMM block found in the ipq5210 SoC. Reviewed-by: Balaji Selvanathan Signed-off-by: Varadarajan Narayanan --- drivers/pinctrl/qcom/Kconfig | 8 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-ipq5210.c | 349 +++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-ipq5210.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 0ee100aad90f..ce69a1e73289 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -76,6 +76,14 @@ config SPL_PINCTRL_QCOM_IPQ4019 SPL variant of PINCTRL_QCOM_IPQ4019. See the help of PINCTRL_QCOM_IPQ4019 for details. +config PINCTRL_QCOM_IPQ5210 + bool "Qualcomm IPQ5210 Pinctrl" + default y if PINCTRL_QCOM_GENERIC + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the IPQ5210 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_IPQ5424 bool "Qualcomm IPQ5424 Pinctrl" default y if PINCTRL_QCOM_GENERIC diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 8280f0b18bc0..a0781ab85290 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM) += pinctrl-qcom.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o +obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ5210) += pinctrl-ipq5210.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_$(PHASE_)PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5210.c b/drivers/pinctrl/qcom/pinctrl-ipq5210.c new file mode 100644 index 000000000000..779011a04a7d --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ipq5210.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm IPQ5210 pinctrl + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +enum ipq5210_functions { + msm_mux_atest_char_start, + msm_mux_atest_char_status0, + msm_mux_atest_char_status1, + msm_mux_atest_char_status2, + msm_mux_atest_char_status3, + msm_mux_atest_tic_en, + msm_mux_audio_pri, + msm_mux_audio_pri_mclk_out0, + msm_mux_audio_pri_mclk_in0, + msm_mux_audio_pri_mclk_out1, + msm_mux_audio_pri_mclk_in1, + msm_mux_audio_pri_mclk_out2, + msm_mux_audio_pri_mclk_in2, + msm_mux_audio_pri_mclk_out3, + msm_mux_audio_pri_mclk_in3, + msm_mux_audio_sec, + msm_mux_audio_sec_mclk_out0, + msm_mux_audio_sec_mclk_in0, + msm_mux_audio_sec_mclk_out1, + msm_mux_audio_sec_mclk_in1, + msm_mux_audio_sec_mclk_out2, + msm_mux_audio_sec_mclk_in2, + msm_mux_audio_sec_mclk_out3, + msm_mux_audio_sec_mclk_in3, + msm_mux_core_voltage_0, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_cri_trng2, + msm_mux_cri_trng3, + msm_mux_dbg_out_clk, + msm_mux_dg_out, + msm_mux_gcc_plltest_bypassnl, + msm_mux_gcc_plltest_resetn, + msm_mux_gcc_tlmm, + msm_mux_gpio, + msm_mux_led0, + msm_mux_led1, + msm_mux_led2, + msm_mux_mdc_mst, + msm_mux_mdc_slv0, + msm_mux_mdc_slv1, + msm_mux_mdc_slv2, + msm_mux_mdio_mst, + msm_mux_mdio_slv0, + msm_mux_mdio_slv1, + msm_mux_mdio_slv2, + msm_mux_mux_tod_out, + msm_mux_pcie0_clk_req_n, + msm_mux_pcie0_wake, + msm_mux_pcie1_clk_req_n, + msm_mux_pcie1_wake, + msm_mux_pll_test, + msm_mux_pon_active_led, + msm_mux_pon_mux_sel, + msm_mux_pon_rx, + msm_mux_pon_rx_los, + msm_mux_pon_tx, + msm_mux_pon_tx_burst, + msm_mux_pon_tx_dis, + msm_mux_pon_tx_fault, + msm_mux_pon_tx_sd, + msm_mux_gpn_rx_los, + msm_mux_gpn_tx_burst, + msm_mux_gpn_tx_dis, + msm_mux_gpn_tx_fault, + msm_mux_gpn_tx_sd, + msm_mux_pps, + msm_mux_pwm0, + msm_mux_pwm1, + msm_mux_pwm2, + msm_mux_pwm3, + msm_mux_qdss_cti_trig_in_a0, + msm_mux_qdss_cti_trig_in_a1, + msm_mux_qdss_cti_trig_in_b0, + msm_mux_qdss_cti_trig_in_b1, + msm_mux_qdss_cti_trig_out_a0, + msm_mux_qdss_cti_trig_out_a1, + msm_mux_qdss_cti_trig_out_b0, + msm_mux_qdss_cti_trig_out_b1, + msm_mux_qdss_traceclk_a, + msm_mux_qdss_tracectl_a, + msm_mux_qdss_tracedata_a, + msm_mux_qrng_rosc0, + msm_mux_qrng_rosc1, + msm_mux_qrng_rosc2, + msm_mux_qspi_data, + msm_mux_qspi_clk, + msm_mux_qspi_cs_n, + msm_mux_qup_se0, + msm_mux_qup_se1, + msm_mux_qup_se2, + msm_mux_qup_se3, + msm_mux_qup_se4, + msm_mux_qup_se5, + msm_mux_qup_se5_l1, + msm_mux_resout, + msm_mux_rx_los0, + msm_mux_rx_los1, + msm_mux_rx_los2, + msm_mux_sdc_clk, + msm_mux_sdc_cmd, + msm_mux_sdc_data, + msm_mux_tsens_max, + msm_mux__, +}; + +#define MSM_PIN_FUNCTION(fname) \ + [msm_mux_##fname] = {#fname, msm_mux_##fname} + +static const struct pinctrl_function msm_pinctrl_functions[] = { + MSM_PIN_FUNCTION(atest_char_start), + MSM_PIN_FUNCTION(atest_char_status0), + MSM_PIN_FUNCTION(atest_char_status1), + MSM_PIN_FUNCTION(atest_char_status2), + MSM_PIN_FUNCTION(atest_char_status3), + MSM_PIN_FUNCTION(atest_tic_en), + MSM_PIN_FUNCTION(audio_pri), + MSM_PIN_FUNCTION(audio_pri_mclk_out0), + MSM_PIN_FUNCTION(audio_pri_mclk_in0), + MSM_PIN_FUNCTION(audio_pri_mclk_out1), + MSM_PIN_FUNCTION(audio_pri_mclk_in1), + MSM_PIN_FUNCTION(audio_pri_mclk_out2), + MSM_PIN_FUNCTION(audio_pri_mclk_in2), + MSM_PIN_FUNCTION(audio_pri_mclk_out3), + MSM_PIN_FUNCTION(audio_pri_mclk_in3), + MSM_PIN_FUNCTION(audio_sec), + MSM_PIN_FUNCTION(audio_sec_mclk_out0), + MSM_PIN_FUNCTION(audio_sec_mclk_in0), + MSM_PIN_FUNCTION(audio_sec_mclk_out1), + MSM_PIN_FUNCTION(audio_sec_mclk_in1), + MSM_PIN_FUNCTION(audio_sec_mclk_out2), + MSM_PIN_FUNCTION(audio_sec_mclk_in2), + MSM_PIN_FUNCTION(audio_sec_mclk_out3), + MSM_PIN_FUNCTION(audio_sec_mclk_in3), + MSM_PIN_FUNCTION(core_voltage_0), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(cri_trng2), + MSM_PIN_FUNCTION(cri_trng3), + MSM_PIN_FUNCTION(dbg_out_clk), + MSM_PIN_FUNCTION(dg_out), + MSM_PIN_FUNCTION(gcc_plltest_bypassnl), + MSM_PIN_FUNCTION(gcc_plltest_resetn), + MSM_PIN_FUNCTION(gcc_tlmm), + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(led0), + MSM_PIN_FUNCTION(led1), + MSM_PIN_FUNCTION(led2), + MSM_PIN_FUNCTION(mdc_mst), + MSM_PIN_FUNCTION(mdc_slv0), + MSM_PIN_FUNCTION(mdc_slv1), + MSM_PIN_FUNCTION(mdc_slv2), + MSM_PIN_FUNCTION(mdio_mst), + MSM_PIN_FUNCTION(mdio_slv0), + MSM_PIN_FUNCTION(mdio_slv1), + MSM_PIN_FUNCTION(mdio_slv2), + MSM_PIN_FUNCTION(mux_tod_out), + MSM_PIN_FUNCTION(pcie0_clk_req_n), + MSM_PIN_FUNCTION(pcie0_wake), + MSM_PIN_FUNCTION(pcie1_clk_req_n), + MSM_PIN_FUNCTION(pcie1_wake), + MSM_PIN_FUNCTION(pll_test), + MSM_PIN_FUNCTION(pon_active_led), + MSM_PIN_FUNCTION(pon_mux_sel), + MSM_PIN_FUNCTION(pon_rx), + MSM_PIN_FUNCTION(pon_rx_los), + MSM_PIN_FUNCTION(pon_tx), + MSM_PIN_FUNCTION(pon_tx_burst), + MSM_PIN_FUNCTION(pon_tx_dis), + MSM_PIN_FUNCTION(pon_tx_fault), + MSM_PIN_FUNCTION(pon_tx_sd), + MSM_PIN_FUNCTION(gpn_rx_los), + MSM_PIN_FUNCTION(gpn_tx_burst), + MSM_PIN_FUNCTION(gpn_tx_dis), + MSM_PIN_FUNCTION(gpn_tx_fault), + MSM_PIN_FUNCTION(gpn_tx_sd), + MSM_PIN_FUNCTION(pps), + MSM_PIN_FUNCTION(pwm0), + MSM_PIN_FUNCTION(pwm1), + MSM_PIN_FUNCTION(pwm2), + MSM_PIN_FUNCTION(pwm3), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b1), + MSM_PIN_FUNCTION(qdss_traceclk_a), + MSM_PIN_FUNCTION(qdss_tracectl_a), + MSM_PIN_FUNCTION(qdss_tracedata_a), + MSM_PIN_FUNCTION(qrng_rosc0), + MSM_PIN_FUNCTION(qrng_rosc1), + MSM_PIN_FUNCTION(qrng_rosc2), + MSM_PIN_FUNCTION(qspi_data), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs_n), + MSM_PIN_FUNCTION(qup_se0), + MSM_PIN_FUNCTION(qup_se1), + MSM_PIN_FUNCTION(qup_se2), + MSM_PIN_FUNCTION(qup_se3), + MSM_PIN_FUNCTION(qup_se4), + MSM_PIN_FUNCTION(qup_se5), + MSM_PIN_FUNCTION(qup_se5_l1), + MSM_PIN_FUNCTION(resout), + MSM_PIN_FUNCTION(rx_los0), + MSM_PIN_FUNCTION(rx_los1), + MSM_PIN_FUNCTION(rx_los2), + MSM_PIN_FUNCTION(sdc_clk), + MSM_PIN_FUNCTION(sdc_cmd), + MSM_PIN_FUNCTION(sdc_data), + MSM_PIN_FUNCTION(tsens_max), +}; + +typedef unsigned int msm_pin_function[10]; + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + [id] = { msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9, \ + } + +static const msm_pin_function ipq5210_pin_functions[] = { + PINGROUP(0, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(1, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(2, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(3, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(4, sdc_cmd, qspi_cs_n, _, _, _, _, _, _, _), + PINGROUP(5, sdc_clk, qspi_clk, _, _, _, _, _, _, _), + PINGROUP(6, qup_se0, led0, pwm1, _, cri_trng0, qdss_tracedata_a, _, _, _), + PINGROUP(7, qup_se0, led1, pwm1, _, cri_trng1, qdss_tracedata_a, _, _, _), + PINGROUP(8, qup_se0, pwm1, audio_pri_mclk_out2, audio_pri_mclk_in2, _, cri_trng2, qdss_tracedata_a, _, _), + PINGROUP(9, qup_se0, led2, pwm1, _, cri_trng3, qdss_tracedata_a, _, _, _), + PINGROUP(10, pon_rx_los, qup_se3, pwm0, _, _, qdss_tracedata_a, _, _, _), + PINGROUP(11, pon_active_led, qup_se3, pwm0, _, _, qdss_tracedata_a, _, _, _), + PINGROUP(12, pon_tx_dis, qup_se2, pwm0, audio_pri_mclk_out0, audio_pri_mclk_in0, _, qrng_rosc0, qdss_tracedata_a, _), + PINGROUP(13, gpn_tx_dis, qup_se2, pwm0, audio_pri_mclk_out3, audio_pri_mclk_in3, _, qrng_rosc1, qdss_tracedata_a, _), + PINGROUP(14, pon_tx_burst, qup_se0, _, qrng_rosc2, qdss_tracedata_a, _, _, _, _), + PINGROUP(15, pon_tx, qup_se0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(16, pon_tx_sd, audio_sec_mclk_out1, audio_sec_mclk_in1, qdss_cti_trig_out_b0, _, _, _, _, _), + PINGROUP(17, pon_tx_fault, audio_sec_mclk_out0, audio_sec_mclk_in0, _, _, _, _, _, _), + PINGROUP(18, pps, pll_test, _, _, _, _, _, _, _), + PINGROUP(19, mux_tod_out, audio_pri_mclk_out1, audio_pri_mclk_in1, _, _, _, _, _, _), + PINGROUP(20, qup_se2, mdc_slv1, tsens_max, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(21, qup_se2, mdio_slv1, qdss_tracedata_a, _, _, _, _, _, _), + PINGROUP(22, core_voltage_0, qup_se3, pwm3, _, _, _, _, _, _), + PINGROUP(23, led0, qup_se3, dbg_out_clk, qdss_traceclk_a, _, _, _, _, _), + PINGROUP(24, _, _, _, _, _, _, _, _, _), + PINGROUP(25, _, _, _, _, _, _, _, _, _), + PINGROUP(26, mdc_mst, led2, _, qdss_tracectl_a, _, _, _, _, _), + PINGROUP(27, mdio_mst, led1, _, _, _, _, _, _, _), + PINGROUP(28, pcie1_clk_req_n, qup_se1, _, _, qdss_cti_trig_out_a0, _, _, _, _), + PINGROUP(29, _, _, _, _, _, _, _, _, _), + PINGROUP(30, pcie1_wake, qup_se1, _, _, qdss_cti_trig_in_a0, _, _, _, _), + PINGROUP(31, pcie0_clk_req_n, mdc_slv0, _, qdss_cti_trig_out_a1, _, _, _, _, _), + PINGROUP(32, _, _, _, _, _, _, _, _, _), + PINGROUP(33, pcie0_wake, mdio_slv0, qdss_cti_trig_in_a1, _, _, _, _, _, _), + PINGROUP(34, audio_pri, atest_char_status0, qdss_cti_trig_in_b0, _, _, _, _, _, _), + PINGROUP(35, audio_pri, rx_los2, atest_char_status1, qdss_cti_trig_out_b1, _, _, _, _, _), + PINGROUP(36, audio_pri, _, rx_los1, atest_char_status2, _, _, _, _, _), + PINGROUP(37, audio_pri, rx_los0, atest_char_status3, _, qdss_cti_trig_in_b1, _, _, _, _), + PINGROUP(38, qup_se1, led2, gcc_plltest_bypassnl, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(39, qup_se1, led1, led0, gcc_tlmm, qdss_tracedata_a, _, _, _, _), + PINGROUP(40, qup_se4, rx_los2, audio_sec, gcc_plltest_resetn, qdss_tracedata_a, _, _, _, _), + PINGROUP(41, qup_se4, rx_los1, audio_sec, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(42, qup_se4, rx_los0, audio_sec, atest_tic_en, _, _, _, _, _), + PINGROUP(43, qup_se4, audio_sec, _, _, _, _, _, _, _), + PINGROUP(44, resout, _, _, _, _, _, _, _, _), + PINGROUP(45, pon_mux_sel, _, _, _, _, _, _, _, _), + PINGROUP(46, dg_out, atest_char_start, _, _, _, _, _, _, _), + PINGROUP(47, gpn_rx_los, mdc_slv2, qup_se5, _, _, _, _, _, _), + PINGROUP(48, pon_rx, qup_se5, _, _, _, _, _, _, _), + PINGROUP(49, gpn_tx_fault, mdio_slv2, qup_se5, audio_sec_mclk_out2, audio_sec_mclk_in2, _, _, _, _), + PINGROUP(50, gpn_tx_sd, qup_se5, audio_sec_mclk_out3, audio_sec_mclk_in3, _, _, _, _, _), + PINGROUP(51, gpn_tx_burst, qup_se5, _, _, _, _, _, _, _), + PINGROUP(52, qup_se2, qup_se5, qup_se4, qup_se5_l1, _, _, _, _, _), + PINGROUP(53, qup_se2, qup_se4, qup_se5_l1, _, _, _, _, _, _), +}; + +static const char *ipq5210_get_function_name(struct udevice *dev, uint selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *ipq5210_get_pin_name(struct udevice *dev, uint selector) +{ + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; +} + +static int ipq5210_get_function_mux(unsigned int pin, uint selector) +{ + unsigned int i; + const msm_pin_function *func = ipq5210_pin_functions + pin; + + for (i = 0; i < 10; i++) + if ((*func)[i] == selector) + return i; + + pr_err("Can't find requested function for pin %u\n", pin); + return -EINVAL; +} + +static const struct msm_pinctrl_data ipq5210_data = { + .pin_data = { + .pin_count = 54, + .special_pins_start = 54, /* There are no special pins */ + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = ipq5210_get_function_name, + .get_function_mux = ipq5210_get_function_mux, + .get_pin_name = ipq5210_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,ipq5210-tlmm", .data = (ulong)&ipq5210_data }, + { /* Sentinal */ } +}; + +U_BOOT_DRIVER(pinctrl_ipq5210) = { + .name = "pinctrl_ipq5210", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, + .flags = DM_FLAG_PRE_RELOC, +}; \ No newline at end of file From 54b513b422f9294e4eae5af389e5dd06843e2843 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 16:39:38 +0530 Subject: [PATCH 38/52] mach-snapdragon: spl: ipq5210: Add SPL support This patch adds the basic board init routines that invoke the common and mach-snapdragon specific SPL frameworks to proceed with the hand over from boot rom to the next stage i.e. U-Boot proper. This also provides the linker script to generate the SPL image in the format expected by the boot rom. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/board_spl.c | 2 + arch/arm/mach-snapdragon/include/mach/spl.h | 13 +++ board/qualcomm/ipq5210/Makefile | 3 + .../qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds | 18 ++++ board/qualcomm/ipq5210/spl-ipq5210.c | 99 +++++++++++++++++++ include/configs/ipq5210.h | 11 +++ 6 files changed, 146 insertions(+) create mode 100644 arch/arm/mach-snapdragon/include/mach/spl.h create mode 100644 board/qualcomm/ipq5210/Makefile create mode 100644 board/qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds create mode 100644 board/qualcomm/ipq5210/spl-ipq5210.c create mode 100644 include/configs/ipq5210.h diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 2655803b31e2..3293eab8f81d 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -12,6 +12,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + /* in SPL, we always use internal DT */ int __weak board_fdt_blob_setup(void **fdtp) { diff --git a/arch/arm/mach-snapdragon/include/mach/spl.h b/arch/arm/mach-snapdragon/include/mach/spl.h new file mode 100644 index 000000000000..50cc8dc4e8f8 --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/spl.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __SPL_H__ +#define __SPL_H__ + +void qcom_spl_malloc_init_f(void); +int qcom_spl_loader_pre_ddr(u8 boot_device); +void qcom_spl_error_handler(void *arg); + +#endif /* __SPL_H__ */ diff --git a/board/qualcomm/ipq5210/Makefile b/board/qualcomm/ipq5210/Makefile new file mode 100644 index 000000000000..d808c1065248 --- /dev/null +++ b/board/qualcomm/ipq5210/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SPL) := spl-ipq5210.o diff --git a/board/qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds b/board/qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds new file mode 100644 index 000000000000..f0ced6765da0 --- /dev/null +++ b/board/qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +PHDRS { + ptype PT_LOAD FLAGS(0x7); +} + +ENTRY(_entry) + +SECTIONS { + . = CONFIG_PLATFORM_ELFENTRY; + _entry = . ; + data : { + *(.data) + . = ALIGN(4); + } :ptype +} diff --git a/board/qualcomm/ipq5210/spl-ipq5210.c b/board/qualcomm/ipq5210/spl-ipq5210.c new file mode 100644 index 000000000000..5fc42e64c119 --- /dev/null +++ b/board/qualcomm/ipq5210/spl-ipq5210.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define QCCONFIG "qc_config" + +/** + * qcom_spl_soc_qclib_override() - Populate ipq5210-specific interface table + * entries. + * @table: Pointer to the QCLIB interface table being built. + * @fit: Pointer to the FIT image blob. + * @images_node: FIT "images" node offset. + * + * Appends the "qc_config" entry and a placeholder "qcsdi" entry, filled in by QCLIB itself. + * + * Return: 0 on success, or a negative error code on failure. + */ +int qcom_spl_soc_qclib_override(struct interface_table *table, + const void *fit, int images_node) +{ + int ret; + int entry_idx; + int qcconfig_node; + + qcconfig_node = fdt_subnode_offset(fit, images_node, "qcconfig_1"); + if (qcconfig_node < 0) { + pr_err("Failed to find qcconfig_1 node in FIT\n"); + return -ENOENT; + } + + entry_idx = table->num_entries; + memcpy(table->if_table_entries[entry_idx].entry_name, + QCCONFIG, strlen(QCCONFIG)); + + ret = qcom_spl_get_fit_img_entry_point((void *)fit, qcconfig_node, + &table->if_table_entries[entry_idx].address); + if (ret) { + pr_err("Failed to get qcconfig_1 entry point (%d)\n", ret); + return ret; + } + table->if_table_entries[entry_idx].attributes = 0; + table->num_entries = entry_idx + 1; + + entry_idx++; + memcpy(table->if_table_entries[entry_idx].entry_name, + QCSDI, strlen(QCSDI)); + table->if_table_entries[entry_idx].address = 0; + table->if_table_entries[entry_idx].attributes = 0; + table->num_entries = entry_idx + 1; + + return 0; +} + +/** + * qcom_spl_soc_post_qclib_routine() - Cache the QCSDI address after QCLIB + * returns. + * @if_tbl: Pointer to the QCLIB interface table, populated by QCLIB. + * + * Return: 0 on success, or a negative error code on failure. + */ +int qcom_spl_soc_post_qclib_routine(struct interface_table *if_tbl) +{ + int ret; + struct interface_table_entry qcsdi_entry; + + ret = qcom_spl_get_iftbl_entry_by_name(if_tbl, QCSDI, &qcsdi_entry); + if (ret) { + pr_err("Failed to get QCSDI entry from interface table (%d)\n", ret); + return ret; + } + + qclib_set_qcsdi_address(qcsdi_entry.address); + pr_info("QCSDI address: 0x%llx\n", qcsdi_entry.address); + + return 0; +} diff --git a/include/configs/ipq5210.h b/include/configs/ipq5210.h new file mode 100644 index 000000000000..5cbf838af824 --- /dev/null +++ b/include/configs/ipq5210.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __CONFIGS_IPQ5210_H +#define __CONFIGS_IPQ5210_H + +#include + +#endif From 7d4b66dc9c38beb8aa430bc2e3360ec597862c6d Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Jul 2026 16:41:12 +0530 Subject: [PATCH 39/52] configs: Add qcom_ipq5210_mmc_defconfig Introduce a defconfig for the Qualcomm IPQ5210 SoC based RDPs. Presently supports eMMC. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- configs/qcom_ipq5210_mmc_defconfig | 113 +++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 configs/qcom_ipq5210_mmc_defconfig diff --git a/configs/qcom_ipq5210_mmc_defconfig b/configs/qcom_ipq5210_mmc_defconfig new file mode 100644 index 000000000000..56a22ce346a8 --- /dev/null +++ b/configs/qcom_ipq5210_mmc_defconfig @@ -0,0 +1,113 @@ +CONFIG_ARM=y +CONFIG_SKIP_LOWLEVEL_INIT=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_SYS_INIT_SP_BSS_OFFSET=0x180000 +CONFIG_ARCH_SNAPDRAGON=y +CONFIG_EVENT=y +CONFIG_TEXT_BASE=0x87980000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_ENV_SIZE=0x40000 +CONFIG_ENV_OFFSET=0 +CONFIG_DEFAULT_DEVICE_TREE="qcom/ipq5210-rdp504" +CONFIG_SYS_LOAD_ADDR=0x90000000 +CONFIG_REMAKE_ELF=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +# CONFIG_BOOTSTD is not set +CONFIG_OF_BOARD_SETUP=y +CONFIG_USE_PREBOOT=y +CONFIG_SYS_PBSIZE=1024 +# CONFIG_DISPLAY_CPUINFO is not set +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +CONFIG_EFI_PARTITION=y +CONFIG_OF_LIVE=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_CLK=y +CONFIG_CLK_QCOM_IPQ5210=y +CONFIG_MSM_GPIO=y +# CONFIG_I2C is not set +# CONFIG_INPUT is not set +CONFIG_MISC=y +CONFIG_QCOM_GENI=y +CONFIG_QCOM_GENI_MINICORE=y +CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_ADMA_HELPERS is not set +# CONFIG_MMC_SDHCI_ADMA is not set +# CONFIG_MMC_SDHCI_ADMA_FORCE_32BIT is not set +# CONFIG_MMC_SDHCI_ADMA_64BIT is not set +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MTD=y +CONFIG_DM_MDIO=y +CONFIG_DM_ETH_PHY=y +CONFIG_DWC_ETH_QOS=y +CONFIG_DWC_ETH_QOS_QCOM=y +CONFIG_RGMII=y +CONFIG_PHY=y +CONFIG_PHY_QCOM_QMP_UFS=y +CONFIG_PHY_QCOM_QUSB2=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_QCOM_IPQ5210=y +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_MSM_SERIAL=y +CONFIG_MSM_GENI_SERIAL=y +CONFIG_SOC_QCOM=y +CONFIG_SPL=y +CONFIG_SPL_FRAMEWORK=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_OF_LIBFDT=y +CONFIG_SPL_DM=y +CONFIG_SPL_GPIO=y +CONFIG_SPL_DM_GPIO=y +CONFIG_SPL_DM_RESET=y +CONFIG_SPL_PINCTRL=y +CONFIG_SPL_CLK=y +CONFIG_SPL_DRIVERS_MISC=y +CONFIG_SPL_DRIVERS_MISC_SUPPORT=y +CONFIG_SPL_SERIAL=y +CONFIG_SPL_SMEM=y +CONFIG_DM_STATS=y +CONFIG_SPL_SYS_MALLOC_F=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x20000 +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SYS_MALLOC_DEFAULT_TO_INIT=y +CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y +CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x80008000 +CONFIG_SPL_SYS_MALLOC_SIZE=0x20000 +# CONFIG_SPL_SEPARATE_BSS is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set +CONFIG_SPL_BSS_MAX_SIZE=0x4000 +CONFIG_SPL_TEXT_BASE=0x08c2e000 +CONFIG_SPL_MAX_SIZE=0x3D000 +CONFIG_SPL_MMC=y +CONFIG_SPL_MMC_SDHCI_ADMA=y +CONFIG_SPL_MMC_WRITE=y +CONFIG_SPL_SYS_MMCSD_RAW_MODE=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x00 +CONFIG_COUNTER_FREQUENCY=24000000 +CONFIG_SPL_STACKPROTECTOR=y +CONFIG_SPL_LOAD_FIT=y +CONFIG_SPL_ATF=y +CONFIG_SPL_ATF_LOAD_IMAGE_V2=y +CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y +CONFIG_SPL_HAS_LOAD_FIT_ADDRESS=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0x08cbe000 +# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set +CONFIG_SPL_HAVE_INIT_STACK=y +CONFIG_SPL_STACK=0x08c2e000 +# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set +CONFIG_SPL_EVENT=y +CONFIG_SYS_BOARD="ipq5210" +CONFIG_SPL_REMAKE_ELF=y +CONFIG_SPL_REMAKE_ELF_LDSCRIPT="board/qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds" +CONFIG_QCOM_TMEL_ELF="../tmel-ipq52xx-patch.elf" +CONFIG_QCOM_GENERATE_MBN=y +CONFIG_SYSRESET_PSCI=y From 9ee9ea62fe7febd3f7587133e48e177e532334d3 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Tue, 30 Jun 2026 13:38:33 +0530 Subject: [PATCH 40/52] doc: board/qualcomm: Update RDP build instructions Add details about the SPL & U-Boot proper build steps, converting to flashable images, source URLs for the needed binaries and scripts. Reviewed-by: Simon Glass Reviewed-by: Balaji Selvanathan Signed-off-by: Varadarajan Narayanan --- doc/board/qualcomm/rdp.rst | 96 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/doc/board/qualcomm/rdp.rst b/doc/board/qualcomm/rdp.rst index 4e63fe624b8a..27101cc2d0dc 100644 --- a/doc/board/qualcomm/rdp.rst +++ b/doc/board/qualcomm/rdp.rst @@ -25,13 +25,17 @@ about image signing can be found in :doc:`signing`. The firmware expects the ELF images to be in MBN format. The `elftombn.py` tool can be used to convert the ELF images to MBN format. - IPQ9574: (MBN version 6) +IPQ9574: (MBN version 6) - $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v6 +.. code-block:: bash - IPQ5424: (MBN version 7) + python elftombn.py -f u-boot.elf -o u-boot.mbn -v6 - $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v7 +IPQ5424: (MBN version 7) + +.. code-block:: bash + + python elftombn.py -f u-boot.elf -o u-boot.mbn -v7 Then install the resulting ``u-boot.mbn`` to the ``0:APPSBL`` partition on your device with:: @@ -43,6 +47,81 @@ on your device with:: U-Boot should be running after a reboot (``reset``). +Build steps for IPQ5210 based Qualcomm Dragonwing F8 & N8 Platforms: +-------------------------------------------------------------------- + +Please refer to the following URLs for more details about the platforms. + + F8: https://www.qualcomm.com/networking-infrastructure/products/f-series/f8-platform + + N8: https://www.qualcomm.com/networking-infrastructure/products/n-series/n8-platform + +1. Since U-Boot SPL is enabled on these platforms, the build command generates + both the U-Boot SPL and U-Boot proper images. Assuming ${uboot_dir} is the + top of the U-Boot sources and ${out_dir} as the output directory, + +.. code-block:: bash + + cd ${uboot_dir} + export CROSS_COMPILE= + make -j8 O=${out_dir} qcom_ipq5210_mmc_defconfig + make -j8 O=${out_dir} + +U-Boot SPL image: ${out_dir}/spl/u-boot-spl.wrap-elf +U-Boot image: ${out_dir}/u-boot.elf + +2. Convert the SPL image to multi ELF + +.. code-block:: bash + + cd ${out_dir}/spl + python elftombn.py -f u-boot-spl.wrap-elf -o u-boot-spl.mbn -v7 + python `create_multielf.py` -f u-boot-spl.mbn,tmel-ipq52xx-patch.elf \ + -o u-boot-spl.melf + +This u-boot-spl.melf should be flashed into 0:SPL partition. +Please see below for the location of `tmel-ipq52xx-patch.elf` + +3. Convert the U-Boot image to bootloader image + +.. code-block:: bash + + cd ${out_dir} + python elftombn.py -f u-boot.elf -o u-boot.mbn -v7 + +The u-boot.mbn has to be combined with `qc_config.elf`, `QCLib.elf`, `TFA` +and `OPTEE`. Please see below for the location for these ELFs. TFA and OPTEE +can be built from the sources using the following commands + +TFA: + +.. code-block:: bash + + make PLAT=ipq52xx QTISECLIB_PATH=path/to/`libqtisec_dbg.a` SPD=opteed + +OPTEE: + +.. code-block:: bash + + make PLATFORM=qcom-ipq52xx -j16 + +These binaries can be combined into a flashable image using `gen_its.py`. + +.. code-block:: bash + + python gen_its.py --arch ipq5210 \ + --qclib_path `QCLib.elf` \ + --qcconfig_path `qc_config.elf` \ + --tfa_bl31_path bl31.mbn \ + --uboot_path u-boot.mbn \ + --optee_path tee-raw.mbn \ + -p qcconfig qclib \ + -P tfa_bl31 uboot optee \ + -o output/hm_503_test_uboot.img \ + --template `template.its` + +This should be flashed into 0:BOOTLDR partition. + .. WARNING Boards with newer software versions would automatically go the emergency download (EDL) mode if U-Boot is not functioning as expected. If its a @@ -55,5 +134,14 @@ U-Boot should be running after a reboot (``reset``). Note that the support added is very basic. Restoring the original U-Boot on boards with older version of the software requires a debugger. +.. _create_multielf.py: https://raw.githubusercontent.com/coreboot/coreboot/refs/heads/main/util/qualcomm/create_multielf.py .. _elftombn.py: https://git.codelinaro.org/clo/qsdk/oss/system/tools/meta/-/tree/NHSS.QSDK.13.0.5.r2/scripts?ref_type=heads .. _edl: https://github.com/bkerler/edl +.. _gen_its.py: https://git.codelinaro.org/clo/qsdk/oss/system/tools/meta/-/tree/win.platform_tools.1.0.r34/scripts?ref_type=heads +.. _libqtisec_dbg.a: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/WIN.TFA.1.0.R4/apss_proc/out/proprietary/qtiseclib/output/ipq52xx/release/libqtisec_dbg.a +.. _OPTEE: https://git.codelinaro.org/clo/trusted-firmware/optee_os/optee_os/-/tree/win.optee.1.0?ref_type=heads +.. _qc_config.elf: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/BOOT.MXF.2.3.1.1/boot_images/boot/QcomPkg/SocPkg/Hermosa/Bin/LC/RELEASE/qc_config.elf +.. _QCLib.elf: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/BOOT.MXF.2.3.1.1/boot_images/boot/QcomPkg/SocPkg/Hermosa/Bin/LC/RELEASE/QCLib.elf +.. _template.its: https://git.codelinaro.org/clo/qsdk/oss/system/tools/meta/-/tree/win.platform_tools.1.0.r34/scripts?ref_type=heads +.. _TFA: https://git.codelinaro.org/clo/trusted-firmware/tf-a/trusted-firmware-a/-/tree/win.tfa.1.0.r4?ref_type=heads +.. _tmel-ipq52xx-patch.elf: https://softwarecenter.qualcomm.com/nexus/generic/product/chip/software-product/IPQ5210.NLQ.14.0/ipq5210.nlq.14.0-qca-oem-qartifact/r00036.1/TMEL.WNS.2.4/tmel-ipq52xx-patch.elf From 1ebc3e5097fa325272e282fac5939d8f87f1a501 Mon Sep 17 00:00:00 2001 From: "abhilash.v" Date: Thu, 3 Sep 2026 04:24:11 -0700 Subject: [PATCH 41/52] configs: qcom_ipq5210_mmc: fix SPL build Enable the missing SPL IPQ5210 pinctrl and GENI options. Disable MBN generation, which is unsupported for this platform. Only register the MSM SDHCI tuning callback when MMC tuning is enabled, avoiding an SPL reference to mmc_send_tuning(). Signed-off-by: abhilash.v --- configs/qcom_ipq5210_mmc_defconfig | 9 +++++---- drivers/mmc/msm_sdhci.c | 4 ++++ drivers/pinctrl/qcom/Kconfig | 8 ++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/configs/qcom_ipq5210_mmc_defconfig b/configs/qcom_ipq5210_mmc_defconfig index 56a22ce346a8..0d85ed5a1288 100644 --- a/configs/qcom_ipq5210_mmc_defconfig +++ b/configs/qcom_ipq5210_mmc_defconfig @@ -33,7 +33,6 @@ CONFIG_MSM_GPIO=y CONFIG_MISC=y CONFIG_QCOM_GENI=y CONFIG_QCOM_GENI_MINICORE=y -CONFIG_MMC_HS200_SUPPORT=y CONFIG_MMC_SDHCI=y # CONFIG_MMC_SDHCI_ADMA_HELPERS is not set # CONFIG_MMC_SDHCI_ADMA is not set @@ -68,9 +67,12 @@ CONFIG_SPL_GPIO=y CONFIG_SPL_DM_GPIO=y CONFIG_SPL_DM_RESET=y CONFIG_SPL_PINCTRL=y +CONFIG_SPL_PINCTRL_QCOM_IPQ5210=y CONFIG_SPL_CLK=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_DRIVERS_MISC_SUPPORT=y +CONFIG_SPL_QCOM_GENI=y +CONFIG_SPL_MSM_GENI_SERIAL=y CONFIG_SPL_SERIAL=y CONFIG_SPL_SMEM=y CONFIG_DM_STATS=y @@ -108,6 +110,5 @@ CONFIG_SPL_EVENT=y CONFIG_SYS_BOARD="ipq5210" CONFIG_SPL_REMAKE_ELF=y CONFIG_SPL_REMAKE_ELF_LDSCRIPT="board/qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds" -CONFIG_QCOM_TMEL_ELF="../tmel-ipq52xx-patch.elf" -CONFIG_QCOM_GENERATE_MBN=y -CONFIG_SYSRESET_PSCI=y +# CONFIG_QCOM_GENERATE_MBN is not set +CONFIG_SYSRESET_PSCI=y \ No newline at end of file diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 71a5aa159584..155bc2ef3791 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -558,6 +558,7 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) return sdhci_msm_cm_dll_sdc4_calibration(host); } +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int msm_find_most_appropriate_phase(struct sdhci_host *host, u8 *phase_table, u8 total_phases) @@ -711,6 +712,7 @@ static int sdhci_msm_execute_tuning(struct mmc *mmc, u8 opcode) return rc; } +#endif /* * Configure HC mode selection. Runs from set_control_reg(), which the @@ -907,7 +909,9 @@ static int msm_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enable) struct sdhci_ops msm_sdhci_ops = { .config_dll = &msm_sdhci_config_dll, .set_control_reg = &sdhci_msm_set_control_reg, +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .platform_execute_tuning = &sdhci_msm_execute_tuning, +#endif }; static int msm_sdc_probe(struct udevice *dev) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index ce69a1e73289..37775f0a484f 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -84,6 +84,14 @@ config PINCTRL_QCOM_IPQ5210 Say Y here to enable support for pinctrl on the IPQ5210 SoC, as well as the associated GPIO driver. +config SPL_PINCTRL_QCOM_IPQ5210 + bool "Qualcomm IPQ5210 Pinctrl in SPL" + depends on SPL_PINCTRL_GENERIC + select SPL_PINCTRL_QCOM + help + SPL variant of PINCTRL_QCOM_IPQ5210. + See the help of PINCTRL_QCOM_IPQ5210 for details. + config PINCTRL_QCOM_IPQ5424 bool "Qualcomm IPQ5424 Pinctrl" default y if PINCTRL_QCOM_GENERIC From b703a8b518b213363de51495f8838efa51c1fef2 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:09:46 +0530 Subject: [PATCH 42/52] mach-snapdragon: Kconfig: Add SPL_QCOM_BOOT_FROM_PBL and SPL_WRAPPER_ELF options Add two Kconfig options needed by boards whose SPL is not loaded directly by PBL: - SPL_QCOM_BOOT_FROM_PBL: gates whether spl_boot_device() trusts the pbl_shared_data structure passed via r0. Boards loaded by an intermediate bootloader (e.g. PBL->XBL->U-Boot SPL) don't get valid PBL shared data in r0 and must rely on a board-specific spl_boot_device() override instead. Defaults to y to preserve existing behavior for boards loaded directly by PBL. - SPL_WRAPPER_ELF: enables wrapping the U-Boot SPL binary in a wrapper ELF for boards whose boot ROM / signing tool expects the SPL image embedded as an ELF segment. Signed-off-by: smadhesu --- arch/arm/mach-snapdragon/Kconfig | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index d85cfbcb4833..cd201cd32fe9 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -138,6 +138,28 @@ config QCOM_TMEL_ELF Path of the TME Elf file to be concatenated to u-boot.mbn to create boot rom expected multi-elf image +config SPL_QCOM_BOOT_FROM_PBL + bool "U-Boot SPL is loaded directly by PBL" + depends on SPL + default y + help + Enable this option when U-Boot SPL is loaded directly by PBL (Primary + Boot Loader). In this case, PBL passes boot parameters via r0 register + containing a pointer to pbl_shared_data structure. + + Disable this option when U-Boot SPL is loaded by XBL or another + intermediate bootloader (e.g., PBL->XBL->U-Boot SPL). In such cases, + the r0 register won't contain valid PBL shared data, and boot device + detection will use fallback mechanisms. + +config SPL_WRAPPER_ELF + bool "Create wrapper ELF for applicable platforms" + depends on SPL + help + Some platforms embed the U-Boot SPL binary within an ELF as a segment. + Additional tools are used to convert this ELF into an image that is + usable for the boot ROM. + choice prompt "Qualcomm boot0.h workaround" optional From 6fa4b4c85a435004592a85c51de110f211e5b3a9 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:09:57 +0530 Subject: [PATCH 43/52] mach-snapdragon: pbl-shared-data: Gate boot-device detection on SPL_QCOM_BOOT_FROM_PBL spl_boot_device() currently assumes the pbl_shared_data structure passed via r0 is always valid, which only holds when U-Boot SPL is loaded directly by PBL. On boards where SPL is loaded by an intermediate bootloader, r0 does not contain valid PBL shared data, so this parsing must be skipped in favor of a board-specific spl_boot_device() override. Wrap the existing boot-media detection logic in a check for CONFIG_SPL_QCOM_BOOT_FROM_PBL so it only runs when applicable. Signed-off-by: smadhesu --- arch/arm/mach-snapdragon/pbl-shared-data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-snapdragon/pbl-shared-data.c b/arch/arm/mach-snapdragon/pbl-shared-data.c index b9dce22c4171..a4b7533924c7 100644 --- a/arch/arm/mach-snapdragon/pbl-shared-data.c +++ b/arch/arm/mach-snapdragon/pbl-shared-data.c @@ -83,7 +83,7 @@ void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3) u32 __weak spl_boot_device(void) { struct pbl_shared_data *psd = &g_psd; - + if (CONFIG_IS_ENABLED(QCOM_BOOT_FROM_PBL)) { #ifdef DEBUG for (int i = 0; psd && i < psd->num_of_entries; i++) { printf("entry[0x%x] = %d 0x%08x %d\n", i, @@ -118,7 +118,7 @@ u32 __weak spl_boot_device(void) return BOOT_DEVICE_UFS; } } - + } out: pr_err("No boot device configured\n"); return BOOT_DEVICE_NONE; From 020145aa77491ed62c19e23a850aa4ef1b91e1fb Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:10:06 +0530 Subject: [PATCH 44/52] pinctrl: qcom: Add SPL_PINCTRL_QCOM_NORD Kconfig option Add the SPL variant of PINCTRL_QCOM_NORD so the Nord pinctrl/GPIO driver can be built into SPL, needed for Nord-Ride SPL to configure pins (e.g. for UFS) before DDR/full driver model bring-up. Signed-off-by: smadhesu --- drivers/pinctrl/qcom/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 37775f0a484f..5e4cf2951c93 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -148,6 +148,14 @@ config PINCTRL_QCOM_NORD Say Y here to enable support for pinctrl on the Snapdragon Nord SoC, as well as the associated GPIO driver. +config SPL_PINCTRL_QCOM_NORD + bool "Qualcomm Nord Pinctrl in SPL" + depends on SPL_PINCTRL_GENERIC + select SPL_PINCTRL_QCOM + help + SPL variant of PINCTRL_QCOM_NORD. + See the help of PINCTRL_QCOM_NORD for details. + config PINCTRL_QCOM_QCM2290 bool "Qualcomm QCM2290 Pinctrl" default y if PINCTRL_QCOM_GENERIC From 9d868fa73659a30474114724a04e1fecaeab3462 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Thu, 3 Sep 2026 15:57:11 +0530 Subject: [PATCH 45/52] configs: qcom: Add qcom_nord_ride_spl_defconfig Add the SPL defconfig for Nord-Ride dev boards using the "Linux Embedded" partition layout (dedicated "uefi" partition for edk2/ U-Boot). SPL loads a FIT image containing TF-A, OP-TEE and U-Boot proper from the "uefi_a" UFS raw partition and hands off to TF-A via CONFIG_SPL_ATF. SPL's memory region (0xbc180000-0xbc280000) lays out TEXT, the FIT load buffer, stack, and malloc/fastboot pool bottom-to-top with explicit gaps, validated on nord-ride hardware. UFS boot parameters (devnum 4, partition "uefi_a"/1) come from the target's confirmed partition table. CONFIG_SPL_QCOM_BOOT_FROM_PBL is left disabled since nord-ride boots via UFS raw partition rather than PBL, and CONFIG_SPL_WRAPPER_ELF/the 4K-aligned wrap-elf build is used to meet the board's boot ROM signing requirements. Signed-off-by: smadhesu --- configs/qcom_nord_ride_spl_defconfig | 112 +++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 configs/qcom_nord_ride_spl_defconfig diff --git a/configs/qcom_nord_ride_spl_defconfig b/configs/qcom_nord_ride_spl_defconfig new file mode 100644 index 000000000000..a46963c76748 --- /dev/null +++ b/configs/qcom_nord_ride_spl_defconfig @@ -0,0 +1,112 @@ +# Configuration for building U-Boot to be flashed +# to the uefi partition of Nord-Ride dev boards with +# the "Linux Embedded" partition layout (which have +# a dedicated "uefi" partition for edk2/U-Boot) + +#include "qcom_defconfig" + +# Otherwise buildman thinks this isn't an ARM platform +CONFIG_ARM=y + +CONFIG_FASTBOOT_BUF_ADDR=0xbc238000 +# CONFIG_OF_UPSTREAM is not set +CONFIG_DEFAULT_DEVICE_TREE="nord-ride" +CONFIG_TEXT_BASE=0xD8D00000 +CONFIG_REMAKE_ELF=y +CONFIG_EVENT=y +CONFIG_ENV_IS_IN_SCSI=y +CONFIG_ENV_SCSI_PART_USE_TYPE_GUID=y +# SCSI partition type GUID for logfs partition +CONFIG_ENV_SCSI_PART_TYPE_GUID="bc0330eb-3410-4951-a617-03898dbe3372" +# CONFIG_ENV_IS_DEFAULT is not set +# CONFIG_ENV_IS_NOWHERE is not set + +# SPL configurations for Nord-Ride +# Purpose: Load FIT image (containing TFA, OPTEE and U-Boot proper) +# from UFS storage and jump to next image (TFA) + +CONFIG_SPL=y +CONFIG_SPL_BUILD=y +CONFIG_SPL_FRAMEWORK=y +CONFIG_SPL_EVENT=y + +CONFIG_SPL_TEXT_BASE=0xbc180000 +CONFIG_SPL_MAX_SIZE=0x60000 +CONFIG_SPL_BSS_LIMIT=y +CONFIG_SPL_BSS_MAX_SIZE=0x10000 +# CONFIG_SPL_SEPARATE_BSS is not set + +# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set +CONFIG_SPL_HAVE_INIT_STACK=y +CONFIG_SPL_STACK=0xbc228000 + +CONFIG_SPL_SYS_MALLOC_F_LEN=0x10000 +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y +CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0xbc238000 +CONFIG_SPL_SYS_MALLOC_SIZE=0x48000 + +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y + +CONFIG_SPL_DM=y +CONFIG_SPL_OF_LIBFDT=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_SPL_OF_REAL=y +CONFIG_SPL_SIMPLE_BUS=y + +CONFIG_SPL_DM_RESET=y + +CONFIG_SPL_CLK=y + +CONFIG_SPL_GPIO=y +CONFIG_SPL_DM_GPIO=y + +CONFIG_SPL_UFS=y +CONFIG_SPL_UFS_QCOM=y + +CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM=4 +CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR=0x0 +CONFIG_SPL_UFS_RAW_U_BOOT_USE_PARTITION=y +CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME="uefi_a" +CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NUM=1 + +CONFIG_SPL_PARTITIONS=y +CONFIG_SPL_DOS_PARTITION=y +CONFIG_SPL_CHARSET=y + +CONFIG_SPL_PHY=y +CONFIG_SPL_PHY_QCOM_QMP_UFS=y + +CONFIG_SPL_POWER=y +CONFIG_SPL_POWER_DOMAIN=y + +CONFIG_SPL_LOAD_FIT=y + +CONFIG_SPL_ATF=y + +CONFIG_SPL_REMAKE_ELF=y + +CONFIG_COUNTER_FREQUENCY=19200000 + +# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set +# CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR is not set +CONFIG_SPL_ATF_LOAD_IMAGE_V2=y +CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y +CONFIG_SPL_HAS_LOAD_FIT_ADDRESS=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0xbc1e8000 + +CONFIG_SPL_DRIVERS_MISC=y +CONFIG_SPL_SERIAL=y +CONFIG_SPL_MISC=y +CONFIG_SPL_QCOM_GENI=y +CONFIG_SPL_MSM_GENI_SERIAL=y + +CONFIG_SPL_BANNER_PRINT=y +CONFIG_SPL_CLK_STUB=y +CONFIG_SPL_PINCTRL=y +CONFIG_SPL_PINCTRL_QCOM_NORD=y +CONFIG_SPL_QCOM_SMEM=y +# CONFIG_SPL_QCOM_BOOT_FROM_PBL is not set +CONFIG_SYS_BOARD="nord" +CONFIG_SPL_WRAPPER_ELF=y From 7736b966a2b45a71a3d262aa9fac3254efe7548c Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:10:23 +0530 Subject: [PATCH 46/52] board: qualcomm: nord: Add SPL board support for Nord-Ride Add the board-specific SPL bring-up for Nord-Ride: - spl-nord.c: nord-ride always boots the SPL FIT image from a fixed UFS raw partition rather than via PBL, so spl_boot_device() is hard-coded to BOOT_DEVICE_UFS instead of relying on pbl_shared_data (see SPL_QCOM_BOOT_FROM_PBL). Also provides board_init_f() to clear BSS, set up malloc, run early init and console, then hand off to board_init_r(). - nord-spl-wrap-elf.lds: linker script for the SPL_WRAPPER_ELF build, wrapping the SPL binary in a single 4K-aligned PT_LOAD segment as required by nord-ride's boot ROM / image-signing tool. - include/configs/nord.h: board config header (CONFIG_SYS_CONFIG_NAME target), currently empty aside from the include guard. Signed-off-by: smadhesu --- .../arm/mach-snapdragon/nord-spl-wrap-elf.lds | 18 +++++ board/qualcomm/nord/Makefile | 2 + board/qualcomm/nord/spl-nord.c | 69 +++++++++++++++++++ include/configs/nord.h | 11 +++ 4 files changed, 100 insertions(+) create mode 100644 arch/arm/mach-snapdragon/nord-spl-wrap-elf.lds create mode 100644 board/qualcomm/nord/Makefile create mode 100644 board/qualcomm/nord/spl-nord.c create mode 100644 include/configs/nord.h diff --git a/arch/arm/mach-snapdragon/nord-spl-wrap-elf.lds b/arch/arm/mach-snapdragon/nord-spl-wrap-elf.lds new file mode 100644 index 000000000000..b5c532499af5 --- /dev/null +++ b/arch/arm/mach-snapdragon/nord-spl-wrap-elf.lds @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +PHDRS { + ptype PT_LOAD FLAGS(0x7); +} + +ENTRY(_entry) + +SECTIONS { + . = IMAGE_TEXT_BASE; + _entry = . ; + data : { + *(.data) + . = ALIGN(0x1000); + } :ptype +} diff --git a/board/qualcomm/nord/Makefile b/board/qualcomm/nord/Makefile new file mode 100644 index 000000000000..1827dc93dbbe --- /dev/null +++ b/board/qualcomm/nord/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_SPL) := spl-nord.o diff --git a/board/qualcomm/nord/spl-nord.c b/board/qualcomm/nord/spl-nord.c new file mode 100644 index 000000000000..3a91c1d7a30c --- /dev/null +++ b/board/qualcomm/nord/spl-nord.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/** + * spl_boot_device() - Report the boot device for nord-ride. + * + * nord-ride always boots the SPL FIT image from a UFS raw partition + * rather than via PBL, so the boot device is fixed. + * + * Return: BOOT_DEVICE_UFS + */ +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_UFS; +} + +#if defined(CONFIG_SPL_BUILD) +/** + * board_init_f() - Main entry point for SPL. + * @dummy: Dummy argument (unused). + */ +void board_init_f(ulong dummy) +{ + int ret = 0; + + memset(__bss_start, 0, __bss_end - __bss_start); /* Clear BSS */ + + qcom_spl_malloc_init_f(); + + ret = spl_early_init(); + if (ret) { + pr_debug("spl_early_init() failed (%d)\n", ret); + goto fail; + } + + event_notify_null(EVT_LAST_STAGE_INIT); + + preloader_console_init(); + + + board_init_r(NULL, 0); + +fail: + if (ret) + reset_cpu(); +} +#endif /* CONFIG_SPL_BUILD */ diff --git a/include/configs/nord.h b/include/configs/nord.h new file mode 100644 index 000000000000..3b3793ad475b --- /dev/null +++ b/include/configs/nord.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __CONFIGS_NORD_H +#define __CONFIGS_NORD_H + +#include + +#endif From c50c6f8a6c10b0636a7c7a9a2f2947e18bb99016 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:10:32 +0530 Subject: [PATCH 47/52] mach-snapdragon: fit-handler: Pass TOC FDT load address to BL32 Some SPL FIT images carry an optional "toc_fdt" image node intended for BL32 (OP-TEE), used to locate the TOC FDT that OP-TEE consumes. This node is loaded into memory by the generic FIT loadables path regardless of QCOM_BOOT_FROM_PBL, but its load address was never communicated to BL32. Add qcom_spl_get_toc_fdt_address() to look up the "toc_fdt" node's load address from the FIT at CONFIG_SPL_LOAD_FIT_ADDRESS, and call it from bl2_plat_get_bl31_params_v2() so the address can be passed to BL32 via arg0. The node is optional: boards whose FIT carries no "toc_fdt" node are unaffected and BL32 receives arg0=0. Signed-off-by: smadhesu --- arch/arm/mach-snapdragon/fit-handler.c | 68 ++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/arch/arm/mach-snapdragon/fit-handler.c b/arch/arm/mach-snapdragon/fit-handler.c index fc419bd3f008..a2a6c179f4fc 100644 --- a/arch/arm/mach-snapdragon/fit-handler.c +++ b/arch/arm/mach-snapdragon/fit-handler.c @@ -10,6 +10,14 @@ #include #include +#define TOC_FDT "toc_fdt" + +/* + * Global TOC FDT load address populated by qcom_spl_get_toc_fdt_address + * Placed in .data section to ensure it persists + */ +static u64 g_toc_fdt_address __section(".data"); + /** * qcom_spl_get_fit_img_entry_point() - Get entry point from FIT image node. * @fit: Pointer to the FIT image blob. @@ -88,6 +96,49 @@ int qcom_spl_get_iftbl_entry_by_name(struct interface_table *if_tbl, return -ENOENT; } +/** + * qcom_spl_get_toc_fdt_address() - Look up the TOC FDT load address in the FIT + * + * Finds the optional "toc_fdt" image node in the FIT at + * CONFIG_SPL_LOAD_FIT_ADDRESS and records its load address in + * g_toc_fdt_address, for later use by bl2_plat_get_bl31_params_v2(). + * + * This is independent of qclib_post_process_from_spl(): the TOC FDT is + * already loaded into memory by the generic FIT loadables path, so its + * address only needs to be looked up, not computed by QCLIB. + */ +static void qcom_spl_get_toc_fdt_address(void) +{ + int ret; + int images_node; + int toc_fdt_node; + const void *fit = (const void *)CONFIG_SPL_LOAD_FIT_ADDRESS; + + images_node = fdt_subnode_offset(fit, 0, "images"); + if (images_node < 0) { + pr_err("Failed to find images node in FIT\n"); + return; + } + + /* + * This node is optional: boards whose FIT image carries no TOC FDT + * for BL31 are unaffected and g_toc_fdt_address remains 0. + */ + toc_fdt_node = fdt_subnode_offset(fit, images_node, TOC_FDT); + if (toc_fdt_node < 0) { + pr_debug("No '%s' node in FIT, BL31 will not receive a TOC FDT address\n", + TOC_FDT); + return; + } + + ret = qcom_spl_get_fit_img_entry_point((void *)fit, toc_fdt_node, + &g_toc_fdt_address); + if (ret) + pr_warn("Failed to get '%s' load address (%d)\n", TOC_FDT, ret); + else + printf("TOC FDT address: 0x%lx\n", (unsigned long)g_toc_fdt_address); +} + /** * bl2_plat_get_bl31_params_v2() - Retrieve and fixup BL31 parameters. * @bl32_entry: Entry point for BL32 (OP-TEE). @@ -110,6 +161,13 @@ struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry, bl_params = bl2_plat_get_bl31_params_v2_default(bl32_entry, bl33_entry, fdt_addr); + /* + * The TOC FDT is loaded into memory by the generic FIT loadables + * path regardless of QCOM_BOOT_FROM_PBL, so its load address is + * looked up here rather than in qclib_post_process_from_spl(). + */ + qcom_spl_get_toc_fdt_address(); + /* * Fixup the bl31 params based on platform requirements. */ @@ -124,6 +182,16 @@ struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry, node->ep_info->args.arg0 = qcsdi_address; pr_debug("Setting BL31 arg0 to QCSDI address: 0x%llx\n", qcsdi_address); + } else if (node->image_id == ATF_BL32_IMAGE_ID) { + /* + * Pass TOC FDT load address to BL32 via arg0 + */ + if (g_toc_fdt_address == 0) + pr_debug("TOC FDT address not set, BL32 will get arg0=0\n"); + + node->ep_info->args.arg0 = g_toc_fdt_address; + printf("TOC FDT address passed to BL32 (arg0): 0x%lx\n", + (unsigned long)node->ep_info->args.arg0); } } From beabbfdc82b52929ae2b9e3856fdbb96dfd8bc56 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:10:38 +0530 Subject: [PATCH 48/52] configs: qcom_nord_ride_spl: Disable SPL_MMC Nord-Ride boots the SPL FIT image from UFS, not MMC. Explicitly disable CONFIG_SPL_MMC so the MMC boot path is not built into SPL. Signed-off-by: smadhesu --- configs/qcom_nord_ride_spl_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/qcom_nord_ride_spl_defconfig b/configs/qcom_nord_ride_spl_defconfig index a46963c76748..ca2bab9d85bb 100644 --- a/configs/qcom_nord_ride_spl_defconfig +++ b/configs/qcom_nord_ride_spl_defconfig @@ -62,6 +62,8 @@ CONFIG_SPL_CLK=y CONFIG_SPL_GPIO=y CONFIG_SPL_DM_GPIO=y +# CONFIG_SPL_MMC is not set + CONFIG_SPL_UFS=y CONFIG_SPL_UFS_QCOM=y From 14515d72eadf5b2e16ac41f6d8be5accf36d67c6 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 20:10:49 +0530 Subject: [PATCH 49/52] common: spl: Add progress prints for FIT image loading and BL31 entry Print which image is being loaded from the FIT (spl_load_simple_fit's load_simple_fit()) and the BL31 entry address just before jumping (spl_invoke_atf's bl31_entry()). These give visibility into SPL's boot progress on platforms without more detailed boot logging, e.g. "Loading image: tfa" / "Loading image: uboot" / "Loading image: optee" and "Jumping to BL31 at 0x...". Signed-off-by: smadhesu --- common/spl/spl_atf.c | 1 + common/spl/spl_fit.c | 1 + 2 files changed, 2 insertions(+) diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c index 8bc5db773950..2e28ad7ad292 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -206,6 +206,7 @@ static void __noreturn bl31_entry(ulong bl31_entry, ulong bl32_entry, if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) dcache_disable(); + printf("Jumping to BL31 at 0x%lx\n", bl31_entry); atf_entry(bl31_params, (void *)fdt_addr); } diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 18bff7b8d4af..e83866d25d9f 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -230,6 +230,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, bool external_data = false; log_debug("starting\n"); + printf("Loading image: %s\n", fit_get_name(fit, node, NULL)); if (CONFIG_IS_ENABLED(BOOTMETH_VBE) && xpl_get_phase(info) != IH_PHASE_NONE) { enum image_phase_t phase; From 9b5e7ea4701f25156fd71b8e7dd9e52d96364ca5 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 15:25:34 +0530 Subject: [PATCH 50/52] arm64: dts: qcom: nord-ride: Tag SPL-required nodes with bootph-all nord-ride's SPL FDT is trimmed to only the nodes tagged bootph-all. Tag the root clock inputs (xo_board_clk, sleep_clk), the negcc clock controller, tlmm (pinctrl, needed for UFS reset-gpios), ufs_mem_phy, ufs_mem_hc, the debug UART and its parent qupv3_0 wrapper, smem, and its reserved-memory carveout, so all of these survive into the SPL FDT instead of being trimmed away. Signed-off-by: smadhesu --- arch/arm/dts/nord-ride-u-boot.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/dts/nord-ride-u-boot.dtsi b/arch/arm/dts/nord-ride-u-boot.dtsi index 66500a979e9d..fdc91473817a 100644 --- a/arch/arm/dts/nord-ride-u-boot.dtsi +++ b/arch/arm/dts/nord-ride-u-boot.dtsi @@ -15,6 +15,14 @@ #include +&xo_board_clk { + bootph-all; +}; + +&sleep_clk { + bootph-all; +}; + / { negcc: clock-controller@8900000 { compatible = "qcom,nord-negcc"; @@ -22,6 +30,7 @@ #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; + bootph-all; }; ufs_mem_phy: phy@1d40000 { @@ -38,11 +47,13 @@ #phy-cells = <0>; status = "okay"; + bootph-all; }; smem { compatible = "qcom,smem"; memory-region = <&smem_region>; + bootph-all; }; sram: sram@146d8000 { @@ -71,9 +82,14 @@ smem_region: smem-region@89b00000 { reg = <0x0 0x89b00000 0x0 0x400000>; no-map; + bootph-all; }; }; +&tlmm { + bootph-all; +}; + &ufs_mem_hc { compatible = "qcom,sa8797p-ufshc", "qcom,sa8255p-ufshc", @@ -101,6 +117,8 @@ phys = <&ufs_mem_phy>; phy-names = "ufsphy"; + + bootph-all; }; &uart4 { @@ -113,12 +131,14 @@ compatible = "qcom,sa8797p-geni-debug-uart", "qcom,sa8255p-geni-debug-uart", "qcom,geni-debug-uart"; + bootph-all; }; &qupv3_0 { compatible = "qcom,sa8797p-geni-se-qup", "qcom,sa8255p-geni-se-qup", "qcom,geni-se-qup"; + bootph-all; }; &qupv3_1 { From 8896d72ead86bc980f53febfb7389201eae929a2 Mon Sep 17 00:00:00 2001 From: smadhesu Date: Tue, 8 Sep 2026 15:43:28 +0530 Subject: [PATCH 51/52] mach-snapdragon: Makefile.xpl: Use 4K page size for nord wrap-elf nord-ride's boot ROM / image-signing tool requires the wrapper ELF's single PT_LOAD segment to be 4K-aligned. Guard the added linker flags behind QCOM_SPL_SOC == nord so this only affects nord's wrap-elf build and does not regress lemans/shikra/ipq5210, which also use the wrap-elf mechanism but don't need this alignment. Signed-off-by: smadhesu --- scripts/Makefile.xpl | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/scripts/Makefile.xpl b/scripts/Makefile.xpl index a3fd3e1375f7..23a19b72d9ec 100644 --- a/scripts/Makefile.xpl +++ b/scripts/Makefile.xpl @@ -256,6 +256,30 @@ MKIMAGEFLAGS_boot.bin = -T zynqmpimage -R $(srctree)/$(CONFIG_BOOT_INIT_FILE) \ -n "$(shell cd $(srctree); readlink -f $(CONFIG_PMUFW_INIT_FILE))" endif +ifeq ($(CONFIG_SPL_WRAPPER_ELF),y) +# Convert ELF to object file +OBJCOPYFLAGS_$(SPL_BIN).bin.o = -I binary -O elf64-littleaarch64 + +# Wrap the object file inside a ELF +QCOM_SPL_SOC = $(shell echo $(notdir "$(CONFIG_DEFAULT_DEVICE_TREE)") | cut -f1 -d-) +QCOM_SPL_WRAP_LDS = $(srctree)/arch/arm/mach-snapdragon/$(QCOM_SPL_SOC)-spl-wrap-elf.lds +LDFLAGS_$(SPL_BIN).wrap-elf = -T $(obj)/$(SPL_BIN).wrap-elf.lds + +ifeq ($(QCOM_SPL_SOC),nord) +LDFLAGS_$(SPL_BIN).wrap-elf += -z common-page-size=0x1000 -z max-page-size=0x1000 +endif + +$(obj)/$(SPL_BIN).wrap-elf.lds: $(QCOM_SPL_WRAP_LDS) FORCE + $(call if_changed_dep,cpp_lds) + +$(obj)/$(SPL_BIN).bin.o: $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).wrap-elf.lds FORCE + $(call if_changed,objcopy) + +$(obj)/$(SPL_BIN).wrap-elf: $(obj)/$(SPL_BIN).bin.o FORCE + $(call if_changed,ld) + +endif + $(obj)/$(SPL_BIN)-align.bin: $(obj)/$(SPL_BIN).bin @dd if=$< of=$@ conv=sync bs=4 2>/dev/null; @@ -302,6 +326,10 @@ INPUTS-$(CONFIG_ARCH_ZYNQMP) += $(obj)/boot.bin INPUTS-$(CONFIG_ARCH_MEDIATEK) += $(obj)/u-boot-spl-mtk.bin +ifeq ($(CONFIG_ARCH_SNAPDRAGON),y) +INPUTS-$(CONFIG_SPL_WRAPPER_ELF) += $(obj)/u-boot-spl.wrap-elf +endif + all: $(INPUTS-y) quiet_cmd_cat = CAT $@ From 99cfcf9d0996d2aeddc4a94dd1bd349fd2ca3932 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Mon, 10 Aug 2026 22:30:05 +0530 Subject: [PATCH 52/52] misc: qcom_geni: add QCOM_GENI_FW_LOAD to gate late fw init qcom_geni_fw_initialise() was unconditionally registered on EVT_LAST_STAGE_INIT for non-SPL builds. Add CONFIG_QCOM_GENI_FW_LOAD to make this optional, and disable it by default in qcom_defconfig for boards that don't need GENI firmware loading. Signed-off-by: Aswin Murugan --- configs/qcom_defconfig | 1 + drivers/misc/Kconfig | 9 +++++++++ drivers/misc/qcom_geni.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index ae4678b35286..f8274f943578 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -113,6 +113,7 @@ CONFIG_QCOM_HYP_SMMU=y CONFIG_MISC=y CONFIG_NVMEM=y CONFIG_QCOM_GENI=y +# CONFIG_QCOM_GENI_FW_LOAD is not set CONFIG_I2C_EEPROM=y CONFIG_SYS_MMC_MAX_BLK_COUNT=16384 CONFIG_MMC_HS400_SUPPORT=y diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index baba41ee2517..76eae1d07dea 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -125,6 +125,15 @@ config QCOM_GENI_MINICORE help Enable support for minicores in Qualcomm GENI and its peripherals. +config QCOM_GENI_FW_LOAD + bool "Load Qualcomm GENI peripheral firmware at late init" + depends on QCOM_GENI + default y + help + Load firmware for GENI peripherals from the firmware partition + at late init. Disable if no GENI peripheral needs firmware + loading. + config ROCKCHIP_EFUSE bool "Rockchip e-fuse support" depends on MISC diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c index f3133f858858..f3cba695f103 100644 --- a/drivers/misc/qcom_geni.c +++ b/drivers/misc/qcom_geni.c @@ -626,7 +626,9 @@ static int qcom_geni_fw_initialise(void) return 0; } +#if IS_ENABLED(CONFIG_QCOM_GENI_FW_LOAD) EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qcom_geni_fw_initialise); +#endif static const struct udevice_id geni_ids[] = { { .compatible = "qcom,geni-se-qup" },