From e31defd29d0325754675b4423d623286f68fc49b Mon Sep 17 00:00:00 2001 From: "abhilash.v" Date: Thu, 3 Sep 2026 07:00:10 -0700 Subject: [PATCH 1/3] board: qualcomm: shikra: add initial SPL boot support Add the Shikra SPL board implementation, linker script, and defconfig. Provide QCLIB interface-table hooks, select the core_nhlos_a FIT partition, and add the SPL pinctrl option needed for early eMMC and console bring-up. Signed-off-by: abhilash.v --- board/qualcomm/shikra/Makefile | 3 + board/qualcomm/shikra/shikra-spl-wrap-elf.lds | 18 ++ board/qualcomm/shikra/spl-shikra.c | 228 ++++++++++++++++++ configs/qcom_shikra_spl_defconfig | 108 +++++++++ drivers/pinctrl/qcom/Kconfig | 9 +- include/configs/shikra.h | 11 + 6 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 board/qualcomm/shikra/Makefile create mode 100644 board/qualcomm/shikra/shikra-spl-wrap-elf.lds create mode 100644 board/qualcomm/shikra/spl-shikra.c create mode 100644 configs/qcom_shikra_spl_defconfig create mode 100644 include/configs/shikra.h diff --git a/board/qualcomm/shikra/Makefile b/board/qualcomm/shikra/Makefile new file mode 100644 index 000000000000..5a08df227db4 --- /dev/null +++ b/board/qualcomm/shikra/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SPL) := spl-shikra.o diff --git a/board/qualcomm/shikra/shikra-spl-wrap-elf.lds b/board/qualcomm/shikra/shikra-spl-wrap-elf.lds new file mode 100644 index 000000000000..f0ced6765da0 --- /dev/null +++ b/board/qualcomm/shikra/shikra-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/shikra/spl-shikra.c b/board/qualcomm/shikra/spl-shikra.c new file mode 100644 index 000000000000..5caf8b1e17fb --- /dev/null +++ b/board/qualcomm/shikra/spl-shikra.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPQ_SPL_BOOTCFG_REG_ADDR 0x1B46070 +#define IPQ_SPL_BOOTCFG_DEV_MASK GENMASK(5, 1) +#define IPQ_SPL_BOOTCFG_DEV_SHFT 0x1 + +#define SHIKRA_DDR_INFORMATION "ddr_information" +#define SHIKRA_DDR_TRAINING_DATA "ddr_training_data" +#define SHIKRA_DDR_SR_EXIT "ddr_sr_exit" +#define SHIKRA_PMIC_COCOS "pmic_cocos" +#define SHIKRA_PMIC_WAILUA "pmic_wailua" +#define SHIKRA_DCB_LP4 "dcb_lp4" +#define SHIKRA_DCB_LP5 "dcb_lp5" +#define SHIKRA_ECC "ecc" + +#define SHIKRA_DDR_TRAINING_DATA_ADDR 0x0c368000 +#define SHIKRA_DDR_TRAINING_DATA_SIZE 0x8000 +#define SHIKRA_PMIC_COCOS_SIZE 0xbc00 +#define SHIKRA_PMIC_WAILUA_SIZE 0x6000 +#define SHIKRA_DCB_LP4_SIZE 0x4800 +#define SHIKRA_DCB_LP5_SIZE 0x4800 +#define SHIKRA_ECC_SIZE 0x400 + +#define SHIKRA_SHRM2_SPROC_CTRL_ADDR 0x0c36000 +#define SHIKRA_SHRM2_SPROC_CTRL_CORE_SW_RESET_BMSK BIT(1) +#define SHIKRA_SHRM2_SPROC_CTRL_DEBUG_SW_RESET_BMSK BIT(3) + +/* GCC_APCS_MISC holds RPM in reset until QCLIB has initialized DDR. */ +#define SHIKRA_GCC_APCS_MISC_ADDR 0x01491000 +#define SHIKRA_GCC_APCS_MISC_RPM_RESET_BMSK BIT(0) + +#define QCOM_SPL_FIT_IMG_PARTITION "core_nhlos_a" + +static u64 g_ddr_sr_exit_address __section(".data"); + +enum { + IPQ_SPL_BOOTCFG_DEV_MMC = 0x0, + IPQ_SPL_BOOTCFG_DEV_SD_EMMC = 0x1, + IPQ_SPL_BOOTCFG_DEV_EDL = 0x2, + IPQ_SPL_BOOTCFG_DEV_NAND = 0x3, + IPQ_SPL_BOOTCFG_DEV_EMMC_SD = 0x4, + IPQ_SPL_BOOTCFG_DEV_MAX +}; + +u64 shikra_get_ddr_sr_exit_address(void) +{ + return g_ddr_sr_exit_address; +} + +void shikra_set_ddr_sr_exit_address(u64 address) +{ + g_ddr_sr_exit_address = address; +} + +static int shikra_add_iftbl_entry(struct interface_table *table, + const char *name, u64 address, u32 size) +{ + uint entry_idx = table->num_entries; + + if (entry_idx >= table->max_entries) + return -ENOSPC; + + memset(&table->if_table_entries[entry_idx], 0, + sizeof(table->if_table_entries[entry_idx])); + memcpy(table->if_table_entries[entry_idx].entry_name, name, strlen(name)); + table->if_table_entries[entry_idx].address = address; + table->if_table_entries[entry_idx].size = size; + table->num_entries = entry_idx + 1; + + return 0; +} + +static int shikra_add_iftbl_fit_blob(struct interface_table *table, + const void *fit, int images_node, + const char *name, u32 size) +{ + int node, ret; + u64 address; + + node = fdt_subnode_offset(fit, images_node, name); + if (node < 0) + return -ENOENT; + + ret = qcom_spl_get_fit_img_entry_point((void *)fit, node, &address); + if (ret) + return ret; + + return shikra_add_iftbl_entry(table, name, address, size); +} + +int qcom_spl_soc_qclib_override(struct interface_table *table, + const void *fit, int images_node) +{ + static const struct { + const char *name; + u32 size; + } fit_blobs[] = { + { SHIKRA_PMIC_COCOS, SHIKRA_PMIC_COCOS_SIZE }, + { SHIKRA_PMIC_WAILUA, SHIKRA_PMIC_WAILUA_SIZE }, + { SHIKRA_DCB_LP4, SHIKRA_DCB_LP4_SIZE }, + { SHIKRA_DCB_LP5, SHIKRA_DCB_LP5_SIZE }, + { SHIKRA_ECC, SHIKRA_ECC_SIZE }, + }; + uint i; + int ret; + + table->global_attributes |= QCLIB_GA_ENABLE_UART_LOGGING; + for (i = 0; i < ARRAY_SIZE(fit_blobs); i++) { + ret = shikra_add_iftbl_fit_blob(table, fit, images_node, + fit_blobs[i].name, fit_blobs[i].size); + if (ret) + return ret; + } + + ret = shikra_add_iftbl_entry(table, SHIKRA_DDR_TRAINING_DATA, + SHIKRA_DDR_TRAINING_DATA_ADDR, + SHIKRA_DDR_TRAINING_DATA_SIZE); + if (ret) + return ret; + ret = shikra_add_iftbl_entry(table, SHIKRA_DDR_INFORMATION, 0, 0); + if (ret) + return ret; + + return shikra_add_iftbl_entry(table, SHIKRA_DDR_SR_EXIT, 0, 0); +} + +int qcom_spl_soc_pre_qclib_routine(void) +{ + writel(SHIKRA_SHRM2_SPROC_CTRL_DEBUG_SW_RESET_BMSK | + SHIKRA_SHRM2_SPROC_CTRL_CORE_SW_RESET_BMSK, + (void *)SHIKRA_SHRM2_SPROC_CTRL_ADDR); + writel(SHIKRA_SHRM2_SPROC_CTRL_CORE_SW_RESET_BMSK, + (void *)SHIKRA_SHRM2_SPROC_CTRL_ADDR); + writel(0, (void *)SHIKRA_SHRM2_SPROC_CTRL_ADDR); + + return 0; +} + +int qcom_spl_soc_post_qclib_routine(struct interface_table *table) +{ + struct interface_table_entry entry; + int ret; + + /* + * QCLIB has completed DDR initialization and loaded the RPM image. + * Release RPM before handing control to the post-DDR SPL stage. + */ + clrbits_le32((void *)SHIKRA_GCC_APCS_MISC_ADDR, + SHIKRA_GCC_APCS_MISC_RPM_RESET_BMSK); + + ret = qcom_spl_get_iftbl_entry_by_name(table, SHIKRA_DDR_SR_EXIT, + &entry); + if (ret) + return ret; + + shikra_set_ddr_sr_exit_address(entry.address); + return 0; +} + +#if CONFIG_IS_ENABLED(MMC) +int spl_mmc_boot_partition(const u32 boot_device) +{ + struct blk_desc *desc; + struct disk_partition info; + int partition; + + desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + if (!desc) + return -ENODEV; + + partition = part_get_info_by_name(desc, QCOM_SPL_FIT_IMG_PARTITION, + &info); + if (partition < 0) + return -ENOENT; + + return partition; +} +#endif + +/** + * spl_boot_device() - Get the boot device. + * + * Return: U-Boot boot device identifier, or -EINVAL if the device is invalid. + */ +u32 spl_boot_device(void) +{ + u8 boot_device_cfg = + (readl(IPQ_SPL_BOOTCFG_REG_ADDR) & IPQ_SPL_BOOTCFG_DEV_MASK) >> + IPQ_SPL_BOOTCFG_DEV_SHFT; + u32 boot_device_smem; + + switch (boot_device_cfg) { + case IPQ_SPL_BOOTCFG_DEV_MMC: + boot_device_smem = BOOT_DEVICE_MMC1; + printf("Selected boot device: MMC\n"); + break; + case IPQ_SPL_BOOTCFG_DEV_SD_EMMC: + boot_device_smem = BOOT_DEVICE_MMC2; + printf("Selected boot device: SD MMC\n"); + break; + case IPQ_SPL_BOOTCFG_DEV_EDL: + boot_device_smem = BOOT_DEVICE_USB; + printf("Selected boot device: SPI-NAND\n"); + break; + case IPQ_SPL_BOOTCFG_DEV_NAND: + boot_device_smem = BOOT_DEVICE_NAND; + printf("Selected boot device: SPI-NAND\n"); + break; + default: + pr_err("Invalid boot device configured: %d\n", + boot_device_cfg); + return -EINVAL; + } + + return boot_device_smem; +} diff --git a/configs/qcom_shikra_spl_defconfig b/configs/qcom_shikra_spl_defconfig new file mode 100644 index 000000000000..90aa4f687309 --- /dev/null +++ b/configs/qcom_shikra_spl_defconfig @@ -0,0 +1,108 @@ +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_OF_UPSTREAM is not set +CONFIG_DEFAULT_DEVICE_TREE="shikra-cqs-evk" +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_SHIKRA=y +CONFIG_MSM_GPIO=y +CONFIG_MISC=y +CONFIG_QCOM_GENI=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_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_QCOM=y +CONFIG_PINCTRL_QCOM_SHIKRA=y +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_BASE=0x4a80000 +CONFIG_DEBUG_UART_CLOCK=14745600 +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_POWER_DOMAIN=y +CONFIG_SPL_PINCTRL=y +CONFIG_SPL_PINCTRL_GENERIC=y +CONFIG_SPL_PINCTRL_QCOM=y +CONFIG_SPL_PINCTRL_QCOM_SHIKRA=y +CONFIG_SPL_CLK=y +CONFIG_SPL_CLK_STUB=y +CONFIG_SPL_DRIVERS_MISC=y +CONFIG_SPL_DRIVERS_MISC_SUPPORT=y +CONFIG_SPL_QCOM_GENI=y +CONFIG_SPL_SERIAL=y +CONFIG_SPL_MSM_GENI_SERIAL=y +CONFIG_SPL_SMEM=y +CONFIG_DM_STATS=y +CONFIG_SPL_SYS_MALLOC_F=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x48000 +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=0x0C219000 +CONFIG_SPL_MAX_SIZE=0x7B800 +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=0x0C2C1800 +# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set +CONFIG_SPL_HAVE_INIT_STACK=y +CONFIG_SPL_STACK=0x0C294800 +# CONFIG_SAVE_PREV_BL_FDT_ADDR is not set +CONFIG_SPL_REMAKE_ELF=y +CONFIG_SPL_REMAKE_ELF_LDSCRIPT="board/qualcomm/shikra/shikra-spl-wrap-elf.lds" +CONFIG_QCOM_SPL_BOOTIMEM_FLUSH_BASE=0x0C219000 +CONFIG_QCOM_SPL_BOOTIMEM_FLUSH_SIZE=0x134000 +CONFIG_SYS_BOARD="shikra" diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 5e4cf2951c93..9800a2e84796 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -259,6 +259,14 @@ config PINCTRL_QCOM_SHIKRA Say Y here to enable support for pinctrl on the Snapdragon Shikra SoC, as well as the associated GPIO driver. +config SPL_PINCTRL_QCOM_SHIKRA + bool "Qualcomm Shikra Pinctrl in SPL" + depends on SPL_PINCTRL_GENERIC + select SPL_PINCTRL_QCOM + help + SPL variant of PINCTRL_QCOM_SHIKRA. + See the help of PINCTRL_QCOM_SHIKRA for details. + config PINCTRL_QCOM_SDM670 bool "Qualcomm SDM670 Pinctrl" default y if PINCTRL_QCOM_GENERIC @@ -445,4 +453,3 @@ config SPL_PINCTRL_QCOM_X1E80100 endmenu endif - diff --git a/include/configs/shikra.h b/include/configs/shikra.h new file mode 100644 index 000000000000..fa6a1d9b4c07 --- /dev/null +++ b/include/configs/shikra.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __CONFIGS_SHIKRA_H +#define __CONFIGS_SHIKRA_H + +#include + +#endif From 02cf709edc46b550bf51c8efba8834a33000f522 Mon Sep 17 00:00:00 2001 From: "abhilash.v" Date: Sun, 6 Sep 2026 07:26:47 -0700 Subject: [PATCH 2/3] board: qualcomm: shikra: enable QUP firmware loading in SPL Load QUP firmware from the eMMC GPT partition before probing the non-minicore console. Retain the required device-tree nodes, initialize eMMC before the last-stage event, enable the QUP wrapper clocks before accessing serial-engine registers, and release the firmware buffer after all consumers have loaded it. Signed-off-by: abhilash.v --- arch/arm/dts/shikra-cqs-evk-u-boot.dtsi | 50 +++++++++++++ board/qualcomm/shikra/spl-shikra.c | 41 +++++++++++ drivers/clk/qcom/clock-qcom.c | 57 ++++++++++++++ drivers/clk/qcom/clock-qcom.h | 16 ++++ drivers/clk/qcom/clock-shikra.c | 37 ++++++++-- drivers/misc/qcom_geni.c | 98 ++++++++++++++++++++----- 6 files changed, 274 insertions(+), 25 deletions(-) diff --git a/arch/arm/dts/shikra-cqs-evk-u-boot.dtsi b/arch/arm/dts/shikra-cqs-evk-u-boot.dtsi index 056268a009d5..16742885604c 100644 --- a/arch/arm/dts/shikra-cqs-evk-u-boot.dtsi +++ b/arch/arm/dts/shikra-cqs-evk-u-boot.dtsi @@ -25,3 +25,53 @@ &{/soc@0/sram@c11e000} { compatible = "qcom,shikra-imem", "syscon", "simple-mfd"; }; + +/* Keep the console and QUPFW storage paths in the SPL device tree. */ +&gcc { + bootph-all; +}; + +&tlmm { + bootph-all; +}; + +&qup_uart0_default { + bootph-all; +}; + +&sdc1_state_on { + bootph-all; +}; + +&sdc1_state_off { + bootph-all; +}; + +&sdhc_1 { + bootph-all; +}; + +&qupv3_0 { + u-boot,qupfw-storage = <&sdhc_1>; + bootph-all; +}; + +&uart0 { + bootph-all; +}; + +&rpm { + bootph-all; + + glink-edge { + bootph-all; + + rpm-requests { + bootph-all; + + clock-controller { + bootph-all; + }; + }; + }; +}; diff --git a/board/qualcomm/shikra/spl-shikra.c b/board/qualcomm/shikra/spl-shikra.c index 5caf8b1e17fb..f8115cc30d41 100644 --- a/board/qualcomm/shikra/spl-shikra.c +++ b/board/qualcomm/shikra/spl-shikra.c @@ -4,7 +4,9 @@ */ #include #include +#include #include +#include #include #include #include @@ -54,6 +56,45 @@ enum { IPQ_SPL_BOOTCFG_DEV_MAX }; +#if defined(CONFIG_SPL_BUILD) +void board_init_f(ulong dummy) +{ + int ret = 0; + + memset(__bss_start, 0, __bss_end - __bss_start); + + 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(); +} +#endif + u64 shikra_get_ddr_sr_exit_address(void) { return g_ddr_sr_exit_address; diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c index 6b46d9db744b..98008b7d0bfd 100644 --- a/drivers/clk/qcom/clock-qcom.c +++ b/drivers/clk/qcom/clock-qcom.c @@ -59,6 +59,63 @@ void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0) ; } +#define PLL_MODE_ACTIVE_FLAG BIT(30) +#define PLL_MODE_BIAS_COUNT GENMASK(19, 14) +#define PLL_MODE_LOCK_COUNT GENMASK(13, 8) +#define PLL_MODE_VOTE_FSM_ENA BIT(20) + +#define PLL_MODE_BIAS_COUNT_VAL (0x6 << 14) +#define PLL_MODE_LOCK_COUNT_VAL (0x0 << 8) + +#define PLL_L_VAL_OFFSET 0x4 +#define PLL_ALPHA_VAL_OFFSET 0x8 +#define PLL_ALPHA_VAL_U_OFFSET 0xc +#define PLL_USER_CTL_OFFSET 0x18 +#define PLL_USER_CTL_U_OFFSET 0x1c +#define PLL_CONFIG_CTL_OFFSET 0x20 +#define PLL_TEST_CTL_OFFSET 0x30 +#define PLL_TEST_CTL_U_OFFSET 0x34 + +#define PLL_LOCK_TIMEOUT_US 200 + +void clk_configure_enable_pll(phys_addr_t base, const struct pll_config *pll) +{ + u32 mode = readl(base + pll->mode_reg); + unsigned int count; + + if ((mode & PLL_MODE_VOTE_FSM_ENA) && + (readl(base + pll->ena_vote) & pll->vote_bit) == pll->vote_bit && + (mode & PLL_MODE_ACTIVE_FLAG)) + return; + + writel(0, base + pll->mode_reg); + writel(pll->user_ctl_u, base + pll->mode_reg + PLL_USER_CTL_U_OFFSET); + writel(pll->config_ctl, base + pll->mode_reg + PLL_CONFIG_CTL_OFFSET); + writel(pll->test_ctl, base + pll->mode_reg + PLL_TEST_CTL_OFFSET); + writel(pll->test_ctl_u, base + pll->mode_reg + PLL_TEST_CTL_U_OFFSET); + writel(pll->user_ctl, base + pll->mode_reg + PLL_USER_CTL_OFFSET); + writel(pll->l_val, base + pll->mode_reg + PLL_L_VAL_OFFSET); + writel(pll->alpha_val, base + pll->mode_reg + PLL_ALPHA_VAL_OFFSET); + writel(pll->alpha_val_u, base + pll->mode_reg + PLL_ALPHA_VAL_U_OFFSET); + + mode &= ~(PLL_MODE_BIAS_COUNT | PLL_MODE_LOCK_COUNT); + mode |= PLL_MODE_BIAS_COUNT_VAL | PLL_MODE_LOCK_COUNT_VAL | + PLL_MODE_VOTE_FSM_ENA; + writel(mode, base + pll->mode_reg); + + setbits_le32(base + pll->ena_vote, pll->vote_bit); + + for (count = 0; count < PLL_LOCK_TIMEOUT_US; count++) { + if (readl(base + pll->mode_reg) & PLL_MODE_ACTIVE_FLAG) + return; + udelay(1); + } + + WARN(count == PLL_LOCK_TIMEOUT_US, + "PLL @ %#llx [%#010x] never locked\n", + base + pll->mode_reg, readl(base + pll->mode_reg)); +} + #define BRANCH_ON_VAL (0) #define BRANCH_NOC_FSM_ON_VAL BIT(29) #define BRANCH_CHECK_MASK GENMASK(31, 28) diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h index 9899cd28aade..ec08a97bb099 100644 --- a/drivers/clk/qcom/clock-qcom.h +++ b/drivers/clk/qcom/clock-qcom.h @@ -36,6 +36,21 @@ struct pll_vote_clk { int vote_bit; }; +/* Configuration for an FSM-voteable Alpha PLL. */ +struct pll_config { + uintptr_t mode_reg; + uintptr_t ena_vote; + u32 vote_bit; + u32 l_val; + u32 alpha_val; + u32 alpha_val_u; + u32 user_ctl; + u32 user_ctl_u; + u32 config_ctl; + u32 test_ctl; + u32 test_ctl_u; +}; + struct vote_clk { uintptr_t cbcr_reg; uintptr_t ena_vote; @@ -107,6 +122,7 @@ struct msm_clk_priv { int qcom_cc_bind(struct udevice *parent); void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0); +void clk_configure_enable_pll(phys_addr_t base, const struct pll_config *pll); void clk_bcr_update(phys_addr_t apps_cmd_rgcr); void clk_enable_cbc(phys_addr_t cbcr); void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk); diff --git a/drivers/clk/qcom/clock-shikra.c b/drivers/clk/qcom/clock-shikra.c index a563e85cb025..7f9e0d1d3799 100644 --- a/drivers/clk/qcom/clock-shikra.c +++ b/drivers/clk/qcom/clock-shikra.c @@ -84,6 +84,21 @@ static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { { } }; +/* GPLL6 configuration required by the SDCC1 clock in SPL. */ +static const struct pll_config gpll6_config = { + .mode_reg = 0x6000, + .ena_vote = 0x79000, + .vote_bit = BIT(6), + .l_val = 40, + .alpha_val = 0x00000000, + .alpha_val_u = 0x00000000, + .user_ctl = 0x01200109, + .user_ctl_u = 0x00000004, + .config_ctl = 0x4001055b, + .test_ctl = 0x00000000, + .test_ctl_u = 0x00000001, +}; + static ulong shikra_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -91,20 +106,16 @@ static ulong shikra_set_rate(struct clk *clk, ulong rate) switch (clk->id) { case GCC_QUPV3_WRAP0_S0_CLK: - /* - * ftbl_gcc_qupv3_wrap0_s0_clk_src[]'s last entry is - * GPLL6-sourced; vote defensively even though this port's - * only requested rate (debug_uart_clock, 14745600) resolves - * to the GPLL0-sourced entry. - */ + /* The QUP clock table includes a GPLL6 source. */ clk_enable_gpll0(priv->base, &gpll6_vote_clk); freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); clk_rcg_set_rate_mnd(priv->base, GCC_QUPV3_WRAP0_S0_CLK_CMD_RCGR, freq->pre_div, freq->m, freq->n, freq->src, 16); return freq->freq; case GCC_SDCC1_APPS_CLK: - clk_enable_gpll0(priv->base, &gpll6_vote_clk); freq = qcom_find_freq(ftbl_gcc_sdcc1_apps_clk_src, rate); + if (freq->src == CFG_CLK_SRC_GPLL6) + clk_configure_enable_pll(priv->base, &gpll6_config); clk_rcg_set_rate_mnd(priv->base, GCC_SDCC1_APPS_CLK_CMD_RCGR, freq->pre_div, freq->m, freq->n, freq->src, 8); return freq->freq; @@ -272,6 +283,18 @@ static int shikra_enable(struct clk *clk) debug("%s: clk %ld: %s\n", __func__, clk->id, shikra_clks[clk->id].name); + switch (clk->id) { + case GCC_QUPV3_WRAP_0_M_AHB_CLK: + case GCC_QUPV3_WRAP_0_S_AHB_CLK: + /* + * The wrapper's core clocks are required along with its AHB + * clocks, but are not listed in the wrapper's clock specifiers. + */ + qcom_gate_clk_en(priv, GCC_QUPV3_WRAP0_CORE_CLK); + qcom_gate_clk_en(priv, GCC_QUPV3_WRAP0_CORE_2X_CLK); + break; + } + return qcom_gate_clk_en(priv, clk->id); } diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c index f3cba695f103..31ad4b3b586f 100644 --- a/drivers/misc/qcom_geni.c +++ b/drivers/misc/qcom_geni.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "GENI-SE: " fmt #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +36,7 @@ struct qup_se_rsc { }; struct geni_se_plat { + struct clk_bulk clks; bool need_firmware_load; bool is_mini_core; }; @@ -446,14 +449,30 @@ int qcom_geni_load_firmware(phys_addr_t qup_base, * We need to determine if firmware loading is necessary. Best way to do that is to check the FW * revision of each QUP and see if it has already been loaded. */ -static int geni_se_of_to_plat(struct udevice *dev) +static int geni_se_probe(struct udevice *dev) { ofnode child; struct resource res; u32 proto; + int ret; struct geni_se_plat *plat = dev_get_plat(dev); + /* Enable the wrapper clocks before accessing serial-engine registers. */ + ret = clk_get_bulk(dev, &plat->clks); + if (ret) { + dev_err(dev, "failed to get wrapper clocks: %d\n", ret); + return ret; + } + + ret = clk_enable_bulk(&plat->clks); + if (ret) { + dev_err(dev, "failed to enable wrapper clocks: %d\n", ret); + clk_release_bulk(&plat->clks); + return ret; + } + plat->need_firmware_load = false; + plat->is_mini_core = false; dev_for_each_subnode(child, dev) { if (!ofnode_is_enabled(child)) @@ -476,32 +495,63 @@ static int geni_se_of_to_plat(struct udevice *dev) return 0; } +static int geni_se_remove(struct udevice *dev) +{ + struct geni_se_plat *plat = dev_get_plat(dev); + + return clk_release_bulk(&plat->clks); +} + #define QUPFW_PART_TYPE_GUID "21d1219f-2ed1-4ab4-930a-41a16ae75f7f" -static int find_qupfw_part(struct udevice **blk_dev, struct disk_partition *part_info) +static int find_qupfw_part(struct udevice *blk_dev, + struct disk_partition *part_info) { struct blk_desc *desc; int ret, partnum; - uclass_foreach_dev_probe(UCLASS_BLK, *blk_dev) { - if (device_get_uclass_id(*blk_dev) != UCLASS_BLK) - continue; + desc = dev_get_uclass_plat(blk_dev); + if (!desc) + return -ENODEV; - desc = dev_get_uclass_plat(*blk_dev); - if (!desc || desc->part_type == PART_TYPE_UNKNOWN) - continue; - for (partnum = 1;; partnum++) { - ret = part_get_info(desc, partnum, part_info); - if (ret) - break; - if (!strcmp(part_info->type_guid, QUPFW_PART_TYPE_GUID)) - return 0; - } + part_init(desc); + if (desc->part_type == PART_TYPE_UNKNOWN) + return -ENOENT; + + for (partnum = 1;; partnum++) { + ret = part_get_info(desc, partnum, part_info); + if (ret) + break; + if (!strcmp(part_info->type_guid, QUPFW_PART_TYPE_GUID)) + return 0; } return -ENOENT; } +static int get_qupfw_blkdev(struct udevice *geni_wrapper, + struct udevice **blk_dev) +{ + struct udevice *mmc_dev; + struct mmc *mmc; + int ret; + + ret = uclass_get_device_by_phandle(UCLASS_MMC, geni_wrapper, + "u-boot,qupfw-storage", &mmc_dev); + if (ret) + return ret; + + mmc = mmc_get_mmc_dev(mmc_dev); + if (!mmc) + return -ENODEV; + + ret = mmc_init(mmc); + if (ret) + return ret; + + return blk_get_from_parent(mmc_dev, blk_dev); +} + static int probe_children_load_firmware(struct udevice *dev) { struct geni_se_plat *plat; @@ -558,6 +608,7 @@ static int qcom_geni_fw_initialise(void) void *fw_buf; size_t fw_size = MAX_FW_BUF_SIZE; struct geni_se_plat *plat; + bool is_mini_core; /* Find the first GENI SE wrapper that needs fw loading */ for (uclass_first_device(UCLASS_MISC, &geni_wrapper); @@ -575,12 +626,19 @@ static int qcom_geni_fw_initialise(void) return 0; } - if (plat->is_mini_core) { + is_mini_core = plat->is_mini_core; + if (is_mini_core) { fw_buf = qup_mini_cores; goto mini_core; } - ret = find_qupfw_part(&blk_dev, &part_info); + ret = get_qupfw_blkdev(geni_wrapper, &blk_dev); + if (ret) { + pr_err("QUP firmware storage device not found: %d\n", ret); + return 0; + } + + ret = find_qupfw_part(blk_dev, &part_info); if (ret) { pr_err("QUP firmware partition not found\n"); return 0; @@ -623,6 +681,9 @@ static int qcom_geni_fw_initialise(void) } } + if (!is_mini_core) + free(fw_buf); + return 0; } @@ -639,7 +700,8 @@ U_BOOT_DRIVER(geni_se_qup) = { .name = "geni-se-qup", .id = UCLASS_MISC, .of_match = geni_ids, - .of_to_plat = geni_se_of_to_plat, + .probe = geni_se_probe, + .remove = geni_se_remove, .plat_auto = sizeof(struct geni_se_plat), .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF, }; From 665f4457470c6a0701f02d57c708701a91153a57 Mon Sep 17 00:00:00 2001 From: "abhilash.v" Date: Sun, 6 Sep 2026 05:53:54 -0700 Subject: [PATCH 3/3] arm: qcom: enable MMU and cache setup for Shikra SPL Use Shikra's fixed pre-DDR memory map when enabling caches in SPL. Allocate page tables from the early malloc-F heap and select the board map through a common Qualcomm hook. Flush BootIMEM before transferring control to QCLIB. Signed-off-by: abhilash.v --- arch/arm/mach-snapdragon/mem_map.c | 22 ++++++- arch/arm/mach-snapdragon/qcom-priv.h | 4 ++ board/qualcomm/shikra/spl-shikra.c | 92 ++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-snapdragon/mem_map.c b/arch/arm/mach-snapdragon/mem_map.c index d95271242cc6..65b968beaef3 100644 --- a/arch/arm/mach-snapdragon/mem_map.c +++ b/arch/arm/mach-snapdragon/mem_map.c @@ -33,6 +33,19 @@ static struct mm_region rbx_mem_map[2 * CONFIG_NR_DRAM_BANKS + 2] = { { 0 } }; struct mm_region *mem_map = rbx_mem_map; +#if defined(CONFIG_SPL_BUILD) +enum qcom_memmap_source qcom_memmap_source __section(".data") = 0; +#endif + +/* + * SPL platforms whose pre-DRAM address map differs from the common Qualcomm + * map may override this hook. + */ +struct mm_region *__weak qcom_spl_mem_map(void) +{ + return NULL; +} + static void build_mem_map(void) { int i, j; @@ -96,10 +109,12 @@ static void build_mem_map(void) #endif } +#if !defined(CONFIG_SPL_BUILD) u64 get_page_table_size(void) { return SZ_1M; } +#endif struct mem_resource_attrs { fdt_addr_t start; @@ -230,6 +245,7 @@ static void configure_reserved_memory(void) */ void enable_caches(void) { + struct mm_region *spl_mem_map; u64 tlb_addr = gd->arch.tlb_addr; u64 tlb_size = gd->arch.tlb_size; u64 pt_size; @@ -237,7 +253,11 @@ void enable_caches(void) gd->arch.tlb_fillptr = tlb_addr; - build_mem_map(); + spl_mem_map = qcom_spl_mem_map(); + if (spl_mem_map) + mem_map = spl_mem_map; + else + build_mem_map(); icache_enable(); diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h index 27e5c54e5128..c267c0d9aec4 100644 --- a/arch/arm/mach-snapdragon/qcom-priv.h +++ b/arch/arm/mach-snapdragon/qcom-priv.h @@ -5,6 +5,8 @@ #include +struct mm_region; + /** * enum qcom_boot_source - Track where we got loaded from. * Used for capsule update logic. @@ -40,4 +42,6 @@ static inline void qcom_configure_capsule_updates(void) {} int qcom_parse_memory(const void *fdt, bool fdt_is_internal); +struct mm_region *qcom_spl_mem_map(void); + #endif /* __QCOM_PRIV_H__ */ diff --git a/board/qualcomm/shikra/spl-shikra.c b/board/qualcomm/shikra/spl-shikra.c index f8115cc30d41..5250c03e8f15 100644 --- a/board/qualcomm/shikra/spl-shikra.c +++ b/board/qualcomm/shikra/spl-shikra.c @@ -3,17 +3,99 @@ * 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 +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_SPL_BUILD) +/* + * The SPL device tree does not describe the complete early physical layout, + * so use Shikra's fixed map when enabling the MMU. + */ +#define SHIKRA_SPL_DEVICE_REG_LOW_BASE 0x00000000UL +#define SHIKRA_SPL_SYSTEM_IMEM_BASE 0x0c100000UL +#define SHIKRA_SPL_SYSTEM_IMEM_SIZE 0x00020000UL +#define SHIKRA_SPL_BOOTIMEM_BASE 0x0c200000UL +#define SHIKRA_SPL_BOOTIMEM_SIZE 0x001c0000UL +#define SHIKRA_SPL_DEVICE_REG_HIGH_BASE (SHIKRA_SPL_BOOTIMEM_BASE + \ + SHIKRA_SPL_BOOTIMEM_SIZE) +#define SHIKRA_SPL_DDR_BASE 0x80000000UL +#define SHIKRA_SPL_DDR_SIZE 0x80000000UL +#define SHIKRA_SPL_DEVICE_REG_LOW_SIZE (SHIKRA_SPL_SYSTEM_IMEM_BASE - \ + SHIKRA_SPL_DEVICE_REG_LOW_BASE) +#define SHIKRA_SPL_DEVICE_REG_HIGH_SIZE (SHIKRA_SPL_DDR_BASE - \ + SHIKRA_SPL_DEVICE_REG_HIGH_BASE) + +static struct mm_region shikra_spl_mem_map[] = { + { + .virt = SHIKRA_SPL_DEVICE_REG_LOW_BASE, + .phys = SHIKRA_SPL_DEVICE_REG_LOW_BASE, + .size = SHIKRA_SPL_DEVICE_REG_LOW_SIZE, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE, + }, { + .virt = SHIKRA_SPL_SYSTEM_IMEM_BASE, + .phys = SHIKRA_SPL_SYSTEM_IMEM_BASE, + .size = SHIKRA_SPL_SYSTEM_IMEM_SIZE, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE, + }, { + /* SPL and QCLIB execute directly from BOOT_IMEM. */ + .virt = SHIKRA_SPL_BOOTIMEM_BASE, + .phys = SHIKRA_SPL_BOOTIMEM_BASE, + .size = SHIKRA_SPL_BOOTIMEM_SIZE, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE, + }, { + .virt = SHIKRA_SPL_DEVICE_REG_HIGH_BASE, + .phys = SHIKRA_SPL_DEVICE_REG_HIGH_BASE, + .size = SHIKRA_SPL_DEVICE_REG_HIGH_SIZE, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE, + }, { + .virt = SHIKRA_SPL_DDR_BASE, + .phys = SHIKRA_SPL_DDR_BASE, + .size = SHIKRA_SPL_DDR_SIZE, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL_NC) | + PTE_BLOCK_INNER_SHARE, + }, { + 0, + } +}; + +struct mm_region *qcom_spl_mem_map(void) +{ + return shikra_spl_mem_map; +} + +int arm_reserve_mmu(void) +{ +#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + mem_map = qcom_spl_mem_map(); + gd->arch.tlb_size = PGTABLE_SIZE; + gd->arch.tlb_addr = (unsigned long)memalign(SZ_64K, gd->arch.tlb_size); + if (!gd->arch.tlb_addr) + return -ENOMEM; +#endif + + return 0; +} +#endif + #define IPQ_SPL_BOOTCFG_REG_ADDR 0x1B46070 #define IPQ_SPL_BOOTCFG_DEV_MASK GENMASK(5, 1) #define IPQ_SPL_BOOTCFG_DEV_SHFT 0x1 @@ -75,6 +157,16 @@ void board_init_f(ulong dummy) preloader_console_init(); +#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + ret = arm_reserve_mmu(); + if (ret) { + pr_debug("arm_reserve_mmu() failed (%d)\n", ret); + goto fail; + } + + enable_caches(); +#endif + ret = qcom_spl_loader_pre_ddr(spl_boot_device()); if (ret) { pr_debug("qcom_spl_loader_pre_ddr() failed (%d)\n", ret);