From fc87b2c81a6a9c9b7be66261426391bb616f4b1e Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:12 +0530 Subject: [PATCH 01/14] mach-snapdragon: Kconfig: Auto select options based on configs The commit 0debfe4801bb ("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: 0debfe4801bb ("mach-snapdragon: Kconfig: changes / additions to support SPL") Signed-off-by: Varadarajan Narayanan --- arch/arm/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8304c2ebb7f9..08822beffece 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1153,6 +1153,10 @@ config ARCH_SNAPDRAGON select ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR select MMU_PGPROT select SUPPORT_SPL + select SPL_DM_PMIC if SPL && DM_PMIC + select SPL_DM_USB_GADGET if SPL && USB + select SPL_HAS_BSS_LINKER_SECTION if SPL && SPL_SEPARATE_BSS + select SPL_USB_GADGET if SPL && USB imply OF_UPSTREAM imply CMD_DM imply DM_USB_GADGET From 4a5d127f43ef17177d565f85f035b371e9c2e2b0 Mon Sep 17 00:00:00 2001 From: Abhilash V Date: Sun, 16 Aug 2026 05:27:22 -0700 Subject: [PATCH 02/14] Revert "mach-snapdragon: Add PBL shared data defines" This reverts commit 3635906b1e278c94d8fcd3eae2e6bb5bf91d5fcb. Signed-off-by: Abhilash V --- arch/arm/mach-snapdragon/qcom-priv.h | 51 ---------------------------- 1 file changed, 51 deletions(-) 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__ */ From ea96c86bdac4a0fcd6dd8711f10efef608bfa51b Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:13 +0530 Subject: [PATCH 03/14] 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. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/include/mach/pbl.h | 57 +++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 arch/arm/mach-snapdragon/include/mach/pbl.h diff --git a/arch/arm/mach-snapdragon/include/mach/pbl.h b/arch/arm/mach-snapdragon/include/mach/pbl.h new file mode 100644 index 000000000000..2e6ad13255c4 --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/pbl.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __PBL_H__ +#define __PBL_H__ + +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, +}; + +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 /* __PBL_H__ */ From cbb5beb4b21b25ccc485826e4f5c568bcf0acd63 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:14 +0530 Subject: [PATCH 04/14] mach-snapdragon: spl: Add support for boot device detection Save the boot parameters passed from the boot rom and use that to identify the boot device. Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/board_spl.c | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 arch/arm/mach-snapdragon/board_spl.c diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c new file mode 100644 index 000000000000..ce80e1545c00 --- /dev/null +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024 Linaro Ltd + * Copyright (c) 2026 Michael Srba + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* in SPL, we always use internal DT */ +int board_fdt_blob_setup(void **fdtp) +{ + *fdtp = (void *)gd->fdt_blob; + return 0; +} + +/* in SPL, we don't have a real reset function */ +__weak void reset_cpu(void) +{ + hang(); +} + +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(); +} + +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; +} From 1333e61219816af46ea87bbe803436cfd207eb3e Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:15 +0530 Subject: [PATCH 05/14] 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 | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index ce80e1545c00..10cae7785bb1 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -84,3 +84,49 @@ u32 spl_boot_device(void) pr_err("No boot device configured\n"); return BOOT_DEVICE_NONE; } + +#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) */ From 04757526123cb288de31682bb865f7b122cbbaf2 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:16 +0530 Subject: [PATCH 06/14] 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 | 107 +++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 10cae7785bb1..d1e4b9683c64 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -130,3 +130,110 @@ 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_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; + + ret = spl_find_partition_info(UCLASS_MMC, 0, QCOM_SPL_FIT_IMG_PARTITION, &info); +#if IS_ENABLED(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION) + 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; + } +#endif + 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) */ From c9b55936ddafd94a9e376ff37c7d35784ae1062a Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:17 +0530 Subject: [PATCH 07/14] mach-snapdragon: spl: Setup malloc Setup the malloc base and limit for the SPL to be able to use the memory allocation APIs. Reviewed-by: Balaji Selvanathan Reviewed-by: Simon Glass Signed-off-by: Varadarajan Narayanan --- arch/arm/mach-snapdragon/board_spl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index d1e4b9683c64..7abf8c09e41f 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -237,3 +237,18 @@ 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; +} From 95f76b4d771fa05b8706d670234a034fe4a4fa98 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:19 +0530 Subject: [PATCH 08/14] 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 | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c index 7abf8c09e41f..5b8303cc3e7d 100644 --- a/arch/arm/mach-snapdragon/board_spl.c +++ b/arch/arm/mach-snapdragon/board_spl.c @@ -252,3 +252,62 @@ void qcom_spl_malloc_init_f(void) 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; +} From 35fcfc59788931d31837eeedc5305a9805e9bb80 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:20 +0530 Subject: [PATCH 09/14] 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 | 326 +++++++++++++++++++++++++ 2 files changed, 327 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 c80f63e33f65..9fbbdc29166a 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_QCOM_HWDETECT) += qcom_hwdetect.o obj-$(CONFIG_OF_LIVE) += of_fixup.o endif obj-$(CONFIG_SPL_BUILD) += spl.o +obj-$(CONFIG_SPL_BUILD) += fit-handler.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..cd571dd628c8 --- /dev/null +++ b/arch/arm/mach-snapdragon/fit-handler.c @@ -0,0 +1,326 @@ +// 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 "qcom-priv.h" +#include + +#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 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"); + +/** + * 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; +} + + +/** + * 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 = spl_get_load_buffer(0, 0); + + 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 "qcconfig_1" image 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; + } + + /* + * Find "qcom-lib-1" image node + */ + 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; + } + + /* + * 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 qcconfig_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 qclib_1 entry point (%d)\n", ret); + return ret; + } + + qclib_entry = (qcom_spl_jump_img_entry_t)entry_point; + + pr_info("Jumping to qclib_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; +} + + +/** + * 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; +} From 02a448f9150bc6c078c8baeaf6cec736ec7e50b6 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:26 +0530 Subject: [PATCH 10/14] doc: board/qualcomm: Update RDP documentation index.rst: - Include 'spl-qclib.rst' rdp.rst: - Add details about the SPL & U-Boot proper build steps, converting to flashable images, source URLs for the needed binaries and scripts. - Update author e-mail id. spl-qclib.rst: - Describe the SPL - Qualcomm Library (QCLib) interface used to exchange information between U-Boot SPL and QCLib for initializing the DDR. Reviewed-by: Simon Glass Reviewed-by: Balaji Selvanathan Signed-off-by: Varadarajan Narayanan --- doc/board/qualcomm/index.rst | 1 + doc/board/qualcomm/rdp.rst | 103 ++++++++++++------------------- doc/board/qualcomm/spl-qclib.rst | 76 +++++++++++++++++++++++ 3 files changed, 115 insertions(+), 65 deletions(-) create mode 100644 doc/board/qualcomm/spl-qclib.rst diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst index ee2bc9e29e32..28769b405935 100644 --- a/doc/board/qualcomm/index.rst +++ b/doc/board/qualcomm/index.rst @@ -15,3 +15,4 @@ Qualcomm phones rdp snagboot + spl-qclib diff --git a/doc/board/qualcomm/rdp.rst b/doc/board/qualcomm/rdp.rst index 354dc9d06e11..74200a56edc2 100644 --- a/doc/board/qualcomm/rdp.rst +++ b/doc/board/qualcomm/rdp.rst @@ -1,5 +1,5 @@ .. SPDX-License-Identifier: GPL-2.0 -.. sectionauthor:: Varadarajan Narayanan +.. sectionauthor:: Varadarajan Narayanan Qualcomm Reference Design Platform (RDP) ======================================== @@ -19,18 +19,8 @@ First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``IPQ9574``:: $ make qcom_ipq9574_mmc_defconfig $ make -j8 -This will build ``u-boot.elf`` in the configured output directory. - -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) - - $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v6 - - IPQ5424: (MBN version 7) - - $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v7 +This will build the signed ``u-boot.mbn`` in the configured output directory. More information +about image signing can be found in :doc:`signing`. Then install the resulting ``u-boot.mbn`` to the ``0:APPSBL`` partition on your device with:: @@ -51,70 +41,53 @@ Please refer to the following URLs for more details about the platforms. 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, +Since U-Boot SPL is enabled on these platforms, the build command generates both +the U-Boot SPL and U-Boot proper images. + +Download `tmel-ipq52xx-patch.elf` and update CONFIG_QCOM_TMEL_ELF in the config +file (i.e. configs/qcom_ipq5210_mmc_defconfig) as appropriate. - $ cd ${uboot_dir} - $ export CROSS_COMPILE= - $ make -j8 O=${out_dir} qcom_ipq5210_mmc_defconfig - $ make -j8 O=${out_dir} +Assuming ${uboot_dir} is the top of the U-Boot sources and ${out_dir} as the +output directory, - U-Boot SPL image: ${out_dir}/spl/u-boot-spl.wrap-elf - U-Boot image: ${out_dir}/u-boot.elf +.. code-block:: bash -2. Convert the SPL image to multi ELF + cd ${uboot_dir} + export CROSS_COMPILE= + make -j8 O=${out_dir} qcom_ipq5210_mmc_defconfig + make -j8 O=${out_dir} - $ 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 +U-Boot SPL image: ${out_dir}/spl/u-boot-spl.melf +U-Boot image: ${out_dir}/u-boot.mbn - This u-boot-spl.melf should be flashed into 0:SPL partition. - Please see below for the location of `tmel-ipq52xx-patch.elf` +TFA: -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 + make PLAT=ipq52xx QTISECLIB_PATH=path/to/`libqtisec_dbg.a` SPD=opteed - 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 +OPTEE: - TFA: - $ make PLAT=ipq52xx QTISECLIB_PATH=path/to/`libqtisec_dbg.a` SPD=opteed +.. code-block:: bash - OPTEE: - $ make PLATFORM=qcom-ipq52xx -j16 + make PLATFORM=qcom-ipq52xx -j16 - These binaries can be combined into a flashable image using binman. +These binaries can be combined into a flashable image using `gen_its.py`. - Assuming all the required binaries are available in ${uboot_dir}/binman +.. code-block:: bash - $ 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" + 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. +This should be flashed into 0:BOOTLDR partition. .. WARNING Boards with newer software versions would automatically go the emergency @@ -128,12 +101,12 @@ Please refer to the following URLs for more details about the platforms. 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 diff --git a/doc/board/qualcomm/spl-qclib.rst b/doc/board/qualcomm/spl-qclib.rst new file mode 100644 index 000000000000..b430f10dc68b --- /dev/null +++ b/doc/board/qualcomm/spl-qclib.rst @@ -0,0 +1,76 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. sectionauthor:: Varadarajan Narayanan + +QCLib Interface Table +===================== + +Overview +-------- + +QCLib (Qualcomm Library) is a Qualcomm proprietary firmware binary that +performs DDR initialization and other pre-DDR hardware bring-up on Snapdragon +SoCs. U-Boot SPL communicates with QCLib through a shared in-memory structure +called the **interface table** (``struct interface_table``). The table is +populated by SPL before jumping to QCLib, and QCLib updates selected entries +before returning. + +Interface Table Header +---------------------- + +The table header occupies the first 0x20 bytes of the structure: + +.. code-block:: none + + Offset Size Field Description + ------ ---- ------------------ ---------------------------------------- + 0x00 8 magic_key ASCII magic: "QCLIB_CB" (no NUL) + 0x08 4 version Interface version; currently 0x00000001 + 0x0C 4 num_entries Number of valid entries in the table + 0x10 4 max_entries Maximum entries the table can hold (16) + 0x14 4 global_attributes Bitmask of global control flags + 0x18 4 reserved1 Reserved; must be zero + 0x1C 4 reserved2 Reserved; must be zero + 0x20 - entries[] Array of up to 16 table entries + +The magic key ``"QCLIB_CB"`` is validated by QCLib on entry. If the magic does +not match, QCLib will not proceed. + +Table Entry Format +------------------ + +Each entry is 0x28 bytes: + +.. code-block:: none + + Offset Size Field Description + ------ ---- ------------------ ---------------------------------------- + 0x00 24 entry_name NUL-padded ASCII name (see entries below) + 0x18 8 address Physical address of the blob in SRAM + 0x20 4 size Size of the blob in bytes + 0x24 4 attributes Bitmask of per-entry flags + +The ``global_attributes`` and per-entry ``attributes`` fields are bitmasks +defined by the QCLib interface specification. SPL initializes both to zero +unless a SoC-specific override sets them. + +Interface Table Entries +----------------------- + +.. list-table:: + :header-rows: 1 + :widths: 22 12 66 + + * - Entry name + - Direction + - Description + * - ``qc_config`` + - Input + - Entry point / load address of the pre-DDR configuration image + (``qcom-config-1`` in the FIT). Contains platform configuration + data consumed by QCLib. + * - ``qcsdi`` + - Bidirectional + - QCSDI (Qualcomm Crash Dump Interface) entry. SPL initializes the + address to zero; QCLib writes the QCSDI physical address here before + returning. SPL reads it back and passes it to downstream firmware + (e.g. TF-A BL31 via ``arg0``) for crash-dump support. From 8d1b06933d3d202611bdbb045d2a9ba00f0f96fe Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:25 +0530 Subject: [PATCH 11/14] 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 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/configs/qcom_ipq5210_mmc_defconfig b/configs/qcom_ipq5210_mmc_defconfig index e903daa581cc..56a22ce346a8 100644 --- a/configs/qcom_ipq5210_mmc_defconfig +++ b/configs/qcom_ipq5210_mmc_defconfig @@ -3,6 +3,7 @@ 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 @@ -83,7 +84,7 @@ 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_TEXT_BASE=0x08c2e000 CONFIG_SPL_MAX_SIZE=0x3D000 CONFIG_SPL_MMC=y CONFIG_SPL_MMC_SDHCI_ADMA=y @@ -101,6 +102,12 @@ 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_SPL_STACK=0x08c2e000 # CONFIG_SAVE_PREV_BL_FDT_ADDR is not set -CONFIG_SPL_WRAPPER_ELF=y +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 271a5188bd9e3291800b1c79fdca25cec0684f68 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 22 Jul 2026 13:11:24 +0530 Subject: [PATCH 12/14] 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/Makefile | 11 +- arch/arm/mach-snapdragon/include/mach/spl.h | 14 + arch/arm/mach-snapdragon/spl.c | 770 ------------------ board/qualcomm/ipq5210/Makefile | 3 + .../qualcomm/ipq5210/ipq5210-spl-wrap-elf.lds | 18 + board/qualcomm/ipq5210/spl-ipq5210.c | 96 +++ include/configs/ipq5210.h | 11 + 7 files changed, 149 insertions(+), 774 deletions(-) create mode 100644 arch/arm/mach-snapdragon/include/mach/spl.h delete mode 100644 arch/arm/mach-snapdragon/spl.c 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/Makefile b/arch/arm/mach-snapdragon/Makefile index 9fbbdc29166a..fcb3f444e08c 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -2,12 +2,15 @@ # # (C) Copyright 2015 Mateusz Kulikowski -ifndef CONFIG_XPL_BUILD -obj-y += board.o dram.o +obj-y += dram.o + +ifeq ($(CONFIG_SPL_BUILD),y) +obj-y += board_spl.o +obj-y += fit-handler.o +else +obj-y += board.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 -obj-$(CONFIG_SPL_BUILD) += fit-handler.o 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..9e09bad82bcd --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/spl.h @@ -0,0 +1,14 @@ +/* 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); +int qclib_post_process_from_spl(void); +void qcom_spl_error_handler(void *arg); + +#endif /* __SPL_H__ */ diff --git a/arch/arm/mach-snapdragon/spl.c b/arch/arm/mach-snapdragon/spl.c deleted file mode 100644 index bfe4dc8dd011..000000000000 --- a/arch/arm/mach-snapdragon/spl.c +++ /dev/null @@ -1,770 +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 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"). - * @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; - - 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; - - if (psd && psd->num_of_entries >= PBL_SHARED_DATA_PARAM_MAX) - memcpy(&g_psd, psd, sizeof(g_psd)); - } - - 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; - - /* - * 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); - } -#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; - } - } - } - - /* - * 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"); - 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(); - - 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 = 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/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..e0c52c0a6f62 --- /dev/null +++ b/board/qualcomm/ipq5210/spl-ipq5210.c @@ -0,0 +1,96 @@ +// 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 + +DECLARE_GLOBAL_DATA_PTR; + +#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; + } + + 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 = 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) + reset_cpu(); +} +#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; +} 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 3e2db800497f5435424b104a75b60f03cfddff88 Mon Sep 17 00:00:00 2001 From: Abhilash V Date: Sun, 16 Aug 2026 06:53:46 -0700 Subject: [PATCH 13/14] 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 Signed-off-by: Abhilash V --- arch/arm/mach-snapdragon/Kconfig | 14 ++++++++++++ board/qualcomm/config.mk | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 board/qualcomm/config.mk diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 29567b66ff9a..46a677de4b49 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -73,6 +73,20 @@ config QCOM_HWDETECT Hardware parameter detection from SMEM and TCSR for DTB selection and other platform subsystems. +config QCOM_TMEL_ELF + string "TME Elf to concatenate with U-Boot SPL MBN image" + depends on SPL + help + Path of the TME Elf file to be concatenated to u-boot.mbn to create + boot rom expected multi-elf image + +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. + choice prompt "Qualcomm boot0.h workaround" optional diff --git a/board/qualcomm/config.mk b/board/qualcomm/config.mk new file mode 100644 index 000000000000..2abecbf8ea50 --- /dev/null +++ b/board/qualcomm/config.mk @@ -0,0 +1,37 @@ +# 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) + +ifeq ($(CONFIG_QCOM_GENERATE_MBN),y) + +quiet_cmd_mksplmbn = SPLMBN $@ + cmd_mksplmbn = $(CMD_MKMBN) -o spl/u-boot-spl.mbn -l $(CONFIG_SPL_TEXT_BASE) -s 4 $< + +INPUTS-$(CONFIG_SPL) += spl/u-boot-spl.mbn + +spl/u-boot-spl.mbn: spl/u-boot-spl.bin FORCE + $(call if_changed,mksplmbn) + +ifneq ($(wildcard $(CONFIG_QCOM_TMEL_ELF)),) + +quiet_cmd_mksplmelf = SPLMELF $@ + cmd_mksplmelf = $(CMD_MKMBN) -o spl/u-boot-spl.melf -m spl/u-boot-spl.mbn,$(CONFIG_QCOM_TMEL_ELF) -s 4 $< + +INPUTS-$(CONFIG_SPL) += spl/u-boot-spl.melf + +spl/u-boot-spl.melf: spl/u-boot-spl.mbn FORCE + $(call if_changed,mksplmelf) +endif # CONFIG_QCOM_TMEL_ELF + +endif # CONFIG_QCOM_GENERATE_MBN From dc030da8dfbdb666a609d90c13e969d2fe01ca40 Mon Sep 17 00:00:00 2001 From: Abhilash V Date: Wed, 19 Aug 2026 07:20:51 -0700 Subject: [PATCH 14/14] mach-snapdragon: fix multiple-definition link error in qcom-priv.h qcom_configure_capsule_updates() had a non-static inline body in a header when CONFIG_EFI_HAVE_CAPSULE_SUPPORT is not set. Any TU including qcom-priv.h got a duplicate symbol at link time. Mark the stub 'static inline' to scope it per-TU. Signed-off-by: Abhilash V --- arch/arm/mach-snapdragon/qcom-priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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);