From 6d9d0ab3a80d203beb0b58fc704bf97b4d394677 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 2 Sep 2026 22:55:46 +0530 Subject: [PATCH 01/41] 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 e34d28ede838cccce02170160ccdac10fc0d8049 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 2 Sep 2026 22:57:24 +0530 Subject: [PATCH 02/41] 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 29567b66ff9a..483b750d5dcf 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -42,20 +42,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 fc246740be0f468e90e7117a2fdcbcc1949e77e5 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 2 Sep 2026 22:57:24 +0530 Subject: [PATCH 03/41] 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 483b750d5dcf..dbe38fb3912a 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -83,14 +83,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 7f990b7ecd8f..8bf0c9175fbb 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 7e979863dfcc..142ccbcaee02 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 ba866b5b6b2e..c5e03baca9ac 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 8145ae37cb46..41f37b0e1756 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 a5ad153afffb28c59e596b6229e00ce72e0dea7f Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:43 +0200 Subject: [PATCH 04/41] 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 d84d7ab9b8dd8ebf0bf394fb92909fe5bb124db3 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:44 +0200 Subject: [PATCH 05/41] 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 4aaebfa874ac04faded2d4ab85f5ac6d7ceb823e Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:45 +0200 Subject: [PATCH 06/41] 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 15d1efb5d7c042c377ba6193f568322d802c23d6 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:46 +0200 Subject: [PATCH 07/41] 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 fabb816b37ca06a10e07139d1f478f94f7e675fc Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:47 +0200 Subject: [PATCH 08/41] 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 e5de815d8cae..c8cfbf5d5de2 100644 --- a/Kconfig +++ b/Kconfig @@ -572,6 +572,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 dbe38fb3912a..f7ec5e6fd3a6 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -111,5 +111,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 2b07a887054255f0272167daddd2f276139832ee Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 11 May 2026 15:57:48 +0200 Subject: [PATCH 09/41] 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 7045da8baeca..0d673d1b9a7a 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 da5ab1faadcd..9447806ce75c 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 cc2fb7879e88..0d042dd4093d 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 f67a10fe4904fe31f332d27129d64c3aa833d929 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:13 +0200 Subject: [PATCH 10/41] 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 | 9 +++++++-- common/spl/Kconfig | 12 ++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c6253670a94e..0239203290d4 100644 --- a/Makefile +++ b/Makefile @@ -2012,12 +2012,17 @@ 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) +SPL_REMAKE_ELF_LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_SPL_REMAKE_ELF_LDSCRIPT:"%"=%)) + +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) 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 9e56ca4d9bf1cdcccb29edcbf28b52d606e214fb Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:14 +0200 Subject: [PATCH 11/41] 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 8ddce89210aa9e91533585a2bb21bf5fb5b071a5 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:15 +0200 Subject: [PATCH 12/41] 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 fff3a0db8a8ce6ed607e6b06470284427a0dc9ea Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:16 +0200 Subject: [PATCH 13/41] 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 f7ec5e6fd3a6..d7bb11b03498 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -121,4 +121,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 5c1993a622178f5782f6f8f3f7f5ced8e9a56822 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:17 +0200 Subject: [PATCH 14/41] 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 2186dea7b259cd2112f593318bddf233638edae3 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:18 +0200 Subject: [PATCH 15/41] 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 d7bb11b03498..337cc5b2d1ab 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 4eb52db03f915af6461490007ae35488d7eb5407 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:19 +0200 Subject: [PATCH 16/41] 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 337cc5b2d1ab..4b0b6336f751 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 @@ -23,6 +26,13 @@ config SYS_MALLOC_LEN config LNX_KRNL_IMG_TEXT_OFFSET_BASE default 0x80000000 +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 46538d8fc6cfb8ce5db69663e799f82c3c327be6 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:20 +0200 Subject: [PATCH 17/41] 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 4b0b6336f751..c0d92e5ca1d9 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -143,6 +143,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 9eb4d23b5b288dbb8116f5267697fb2fce2cee86 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:21 +0200 Subject: [PATCH 18/41] 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 fcfa367902ae..973add34050a 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 @@ -168,44 +163,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 0f577d485f1ed18c7f653a9c24bac1d9866bf1d4 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:22 +0200 Subject: [PATCH 19/41] 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 | 217 +------------------------ 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(+), 211 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 973add34050a..92c23b77b334 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,10 +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) -static struct mm_region rbx_mem_map[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; @@ -99,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 @@ -158,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; } @@ -175,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 @@ -484,200 +480,3 @@ int board_late_init(void) return 0; } - -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(); -} 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 bf7596b872ed187ad357a221087b3c6e1f52c139 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:23 +0200 Subject: [PATCH 20/41] 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 73eaadc42a7ca6a1c434d61eee40e302175ab5b1 Mon Sep 17 00:00:00 2001 From: Michael Srba Date: Thu, 21 May 2026 22:37:24 +0200 Subject: [PATCH 21/41] 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 fdab22c1a25c027770074c3abef01d6839cd9d01 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:30 +0530 Subject: [PATCH 22/41] 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 fa754bac3095b5deb77b09be490ad70419604c45 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:31 +0530 Subject: [PATCH 23/41] 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 c66016d839b3d0cf15e03da185d37d815992ac0f Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:32 +0530 Subject: [PATCH 24/41] 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..41d8789a0025 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) @@ -20,11 +21,3 @@ __weak void reset_cpu(void) 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 ecd5d66d7a8be947d59db4bb06790ea50e37e9e2 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:33 +0530 Subject: [PATCH 25/41] 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 | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 41d8789a0025..460d07ef0a36 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -21,3 +21,45 @@ __weak void reset_cpu(void) printf("reset_cpu called, going to hang()\n"); hang(); } + +#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 c73bed6605816da2dc5f598746b3c526c644dc65 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:34 +0530 Subject: [PATCH 26/41] 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 f66e2ca7f768fc438bb71e5531960d59ac3631eb Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:35 +0530 Subject: [PATCH 27/41] 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 | 25 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index c0d92e5ca1d9..b9c0362117a5 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -128,6 +128,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..5c45f993a41c 100644 --- a/board/qualcomm/config.mk +++ b/board/qualcomm/config.mk @@ -8,7 +8,30 @@ # Create Qualcomm signed elf images CMD_MKMBN = $(srctree)/tools/qcom/mkmbn/mkmbn.py quiet_cmd_mkmbn = MBN $@ - cmd_mkmbn = $(CMD_MKMBN) $< + cmd_mkmbn = $(CMD_MKMBN) -l $(CONFIG_TEXT_BASE) $< 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) $< + +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 spl/u-boot-spl.mbn $(CONFIG_QCOM_TMEL_ELF) + +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 61c5503232a0c600bf5596207afe5b0d3d45fe63 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:36 +0530 Subject: [PATCH 28/41] 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 270d412ec69f087d52f74e2a43ce39e7be0d00f0 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:37 +0530 Subject: [PATCH 29/41] 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 063bed9d6e6abc6c258ddb6138d7a653080816ff Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:38 +0530 Subject: [PATCH 30/41] 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 43055baccb1543b1abd0ea9505d33dd77547d9bb Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:39 +0530 Subject: [PATCH 31/41] 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 c71847fc562b9d01ed73e85089f1a18e6bedc390 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:40 +0530 Subject: [PATCH 32/41] 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 8bf0c9175fbb..7f990b7ecd8f 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 142ccbcaee02..7e979863dfcc 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 ed2bea72a3cccebda364042471a1678b5af228cc Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:41 +0530 Subject: [PATCH 33/41] 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 c5e03baca9ac..ba866b5b6b2e 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 41f37b0e1756..8145ae37cb46 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..a9b435ad543a --- /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, +}; From 68be9938457ceafcd66cb2a78e76f434be415489 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:42 +0530 Subject: [PATCH 34/41] 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 6fc8d5cd038294f49a9f50210bfb731bacc80464 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:43 +0530 Subject: [PATCH 35/41] 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 ba064ef06c6cca61ae3cfeac420411811a1b73c7 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 17 Sep 2026 13:15:44 +0530 Subject: [PATCH 36/41] 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 f86c669b8122d7d76edcf520d2b45b810c5cdec4 Mon Sep 17 00:00:00 2001 From: "abhilash.v" Date: Thu, 3 Sep 2026 04:24:11 -0700 Subject: [PATCH 37/41] 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 | 4 +++- drivers/mmc/msm_sdhci.c | 4 ++++ drivers/pinctrl/qcom/Kconfig | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/configs/qcom_ipq5210_mmc_defconfig b/configs/qcom_ipq5210_mmc_defconfig index 56a22ce346a8..b4f2ba497285 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 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 ba866b5b6b2e..fbf91b752161 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 fe2147c0ac48528e3559fd81ea7b5ff25397cb32 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 10 Sep 2026 15:59:39 +0530 Subject: [PATCH 38/41] tools: qcom: mkmbn: Fix ipq5424 MBN version Since ipq5424 uses MBN version 7, update the ipq5424 entry in the 'boards' table accordingly. Signed-off-by: Varadarajan Narayanan --- tools/qcom/mkmbn/mkmbn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qcom/mkmbn/mkmbn.py b/tools/qcom/mkmbn/mkmbn.py index e4484b539b02..8d2078acc306 100755 --- a/tools/qcom/mkmbn/mkmbn.py +++ b/tools/qcom/mkmbn/mkmbn.py @@ -85,7 +85,7 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): 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,ipq5424\0": MbnData(0x8a380000, 7, SwId.aboot), b"qcom,ipq9574\0": MbnData(0x4A240000, 6, SwId.aboot), # msm8916/apq8016 has an "aboot" partition but the process is the same From a0f902e027f67434a6a791148b67601f1fb62e2a Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 10 Sep 2026 15:59:41 +0530 Subject: [PATCH 39/41] tools: qcom: mkmbn: Add support for ipq5210 - Add ipq5210 entry to the 'boards' table - Add an argument to specify the SPL load address - ipq5210's boot rom expects the SPL image size to be 4-byte aligned. To support this add an argument to specify the image size alignment to enable the mkmbn script to pad the image accordingly. Signed-off-by: Varadarajan Narayanan --- tools/qcom/mkmbn/mkmbn.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/tools/qcom/mkmbn/mkmbn.py b/tools/qcom/mkmbn/mkmbn.py index 8d2078acc306..6fe66fc4e554 100755 --- a/tools/qcom/mkmbn/mkmbn.py +++ b/tools/qcom/mkmbn/mkmbn.py @@ -18,6 +18,8 @@ from enum import Enum import struct +MBN_ALIGN_SIZE = 4096 + verbose = False def log(*args, **kwargs): @@ -63,19 +65,17 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): """ -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. +This dictionary is used to map a board or platform to the appropriate MBN +metadata. When adding support for a new platform to U-Boot, the appropriate data +should be filled out here. 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 + b"qcom,qcs6490-rb3gen2\0": MbnData(6, SwId.uefi), + b"qcom,qcs9100-ride-r3\0": MbnData(6, SwId.uefi), # Dragonwing IQ9 + b"qcom,qcs8300-ride\0": MbnData(6, SwId.uefi), # Dragonwing IQ8 + b"qcom,qcs615-ride\0": MbnData(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 @@ -85,6 +85,7 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): 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,ipq5210\0": MbnData(0x87980000, 7, SwId.aboot), b"qcom,ipq5424\0": MbnData(0x8a380000, 7, SwId.aboot), b"qcom,ipq9574\0": MbnData(0x4A240000, 6, SwId.aboot), @@ -100,6 +101,9 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): """ ) parser.register("type", "hex", lambda s: int(s, 16)) +parser.add_argument( + "-l", "--load", type=lambda x: int(x, 0), default=0, help="Load address" +) parser.add_argument( "-o", "--output", type=Path, default="u-boot.mbn", help="Output file" ) @@ -149,8 +153,18 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): args.output.unlink(missing_ok=True) exit(1) +if args.load == 0: + error( + "Cannot proceed without load address.\n" + "Ensure CONFIG_TEXT_BASE/CONFIG_SPL_TEXT_BASE is set\n") + exit(1) +else: + mbn.loadaddr = args.load + log(f"Detected board {match.decode('UTF-8')} with load address {mbn.loadaddr:#x}") +data += b'\x00' * (-len(data) % MBN_ALIGN_SIZE) + elf.phdrs.append(Phdr.from_bin(data, mbn.loadaddr)) elf.ehdr.e_entry = mbn.loadaddr elf.update() From 38ebfd1b0b3f47a37963bda0c0e4a0093d133314 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 10 Sep 2026 15:59:42 +0530 Subject: [PATCH 40/41] tools: qcom: mkmbn: Add support to create multi-elf Add a command line argument to take a list of files to be combined to create a multi-elf expected by the boot rom. Signed-off-by: Varadarajan Narayanan --- tools/qcom/mkmbn/mkmbn.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/qcom/mkmbn/mkmbn.py b/tools/qcom/mkmbn/mkmbn.py index 6fe66fc4e554..6b0ea3a42394 100755 --- a/tools/qcom/mkmbn/mkmbn.py +++ b/tools/qcom/mkmbn/mkmbn.py @@ -104,6 +104,9 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): parser.add_argument( "-l", "--load", type=lambda x: int(x, 0), default=0, help="Load address" ) +parser.add_argument( + "-m", "--melfs", nargs='+', default=[], help="List of ELFs to include in multi-elf" +) parser.add_argument( "-o", "--output", type=Path, default="u-boot.mbn", help="Output file" ) @@ -116,6 +119,18 @@ def __init__(self, loadaddr: int, version: int, sw_id: SwId = SwId.aboot): args = parser.parse_args() verbose = args.verbose +if (len(args.melfs)): + try: + with open(args.output, "wb") as f: + for path in args.melfs: + with open(path, 'rb') as tmp: + f.write(tmp.read()) + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + sys.exit(0) + elf = Elf() data: bytes = args.bin.read() From 79270ea454a64a1fee1cfe42c3d8c08a242e32dc Mon Sep 17 00:00:00 2001 From: "abhilash.v" Date: Thu, 17 Sep 2026 04:12:28 -0700 Subject: [PATCH 41/41] board: qualcomm: fix IPQ5210 MELF generation Strip quotes from the configured TMEL ELF path before checking for the file and passing it to mkmbn. Use mkmbn multi-ELF mode to combine the SPL MBN and TMEL ELF into the boot ROM expected MELF image. Signed-off-by: abhilash.v --- board/qualcomm/config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/board/qualcomm/config.mk b/board/qualcomm/config.mk index 5c45f993a41c..d6253ebb545a 100644 --- a/board/qualcomm/config.mk +++ b/board/qualcomm/config.mk @@ -23,10 +23,10 @@ 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)),) +ifneq ($(wildcard $(CONFIG_QCOM_TMEL_ELF:"%"=%)),) quiet_cmd_mksplmelf = SPLMELF $@ - cmd_mksplmelf = $(CMD_MKMBN) -o spl/u-boot-spl.melf spl/u-boot-spl.mbn $(CONFIG_QCOM_TMEL_ELF) + cmd_mksplmelf = $(CMD_MKMBN) -m spl/u-boot-spl.mbn $(CONFIG_QCOM_TMEL_ELF:"%"=%) -o spl/u-boot-spl.melf $< INPUTS-$(CONFIG_SPL) += spl/u-boot-spl.melf