From b2446a2314310971563c0279345bbd3293614e33 Mon Sep 17 00:00:00 2001 From: Gopinath Sekar Date: Wed, 25 Jun 2025 15:16:07 +0530 Subject: [PATCH 01/35] watchdog: qcom: Add max timeout check to prevent overflow Added a check to ensure the requested timeout does not exceed the hardware's maximum supported value. This prevents register overflow and ensures watchdog reliability. So, added a check in qcom_wdt_start() to ensure the requested timeout does not exceed the hardware-supported maximum value. If the requested value exceeds the maximum value, then the timeout is clamped at maximum value. The timeout is first converted to watchdog ticks and then compared against QCOM_WDT_MAX_TIMEOUT. This helps prevent misconfiguration and potential watchdog misbehavior due to overflow. QCOM_WDT_MAX_TIMEOUT is set to 0xFFFFF, as Qualcomm SoCs typically use 20 bits to store bark/bite timeout values. This work builds upon the previous submission: https://lore.kernel.org/u-boot/20250527124926.128413-1-balaji.selvanathan@oss.qualcomm.com/ Signed-off-by: Gopinath Sekar Reviewed-by: Stefan Roese Link: https://patch.msgid.link/20250625094607.1348494-1-gopinath.sekar@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/watchdog/qcom-wdt.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index 4b972cff72c..e4ebb1f31d4 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -17,6 +17,9 @@ #include +/* Maximum allowed timeout value in Qcom SoCs*/ +#define QCOM_WDT_MAX_TIMEOUT 0xfffff + enum wdt_reg { WDT_RST, WDT_EN, @@ -55,8 +58,24 @@ static void __iomem *wdt_addr(struct qcom_wdt *wdt, enum wdt_reg reg) int qcom_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { struct qcom_wdt *wdt = dev_get_priv(dev); - ulong bark_timeout_s = ((timeout_ms - 1) * wdt->clk_rate) / 1000; - ulong bite_timeout_s = (timeout_ms * wdt->clk_rate) / 1000; + u64 tmp_timeout; + u32 bark_timeout_s, bite_timeout_s; + + /* Compute timeout in watchdog ticks */ + tmp_timeout = (timeout_ms * (u64)wdt->clk_rate) / 1000; + if (tmp_timeout > QCOM_WDT_MAX_TIMEOUT) { + dev_warn(dev, + "Requested timeout (%llu ms) exceeds maximum allowed value (%llu ms). " + "Using max timeout instead.\n", + timeout_ms, + ((u64)QCOM_WDT_MAX_TIMEOUT * 1000) / wdt->clk_rate); + tmp_timeout = (u32)QCOM_WDT_MAX_TIMEOUT; + timeout_ms = (tmp_timeout * 1000) / wdt->clk_rate; + } + + bite_timeout_s = (u32)tmp_timeout; + tmp_timeout = ((timeout_ms - 1) * (u64)wdt->clk_rate) / 1000; + bark_timeout_s = (u32)tmp_timeout; writel(0, wdt_addr(wdt, WDT_EN)); writel(BIT(0), wdt_addr(wdt, WDT_RST)); From fba8fc4a9620c2e4600f609d6c70076885d5184e Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Fri, 27 Jun 2025 10:22:44 +0530 Subject: [PATCH 02/35] usb: dwc3: qcom: Add delays in UTMI clock selection for Qscratch Added delays before and after setting the PIPE_UTMI_CLK_SEL and PIPE3_PHYSTATUS_SW bits in the Qscratch GENERAL_CFG register during UTMI clock selection for DWC3 on Qualcomm platforms. These delays help ensure proper timing and stability of the UTMI clock switching sequence, potentially avoiding race conditions or unstable PHY behavior during initialization. Tested on platforms using Qscratch-based DWC3 PHY configuration. This change is taken from this Linux kernel implementation: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/dwc3/dwc3-qcom.c?id=a4333c3a6ba9ca9cff50a3c1d1bf193dc5489e1c Signed-off-by: Balaji Selvanathan Reviewed-by: Neil Armstrong Reviewed-by: Mattijs Korpershoek Link: https://patch.msgid.link/20250627045244.2225303-1-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/usb/dwc3/dwc3-generic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index bb11613a587..02c02b1d80e 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -461,9 +461,13 @@ static void dwc3_qcom_select_utmi_clk(void __iomem *qscratch_base) setbits_le32(qscratch_base + QSCRATCH_GENERAL_CFG, PIPE_UTMI_CLK_DIS); + udelay(100); + setbits_le32(qscratch_base + QSCRATCH_GENERAL_CFG, PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW); + udelay(100); + clrbits_le32(qscratch_base + QSCRATCH_GENERAL_CFG, PIPE_UTMI_CLK_DIS); } From 83d9b5a7403b4468b7370fdbb891a6938445fc57 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Mon, 30 Jun 2025 12:30:39 +0530 Subject: [PATCH 03/35] configs: Rename qcs9100_defconfig to qcom_qcs9100_defconfig To align with the naming convention used for Qualcomm platforms in U-Boot, renamed the defconfig file from qcs9100_defconfig to qcom_qcs9100_defconfig. Signed-off-by: Balaji Selvanathan Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20250630070040.734486-2-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- configs/{qcs9100_defconfig => qcom_qcs9100_defconfig} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename configs/{qcs9100_defconfig => qcom_qcs9100_defconfig} (100%) diff --git a/configs/qcs9100_defconfig b/configs/qcom_qcs9100_defconfig similarity index 100% rename from configs/qcs9100_defconfig rename to configs/qcom_qcs9100_defconfig From 68daf96a909c882b0c01d203c629c7227e16b4d5 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Mon, 30 Jun 2025 12:30:40 +0530 Subject: [PATCH 04/35] configs: qcom_qcs9100: Fix fastboot buffer address for QCS9100 board The default value of CONFIG_FASTBOOT_BUF_ADDR is 0, which causes NULL pointer dereference during fastboot commands. Set it to 0xdb300000, a safe and sufficiently large region in RAM of the QCS9100 board, to prevent crashes and ensure reliable fastboot functionality. Signed-off-by: Balaji Selvanathan Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20250630070040.734486-3-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- configs/qcom_qcs9100_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/qcom_qcs9100_defconfig b/configs/qcom_qcs9100_defconfig index 216dfa3211e..371448b8b1b 100644 --- a/configs/qcom_qcs9100_defconfig +++ b/configs/qcom_qcs9100_defconfig @@ -8,6 +8,7 @@ # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0xaf000000 CONFIG_REMAKE_ELF=y +CONFIG_FASTBOOT_BUF_ADDR=0xdb300000 CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs9100-ride-r3" CONFIG_ENV_IS_IN_SCSI=y CONFIG_SCSI_ENV_PART_UUID="71cb9cd0-acf1-b6cb-ad91-be9572fe11a9" From fe3b827a59375e44a187669068af1c609e745b43 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 24 Dec 2025 10:17:47 +0530 Subject: [PATCH 05/35] usb: gadget: Kconfig: Correct Qualcomm config name used Correct ARCH_QCOM to ARCH_SNAPDRAGON as ARCH_QCOM is outdated/unused config. Using ARCH_QCOM was causing USB fastboot mode to fail. Signed-off-by: Balaji Selvanathan Reviewed-by: Mattijs Korpershoek Acked-by: Mattijs Korpershoek Reviewed-by: Sumit Garg Link: https://patch.msgid.link/20251224044747.3898137-1-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/usb/gadget/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 7e08aeab904..ebb306852a6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -61,7 +61,7 @@ config USB_GADGET_VENDOR_NUM default 0x0955 if ARCH_TEGRA default 0x1f3a if ARCH_SUNXI default 0x2207 if ARCH_ROCKCHIP - default 0x18d1 if ARCH_QCOM + default 0x18d1 if ARCH_SNAPDRAGON default 0x0 help Vendor ID of the USB device emulated, reported to the host device. @@ -89,7 +89,7 @@ config USB_GADGET_PRODUCT_NUM default 0x350b if ROCKCHIP_RK3588 default 0x350c if ROCKCHIP_RK3528 default 0x350e if ROCKCHIP_RK3576 - default 0x4ee0 if ARCH_QCOM + default 0x4ee0 if ARCH_SNAPDRAGON default 0x0 help Product ID of the USB device emulated, reported to the host device. From 5c71f81101f811816463c7153256c24f43c3f657 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 6 Nov 2025 12:01:48 +0100 Subject: [PATCH 06/35] mach-snapdragon: enable MMU_PGPROT by default Let's enable proper MMU page table protection to properly protect write-protected and non-executable sections. Signed-off-by: Neil Armstrong Reviewed-by: Ilias Apalodimas Link: https://patch.msgid.link/20251106-topic-snapdragron-en-pgprot-v1-1-d2b9e802230b@linaro.org Signed-off-by: Casey Connolly --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0485fe78e10..d5d650e0cb5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1144,6 +1144,7 @@ config ARCH_SNAPDRAGON select SYSRESET select SYSRESET_PSCI select ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR + select MMU_PGPROT imply OF_UPSTREAM imply CMD_DM imply DM_USB_GADGET From bf4045ede829b00b1f82794df84152e7ca839d65 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sat, 8 Nov 2025 02:29:35 +0300 Subject: [PATCH 07/35] mach-snapdragon: capsule_update: Fix eMMC detection for non-UFS devices Currently (since 2026.01-rc) on all SDM630/660 based devices this is printed, after observing long boot delay (several seconds) before executing preboot commands: QCOM-FMP: Failed to find boot partition find_target_partition() function incorrectly assumes that eMMC is always at number 0. In general you can't rely on device numbering to determine if particular block device is eMMC or SD-card, because it depends on how aliases are defined in device tree "chosen" node. Some SoCs have MMC numbers starting at 1, not 0; so mmc1 is eMMC, mmc2 is SD-card. Make eMMC detection reliable by using IS_SD() macro from mmc.h header. Using this method target boot partition can be found successfully. With debug prints enabled, this is printed: QCOM-FMP: skipped SD-Card (devnum 2) QCOM-FMP: Capsule update target: boot (disk 1:60) QCOM-FMP: DFU string: 'mmc 0=u-boot.bin part 1 60' Without debug prints nothing is printed, no error about failure to find boot partition. Fixes: fe80a5f80095 ("mach-snapdragon: CapsuleUpdate: support all boot methods") Signed-off-by: Alexey Minnekhanov Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20251107232935.283843-1-alexeymin@minlexx.ru Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/capsule_update.c | 28 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-snapdragon/capsule_update.c b/arch/arm/mach-snapdragon/capsule_update.c index 3699d91852d..586682434b7 100644 --- a/arch/arm/mach-snapdragon/capsule_update.c +++ b/arch/arm/mach-snapdragon/capsule_update.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,23 @@ static enum ab_slot get_part_slot(const char *partname) return SLOT_NONE; } +/* Shamelessly copied from lib/efi_loader/efi_device_path.c @ 33 */ +/* + * Determine if an MMC device is an SD card. + * + * @desc block device descriptor + * Return: true if the device is an SD card + */ +static bool is_sd(struct blk_desc *desc) +{ + struct mmc *mmc = find_mmc_device(desc->devnum); + + if (!mmc) + return false; + + return IS_SD(mmc) != 0U; +} + /* * Determine which partition U-Boot is flashed to based on the boot source (ABL/XBL), * the slot status, and prioritizing the uefi partition over xbl if found. @@ -109,19 +127,21 @@ static int find_target_partition(int *devnum, enum uclass_id *uclass, if (device_get_uclass_id(dev) != UCLASS_BLK) continue; + desc = dev_get_uclass_plat(dev); + /* If we have a UFS then don't look at any other block devices */ if (have_ufs) { if (device_get_uclass_id(dev->parent->parent) != UCLASS_UFS) continue; + } /* - * If we don't have UFS, then U-Boot must be on the eMMC which is always the first - * MMC device. + * If we don't have UFS, then U-Boot must be on the eMMC */ - } else if (dev->parent->seq_ > 0) { + else if (IS_ENABLED(CONFIG_MMC) && is_sd(desc)) { + log_debug("skipped SD-Card (devnum %d)\n", desc->devnum); continue; } - desc = dev_get_uclass_plat(dev); if (!desc || desc->part_type == PART_TYPE_UNKNOWN) continue; for (partnum = 1;; partnum++) { From 07e66ed61918e127ceb60d51516c267d4c26a865 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Wed, 12 Nov 2025 22:12:04 +0530 Subject: [PATCH 08/35] regulator: qcom-rpmh-regulator: add support for PM8150 PM8350 PM7325 Add the PM8150, PM8350, and PM7325 regulator data found on Qualcomm platforms. These regulator tables are imported from the Linux driver to enable support for these PMICs in U-Boot. Signed-off-by: Aswin Murugan Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251112164204.1557934-1-aswin.murugan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/power/regulator/qcom-rpmh-regulator.c | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index 06466142560..b16cbccbfc4 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -402,6 +402,42 @@ static const struct rpmh_vreg_hw_data pmic5_bob = { .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_bob), }; +static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + .n_voltages = 216, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + +static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000), + .n_voltages = 236, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .n_voltages = 264, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .n_voltages = 264, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, @@ -521,7 +557,34 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"), {} }; @@ -626,6 +689,65 @@ static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps515, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l12"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo_lv, "vdd-l2-l8"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l9-l11"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l2-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l6-l9-l11"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l6-l9-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + {} +}; + +static const struct rpmh_vreg_init_data pm7325_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + {} +}; + /* probe an individual regulator */ static int rpmh_regulator_probe(struct udevice *dev) { @@ -736,6 +858,10 @@ static const struct udevice_id rpmh_regulator_ids[] = { .compatible = "qcom,pm6150l-rpmh-regulators", .data = (ulong)pm6150l_vreg_data, }, + { + .compatible = "qcom,pm7325-rpmh-regulators", + .data = (ulong)pm7325_vreg_data, + }, { .compatible = "qcom,pm8150-rpmh-regulators", .data = (ulong)pm8150_vreg_data, @@ -744,6 +870,10 @@ static const struct udevice_id rpmh_regulator_ids[] = { .compatible = "qcom,pm8150l-rpmh-regulators", .data = (ulong)pm8150l_vreg_data, }, + { + .compatible = "qcom,pm8350c-rpmh-regulators", + .data = (ulong)pm8350c_vreg_data, + }, { .compatible = "qcom,pm8550-rpmh-regulators", .data = (ulong)pm8550_vreg_data, From 46a66c02e9d5211f9c5b2380246680e6bfb31ff5 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Wed, 12 Nov 2025 22:17:57 +0530 Subject: [PATCH 09/35] pinctrl: qcom: add driver for QCS615 SoC Add pinctrl driver for QCS615. Driver code is based on the similar U-Boot and Linux drivers. Signed-off-by: Aswin Murugan Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251112164758.1560041-2-aswin.murugan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/pinctrl/qcom/Kconfig | 7 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-qcs615.c | 473 ++++++++++++++++++++++++++ 3 files changed, 481 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-qcs615.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 320aba33347..725200d94c8 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -55,6 +55,13 @@ config PINCTRL_QCOM_QCS404 Say Y here to enable support for pinctrl on the Snapdragon QCS404 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_QCS615 + bool "Qualcomm QCS615 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon QCS615 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SA8775P bool "Qualcomm SA8775P Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 06582ac2068..b5a111605ed 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o +obj-$(CONFIG_PINCTRL_QCOM_QCS615) += pinctrl-qcs615.o obj-$(CONFIG_PINCTRL_QCOM_SA8775P) += pinctrl-sa8775p.o obj-$(CONFIG_PINCTRL_QCOM_SC7280) += pinctrl-sc7280.o obj-$(CONFIG_PINCTRL_QCOM_SDM660) += pinctrl-sdm660.o diff --git a/drivers/pinctrl/qcom/pinctrl-qcs615.c b/drivers/pinctrl/qcom/pinctrl-qcs615.c new file mode 100644 index 00000000000..1a66cf73456 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-qcs615.c @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +typedef unsigned int msm_pin_function[10]; + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\ + { \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9 \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, ctl) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = ctl + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +#define EAST 0x000000 +#define SOUTH 0xc00000 +#define WEST 0x400000 + +enum qcs615_functions { + msm_mux_gpio, + msm_mux_adsp_ext, + msm_mux_agera_pll, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_tsens, + msm_mux_atest_usb, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cci_timer, + msm_mux_copy_gp, + msm_mux_copy_phase, + msm_mux_cri_trng, + msm_mux_dbg_out_clk, + msm_mux_ddr_bist, + msm_mux_ddr_pxi, + msm_mux_dp_hot, + msm_mux_edp_hot, + msm_mux_edp_lcd, + msm_mux_emac_gcc, + msm_mux_emac_phy_intr, + msm_mux_forced_usb, + msm_mux_gcc_gp, + msm_mux_gp_pdm, + msm_mux_gps_tx, + msm_mux_hs0_mi2s, + msm_mux_hs1_mi2s, + msm_mux_jitter_bist, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_m_voc, + msm_mux_mclk1, + msm_mux_mclk2, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0_out, + msm_mux_mdp_vsync1_out, + msm_mux_mdp_vsync2_out, + msm_mux_mdp_vsync3_out, + msm_mux_mdp_vsync4_out, + msm_mux_mdp_vsync5_out, + msm_mux_mi2s_1, + msm_mux_mss_lte, + msm_mux_nav_pps_in, + msm_mux_nav_pps_out, + msm_mux_pa_indicator_or, + msm_mux_pcie_clk_req, + msm_mux_pcie_ep_rst, + msm_mux_phase_flag, + msm_mux_pll_bist, + msm_mux_pll_bypassnl, + msm_mux_pll_reset_n, + msm_mux_prng_rosc, + msm_mux_qdss_cti, + msm_mux_qdss_gpio, + msm_mux_qlink_enable, + msm_mux_qlink_request, + msm_mux_qspi, + msm_mux_qup0, + msm_mux_qup1, + msm_mux_rgmii, + msm_mux_sd_write_protect, + msm_mux_sp_cmu, + msm_mux_ter_mi2s, + msm_mux_tgu_ch, + msm_mux_uim1, + msm_mux_uim2, + msm_mux_usb0_hs, + msm_mux_usb1_hs, + msm_mux_usb_phy_ps, + msm_mux_vfr_1, + msm_mux_vsense_trigger_mirnat, + msm_mux_wlan, + msm_mux_wsa_clk, + msm_mux_wsa_data, + msm_mux__, +}; + +#define MSM_PIN_FUNCTION(fname) \ + [msm_mux_##fname] = {#fname, msm_mux_##fname} + +static const struct pinctrl_function msm_pinctrl_functions[] = { + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(adsp_ext), + MSM_PIN_FUNCTION(agera_pll), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_tsens), + MSM_PIN_FUNCTION(atest_usb), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async), + MSM_PIN_FUNCTION(cci_i2c), + MSM_PIN_FUNCTION(cci_timer), + MSM_PIN_FUNCTION(copy_gp), + MSM_PIN_FUNCTION(copy_phase), + MSM_PIN_FUNCTION(cri_trng), + MSM_PIN_FUNCTION(dbg_out_clk), + MSM_PIN_FUNCTION(ddr_bist), + MSM_PIN_FUNCTION(ddr_pxi), + MSM_PIN_FUNCTION(dp_hot), + MSM_PIN_FUNCTION(edp_hot), + MSM_PIN_FUNCTION(edp_lcd), + MSM_PIN_FUNCTION(emac_gcc), + MSM_PIN_FUNCTION(emac_phy_intr), + MSM_PIN_FUNCTION(forced_usb), + MSM_PIN_FUNCTION(gcc_gp), + MSM_PIN_FUNCTION(gp_pdm), + MSM_PIN_FUNCTION(gps_tx), + MSM_PIN_FUNCTION(hs0_mi2s), + MSM_PIN_FUNCTION(hs1_mi2s), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(ldo_en), + MSM_PIN_FUNCTION(ldo_update), + MSM_PIN_FUNCTION(m_voc), + MSM_PIN_FUNCTION(mclk1), + MSM_PIN_FUNCTION(mclk2), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mdp_vsync0_out), + MSM_PIN_FUNCTION(mdp_vsync1_out), + MSM_PIN_FUNCTION(mdp_vsync2_out), + MSM_PIN_FUNCTION(mdp_vsync3_out), + MSM_PIN_FUNCTION(mdp_vsync4_out), + MSM_PIN_FUNCTION(mdp_vsync5_out), + MSM_PIN_FUNCTION(mi2s_1), + MSM_PIN_FUNCTION(mss_lte), + MSM_PIN_FUNCTION(nav_pps_in), + MSM_PIN_FUNCTION(nav_pps_out), + MSM_PIN_FUNCTION(pa_indicator_or), + MSM_PIN_FUNCTION(pcie_clk_req), + MSM_PIN_FUNCTION(pcie_ep_rst), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist), + MSM_PIN_FUNCTION(pll_bypassnl), + MSM_PIN_FUNCTION(pll_reset_n), + MSM_PIN_FUNCTION(prng_rosc), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qdss_gpio), + MSM_PIN_FUNCTION(qlink_enable), + MSM_PIN_FUNCTION(qlink_request), + MSM_PIN_FUNCTION(qspi), + MSM_PIN_FUNCTION(qup0), + MSM_PIN_FUNCTION(qup1), + MSM_PIN_FUNCTION(rgmii), + MSM_PIN_FUNCTION(sd_write_protect), + MSM_PIN_FUNCTION(sp_cmu), + MSM_PIN_FUNCTION(ter_mi2s), + MSM_PIN_FUNCTION(tgu_ch), + MSM_PIN_FUNCTION(uim1), + MSM_PIN_FUNCTION(uim2), + MSM_PIN_FUNCTION(usb0_hs), + MSM_PIN_FUNCTION(usb1_hs), + MSM_PIN_FUNCTION(usb_phy_ps), + MSM_PIN_FUNCTION(vfr_1), + MSM_PIN_FUNCTION(vsense_trigger_mirnat), + MSM_PIN_FUNCTION(wlan), + MSM_PIN_FUNCTION(wsa_clk), + MSM_PIN_FUNCTION(wsa_data), +}; + +static const msm_pin_function qcs615_pin_functions[] = { + [0] = PINGROUP(0, qup0, _, qdss_gpio, _, _, _, _, _, _), + [1] = PINGROUP(1, qup0, _, qdss_gpio, _, _, _, _, _, _), + [2] = PINGROUP(2, qup0, _, qdss_gpio, _, _, _, _, _, _), + [3] = PINGROUP(3, qup0, _, qdss_gpio, _, _, _, _, _, _), + [4] = PINGROUP(4, qup0, _, _, _, _, _, _, _, _), + [5] = PINGROUP(5, qup0, _, _, _, _, _, _, _, _), + [6] = PINGROUP(6, qup1, qdss_gpio, ddr_pxi, _, _, _, _, _, _), + [7] = PINGROUP(7, qup1, ddr_bist, qdss_gpio, atest_tsens, + vsense_trigger_mirnat, atest_usb, ddr_pxi, _, _), + [8] = PINGROUP(8, qup1, gp_pdm, ddr_bist, qdss_gpio, _, _, _, _, _), + [9] = PINGROUP(9, qup1, ddr_bist, qdss_gpio, _, _, _, _, _, _), + [10] = PINGROUP(10, qup1, ddr_bist, _, phase_flag, atest_usb, ddr_pxi, _, _, _), + [11] = PINGROUP(11, qup1, dbg_out_clk, atest_usb, ddr_pxi, _, _, _, _, _), + [12] = PINGROUP(12, qup1, jitter_bist, ddr_pxi, _, _, _, _, _, _), + [13] = PINGROUP(13, qup1, pll_bypassnl, _, ddr_pxi, _, _, _, _, _), + [14] = PINGROUP(14, qup1, pll_reset_n, _, qdss_gpio, _, _, _, _, _), + [15] = PINGROUP(15, qup1, qdss_gpio, _, _, _, _, _, _, _), + [16] = PINGROUP(16, qup0, _, wlan, _, _, _, _, _, _), + [17] = PINGROUP(17, qup0, _, wlan, _, _, _, _, _, _), + [18] = PINGROUP(18, qup0, _, phase_flag, _, _, _, _, _, _), + [19] = PINGROUP(19, qup0, _, phase_flag, _, _, _, _, _, _), + [20] = PINGROUP(20, qup1, _, phase_flag, qdss_gpio, _, _, _, _, _), + [21] = PINGROUP(21, qup1, gcc_gp, _, qdss_gpio, _, _, _, _, _), + [22] = PINGROUP(22, qup1, gcc_gp, _, _, _, _, _, _, _), + [23] = PINGROUP(23, qup1, _, phase_flag, _, _, _, _, _, _), + [24] = PINGROUP(24, hs1_mi2s, sd_write_protect, _, phase_flag, _, _, _, _, _), + [25] = PINGROUP(25, hs1_mi2s, _, phase_flag, _, _, _, _, _, _), + [26] = PINGROUP(26, cci_async, hs1_mi2s, jitter_bist, _, _, _, _, _, _), + [27] = PINGROUP(27, hs1_mi2s, pll_bist, _, _, _, _, _, _, _), + [28] = PINGROUP(28, cam_mclk, agera_pll, qdss_gpio, _, _, _, _, _, _), + [29] = PINGROUP(29, cam_mclk, _, qdss_gpio, atest_tsens, _, _, _, _, _), + [30] = PINGROUP(30, cam_mclk, qdss_gpio, _, _, _, _, _, _, _), + [31] = PINGROUP(31, cam_mclk, _, qdss_gpio, _, _, _, _, _, _), + [32] = PINGROUP(32, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [33] = PINGROUP(33, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [34] = PINGROUP(34, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [35] = PINGROUP(35, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [36] = PINGROUP(36, hs0_mi2s, _, _, _, _, _, _, _, _), + [37] = PINGROUP(37, cci_timer, hs0_mi2s, _, _, _, _, _, _, _), + [38] = PINGROUP(38, cci_timer, hs0_mi2s, _, phase_flag, _, _, _, _, _), + [39] = PINGROUP(39, cci_timer, hs0_mi2s, _, _, _, _, _, _, _), + [40] = PINGROUP(40, _, phase_flag, _, _, _, _, _, _, _), + [41] = PINGROUP(41, cci_async, cci_timer, _, phase_flag, _, _, _, _, _), + [42] = PINGROUP(42, cci_async, cci_timer, _, phase_flag, _, _, _, _, _), + [43] = PINGROUP(43, _, phase_flag, forced_usb, _, _, _, _, _, _), + [44] = PINGROUP(44, qspi, _, phase_flag, qdss_gpio, _, _, _, _, _), + [45] = PINGROUP(45, qspi, _, phase_flag, qdss_gpio, _, _, _, _, _), + [46] = PINGROUP(46, qspi, _, qdss_gpio, _, _, _, _, _, _), + [47] = PINGROUP(47, qspi, _, qdss_gpio, wlan, _, _, _, _, _), + [48] = PINGROUP(48, qspi, _, wlan, _, _, _, _, _, _), + [49] = PINGROUP(49, qspi, _, _, _, _, _, _, _, _), + [50] = PINGROUP(50, qspi, _, _, _, _, _, _, _, _), + [51] = PINGROUP(51, qlink_request, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, qlink_enable, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, pa_indicator_or, nav_pps_in, nav_pps_out, gps_tx, _, + phase_flag, _, _, _), + [54] = PINGROUP(54, _, gps_tx, gp_pdm, _, phase_flag, atest_usb, ddr_pxi, _, _), + [55] = PINGROUP(55, _, _, phase_flag, atest_usb, ddr_pxi, _, _, _, _), + [56] = PINGROUP(56, _, nav_pps_in, nav_pps_out, gps_tx, _, _, _, _, _), + [57] = PINGROUP(57, _, nav_pps_in, gps_tx, nav_pps_out, gcc_gp, _, _, _, _), + [58] = PINGROUP(58, _, gcc_gp, _, _, _, _, _, _, _), + [59] = PINGROUP(59, _, nav_pps_in, nav_pps_out, gps_tx, gcc_gp, _, _, _, _), + [60] = PINGROUP(60, _, nav_pps_in, nav_pps_out, gps_tx, cri_trng, _, _, _, _), + [61] = PINGROUP(61, _, cri_trng, _, _, _, _, _, _, _), + [62] = PINGROUP(62, _, cri_trng, _, _, _, _, _, _, _), + [63] = PINGROUP(63, _, _, gp_pdm, _, _, _, _, _, _), + [64] = PINGROUP(64, _, sp_cmu, _, _, _, _, _, _, _), + [65] = PINGROUP(65, _, _, _, _, _, _, _, _, _), + [66] = PINGROUP(66, _, gp_pdm, _, _, _, _, _, _, _), + [67] = PINGROUP(67, _, _, _, phase_flag, atest_usb, _, _, _, _), + [68] = PINGROUP(68, _, _, _, phase_flag, atest_usb, _, _, _, _), + [69] = PINGROUP(69, _, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, _, _, _, _, _, _, _, _, _), + [71] = PINGROUP(71, _, _, _, _, _, _, _, _, _), + [72] = PINGROUP(72, _, _, _, _, _, _, _, _, _), + [73] = PINGROUP(73, uim2, _, _, _, _, _, _, _, _), + [74] = PINGROUP(74, uim2, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, uim2, _, phase_flag, atest_usb, _, _, _, _, _), + [76] = PINGROUP(76, uim2, _, phase_flag, atest_usb, aoss_cti, _, _, _, _), + [77] = PINGROUP(77, uim1, _, phase_flag, atest_usb, _, _, _, _, _), + [78] = PINGROUP(78, uim1, gcc_gp, _, phase_flag, _, _, _, _, _), + [79] = PINGROUP(79, uim1, gp_pdm, _, phase_flag, _, _, _, _, _), + [80] = PINGROUP(80, uim1, _, phase_flag, _, _, _, _, _, _), + [81] = PINGROUP(81, rgmii, mdp_vsync, _, qdss_gpio, _, _, _, _, _), + [82] = PINGROUP(82, rgmii, mdp_vsync, _, phase_flag, qdss_gpio, _, _, _, _), + [83] = PINGROUP(83, rgmii, mdp_vsync, _, qdss_cti, _, _, _, _, _), + [84] = PINGROUP(84, _, phase_flag, atest_char, _, _, _, _, _, _), + [85] = PINGROUP(85, _, atest_char, _, _, _, _, _, _, _), + [86] = PINGROUP(86, copy_gp, _, atest_char, _, _, _, _, _, _), + [87] = PINGROUP(87, _, atest_char, _, _, _, _, _, _, _), + [88] = PINGROUP(88, _, usb0_hs, _, _, _, _, _, _, _), + [89] = PINGROUP(89, emac_phy_intr, pcie_ep_rst, tgu_ch, usb1_hs, _, _, _, _, _), + [90] = PINGROUP(90, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, + mdp_vsync2_out, mdp_vsync3_out, mdp_vsync4_out, mdp_vsync5_out, + pcie_clk_req, tgu_ch), + [91] = PINGROUP(91, rgmii, tgu_ch, _, _, _, _, _, _, _), + [92] = PINGROUP(92, rgmii, vfr_1, tgu_ch, _, phase_flag, qdss_gpio, _, _, _), + [93] = PINGROUP(93, rgmii, qdss_gpio, _, _, _, _, _, _, _), + [94] = PINGROUP(94, rgmii, qdss_gpio, _, _, _, _, _, _, _), + [95] = PINGROUP(95, rgmii, gp_pdm, qdss_gpio, _, _, _, _, _, _), + [96] = PINGROUP(96, rgmii, qdss_cti, _, _, _, _, _, _, _), + [97] = PINGROUP(97, rgmii, mdp_vsync, ldo_en, qdss_cti, _, _, _, _, _), + [98] = PINGROUP(98, mdp_vsync, ldo_update, qdss_cti, _, _, _, _, _, _), + [99] = PINGROUP(99, prng_rosc, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, _, _, _, _, _, _, _, _, _), + [101] = PINGROUP(101, emac_gcc, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, rgmii, dp_hot, emac_gcc, prng_rosc, _, _, _, _, _), + [103] = PINGROUP(103, rgmii, dp_hot, copy_phase, qdss_cti, _, _, _, _, _), + [104] = PINGROUP(104, usb_phy_ps, _, qdss_cti, dp_hot, _, _, _, _, _), + [105] = PINGROUP(105, _, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, mss_lte, _, _, _, _, _, _, _, _), + [107] = PINGROUP(107, mss_lte, _, _, _, _, _, _, _, _), + [108] = PINGROUP(108, mi2s_1, _, qdss_gpio, _, _, _, _, _, _), + [109] = PINGROUP(109, mi2s_1, _, qdss_gpio, _, _, _, _, _, _), + [110] = PINGROUP(110, wsa_data, mi2s_1, _, _, _, _, _, _, _), + [111] = PINGROUP(111, wsa_clk, mi2s_1, _, _, _, _, _, _, _), + [112] = PINGROUP(112, rgmii, _, qdss_cti, _, _, _, _, _, _), + [113] = PINGROUP(113, rgmii, edp_hot, _, qdss_cti, _, _, _, _, _), + [114] = PINGROUP(114, rgmii, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, ter_mi2s, atest_char, _, _, _, _, _, _, _), + [116] = PINGROUP(116, ter_mi2s, _, phase_flag, _, _, _, _, _, _), + [117] = PINGROUP(117, ter_mi2s, _, phase_flag, qdss_gpio, atest_char, _, _, _, _), + [118] = PINGROUP(118, ter_mi2s, adsp_ext, _, phase_flag, qdss_gpio, atest_char, + _, _, _), + [119] = PINGROUP(119, edp_lcd, _, phase_flag, qdss_gpio, atest_char, _, _, _, _), + [120] = PINGROUP(120, m_voc, qdss_gpio, atest_char, _, _, _, _, _, _), + [121] = PINGROUP(121, mclk1, atest_char, _, _, _, _, _, _, _), + [122] = PINGROUP(122, mclk2, _, _, _, _, _, _, _, _), +}; + +static const struct msm_special_pin_data qcs615_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", 0x9f000 + WEST), + [1] = SDC_QDSD_PINGROUP("sdc1_rclk", 0x9a000 + WEST, 15, 0), + [2] = SDC_QDSD_PINGROUP("sdc1_clk", 0x9a000 + WEST, 13, 6), + [3] = SDC_QDSD_PINGROUP("sdc1_cmd", 0x9a000 + WEST, 11, 3), + [4] = SDC_QDSD_PINGROUP("sdc1_data", 0x9a000 + WEST, 9, 0), + [5] = SDC_QDSD_PINGROUP("sdc2_clk", 0x98000 + SOUTH, 14, 6), + [6] = SDC_QDSD_PINGROUP("sdc2_cmd", 0x98000 + SOUTH, 11, 3), + [7] = SDC_QDSD_PINGROUP("sdc2_data", 0x98000 + SOUTH, 9, 0), +}; + +static const unsigned int qcs615_pin_offsets[] = { + [0] = WEST, [1] = WEST, [2] = WEST, + [3] = WEST, [4] = WEST, [5] = WEST, + [6] = EAST, [7] = EAST, [8] = EAST, + [9] = EAST, [10] = EAST, [11] = EAST, + [12] = EAST, [13] = EAST, [14] = EAST, + [15] = EAST, [16] = WEST, [17] = WEST, + [18] = WEST, [19] = WEST, [20] = SOUTH, + [21] = SOUTH, [22] = SOUTH, [23] = SOUTH, + [24] = EAST, [25] = EAST, [26] = EAST, + [27] = EAST, [28] = EAST, [29] = EAST, + [30] = EAST, [31] = EAST, [32] = EAST, + [33] = EAST, [34] = EAST, [35] = EAST, + [36] = EAST, [37] = EAST, [38] = EAST, + [39] = EAST, [40] = EAST, [41] = EAST, + [42] = EAST, [43] = SOUTH, [44] = EAST, + [45] = EAST, [46] = EAST, [47] = EAST, + [48] = EAST, [49] = EAST, [50] = EAST, + [51] = SOUTH, [52] = SOUTH, [53] = SOUTH, + [54] = SOUTH, [55] = SOUTH, [56] = SOUTH, + [57] = SOUTH, [58] = SOUTH, [59] = SOUTH, + [60] = SOUTH, [61] = SOUTH, [62] = SOUTH, + [63] = SOUTH, [64] = SOUTH, [65] = SOUTH, + [66] = SOUTH, [67] = SOUTH, [68] = SOUTH, + [69] = SOUTH, [70] = SOUTH, [71] = SOUTH, + [72] = SOUTH, [73] = SOUTH, [74] = SOUTH, + [75] = SOUTH, [76] = SOUTH, [77] = SOUTH, + [78] = SOUTH, [79] = SOUTH, [80] = SOUTH, + [81] = WEST, [82] = WEST, [83] = WEST, + [84] = SOUTH, [85] = SOUTH, [86] = SOUTH, + [87] = SOUTH, [88] = WEST, [89] = WEST, + [90] = WEST, [91] = WEST, [92] = WEST, + [93] = WEST, [94] = WEST, [95] = WEST, + [96] = WEST, [97] = WEST, [98] = WEST, + [99] = EAST, [100] = WEST, [101] = WEST, + [102] = WEST, [103] = WEST, [104] = WEST, + [105] = SOUTH, [106] = EAST, [107] = EAST, + [108] = SOUTH, [109] = SOUTH, [110] = SOUTH, + [111] = SOUTH, [112] = WEST, [113] = WEST, + [114] = WEST, [115] = SOUTH, [116] = SOUTH, + [117] = SOUTH, [118] = SOUTH, [119] = SOUTH, + [120] = SOUTH, [121] = SOUTH, [122] = SOUTH, +}; + +static const char *qcs615_get_function_name(struct udevice *dev, + unsigned int selector) + +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *qcs615_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct msm_pinctrl_data *data = (struct msm_pinctrl_data *)dev_get_driver_data(dev); + unsigned int special_pins_start = data->pin_data.special_pins_start; + + if (selector > (data->pin_data.pin_count - 1)) + snprintf(pin_name, MAX_PIN_NAME_LEN, "unknown"); + else if (selector >= special_pins_start) + + snprintf(pin_name, MAX_PIN_NAME_LEN, + qcs615_special_pins_data[selector - special_pins_start].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int qcs615_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + unsigned int i; + const msm_pin_function *func = NULL; + + if (pin >= ARRAY_SIZE(qcs615_pin_functions)) + return -EINVAL; + + func = qcs615_pin_functions + pin; + for (i = 0; i < 10; i++) + if ((*func)[i] == selector) + return i; + + pr_err("Can't find requested function for pin %u pin\n", pin); + + return -EINVAL; +} + +static const struct msm_pinctrl_data qcs615_data = { + .pin_data = { + .pin_count = 131, + .special_pins_start = 123, + .special_pins_data = qcs615_special_pins_data, + .pin_offsets = qcs615_pin_offsets, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = qcs615_get_function_name, + .get_function_mux = qcs615_get_function_mux, + .get_pin_name = qcs615_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,qcs615-tlmm", .data = (ulong)&qcs615_data}, + { } +}; + +U_BOOT_DRIVER(qcs615_pinctrl) = { + .name = "qcs615_pinctrl", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, + .flags = DM_FLAG_PRE_RELOC, + +}; From 25a260c2cbcc3fadb1059f9b20e38e06038ccf4b Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Wed, 7 Jan 2026 21:17:44 +0530 Subject: [PATCH 10/35] pinctrl: qcom: add PINCTRL_QCOM_GENERIC to enable all drivers by default Introduce a new Kconfig option PINCTRL_QCOM_GENERIC that, when selected, enables all Qualcomm pinctrl drivers by default. This simplifies defconfigs for platforms supporting multiple SoCs and avoids manual driver selection. Individual drivers can still be disabled if required. Signed-off-by: Aswin Murugan Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260107154745.571319-2-aswin.murugan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/pinctrl/qcom/Kconfig | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 725200d94c8..580308621b1 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -6,8 +6,17 @@ config PINCTRL_QCOM menu "Qualcomm pinctrl drivers" +config PINCTRL_QCOM_GENERIC + bool "Enable all Qualcomm pinctrl drivers by default" + select PINCTRL_QCOM + help + Say Y here to enable all Qualcomm pinctrl drivers by default. + This is useful for generic Qualcomm defconfigs that support + multiple SoCs. Individual drivers can still be disabled if needed. + config PINCTRL_QCOM_APQ8016 bool "Qualcomm APQ8016 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the MSM8916 / APQ8016 @@ -15,6 +24,7 @@ config PINCTRL_QCOM_APQ8016 config PINCTRL_QCOM_APQ8096 bool "Qualcomm APQ8096 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the MSM8996 / APQ8096 @@ -22,6 +32,7 @@ config PINCTRL_QCOM_APQ8096 config PINCTRL_QCOM_IPQ4019 bool "Qualcomm IPQ4019 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the IPQ4019 SoC, @@ -29,6 +40,7 @@ config PINCTRL_QCOM_IPQ4019 config PINCTRL_QCOM_IPQ5424 bool "Qualcomm IPQ5424 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the IPQ5424 SoC, @@ -36,6 +48,7 @@ config PINCTRL_QCOM_IPQ5424 config PINCTRL_QCOM_IPQ9574 bool "Qualcomm IPQ9574 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the IPQ9574 SoC, @@ -43,6 +56,7 @@ config PINCTRL_QCOM_IPQ9574 config PINCTRL_QCOM_QCM2290 bool "Qualcomm QCM2290 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon QCM2290 SoC, @@ -50,6 +64,7 @@ config PINCTRL_QCOM_QCM2290 config PINCTRL_QCOM_QCS404 bool "Qualcomm QCS404 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon QCS404 SoC, @@ -57,6 +72,7 @@ config PINCTRL_QCOM_QCS404 config PINCTRL_QCOM_QCS615 bool "Qualcomm QCS615 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon QCS615 SoC, @@ -64,6 +80,7 @@ config PINCTRL_QCOM_QCS615 config PINCTRL_QCOM_SA8775P bool "Qualcomm SA8775P Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SA8775P SoC, @@ -71,12 +88,14 @@ config PINCTRL_QCOM_SA8775P config PINCTRL_QCOM_SC7280 bool "Qualcomm SC7280/QCM6490 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC, config PINCTRL_QCOM_SDM670 bool "Qualcomm SDM670 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SDM670 SoC, @@ -84,6 +103,7 @@ config PINCTRL_QCOM_SDM670 config PINCTRL_QCOM_SDM660 bool "Qualcomm SDM630/660 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon 630/636/660 @@ -91,6 +111,7 @@ config PINCTRL_QCOM_SDM660 config PINCTRL_QCOM_SDM845 bool "Qualcomm SDM845 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon 845 SoC, @@ -98,6 +119,7 @@ config PINCTRL_QCOM_SDM845 config PINCTRL_QCOM_SM6115 bool "Qualcomm SM6115 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM6115 SoC, @@ -105,12 +127,14 @@ config PINCTRL_QCOM_SM6115 config PINCTRL_QCOM_SM6350 bool "Qualcomm SM6350 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM6350 SoC, config PINCTRL_QCOM_SM7150 bool "Qualcomm SM7150 GCC" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM7150 SoC, @@ -118,6 +142,7 @@ config PINCTRL_QCOM_SM7150 config PINCTRL_QCOM_SM8150 bool "Qualcomm SM8150 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8150 SoC, @@ -125,6 +150,7 @@ config PINCTRL_QCOM_SM8150 config PINCTRL_QCOM_SM8250 bool "Qualcomm SM8250 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8250 SoC, @@ -132,6 +158,7 @@ config PINCTRL_QCOM_SM8250 config PINCTRL_QCOM_SM8550 bool "Qualcomm SM8550 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8550 SoC, @@ -139,6 +166,7 @@ config PINCTRL_QCOM_SM8550 config PINCTRL_QCOM_SM8650 bool "Qualcomm SM8650 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8650 SoC, @@ -146,6 +174,7 @@ config PINCTRL_QCOM_SM8650 config PINCTRL_QCOM_X1E80100 bool "Qualcomm X1E80100 Pinctrl" + default y if PINCTRL_QCOM_GENERIC select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon X1E80100 SoC, From 63439561493f9159732da7be3e1f3d34ffdae030 Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Wed, 7 Jan 2026 21:17:45 +0530 Subject: [PATCH 11/35] qcom_defconfig: Remove redundant pinctrl driver selections Enable PINCTRL_QCOM_GENERIC config The pinctrl drivers are now automatically enabled via Kconfig defaults based on PINCTRL_QCOM_GENERIC, so explicit selection in the defconfig is no longer needed. Signed-off-by: Aswin Murugan Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20260107154745.571319-3-aswin.murugan@oss.qualcomm.com Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index a210f4dc5e6..fe5880de1fd 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -113,23 +113,7 @@ CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y CONFIG_PHY_QCOM_SNPS_EUSB2=y CONFIG_PINCTRL=y CONFIG_PINCONF=y -CONFIG_PINCTRL_QCOM_APQ8016=y -CONFIG_PINCTRL_QCOM_APQ8096=y -CONFIG_PINCTRL_QCOM_QCM2290=y -CONFIG_PINCTRL_QCOM_QCS404=y -CONFIG_PINCTRL_QCOM_SA8775P=y -CONFIG_PINCTRL_QCOM_SC7280=y -CONFIG_PINCTRL_QCOM_SDM670=y -CONFIG_PINCTRL_QCOM_SDM660=y -CONFIG_PINCTRL_QCOM_SDM845=y -CONFIG_PINCTRL_QCOM_SM6115=y -CONFIG_PINCTRL_QCOM_SM6350=y -CONFIG_PINCTRL_QCOM_SM7150=y -CONFIG_PINCTRL_QCOM_SM8150=y -CONFIG_PINCTRL_QCOM_SM8250=y -CONFIG_PINCTRL_QCOM_SM8550=y -CONFIG_PINCTRL_QCOM_SM8650=y -CONFIG_PINCTRL_QCOM_X1E80100=y +CONFIG_PINCTRL_QCOM_GENERIC=y CONFIG_DM_PMIC=y CONFIG_PMIC_QCOM=y CONFIG_DM_REGULATOR=y From 984ebe2d553ba37cd92de2c093c73a07c16ea17c Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Wed, 12 Nov 2025 22:28:51 +0530 Subject: [PATCH 12/35] smem: msm: Fix memory-region lookup, direct mapping and update SMEM host count The SMEM driver was failing to resolve memory regions on some boards because `dev_of_offset()` + `fdtdec_lookup_phandle()` did not yield a valid DT node. Modernize the code to use driver-model/ofnode accessors and make the probe robust for both DT styles (direct `reg` vs `memory-region` phandle). - qcom_smem_map_memory(): * Drop fdtdec path; use dev_read_phandle_with_args() + ofnode_read_resource(). * Use dev_read_phandle_with_args() + fnode_read_resource(). - qcom_smem_probe(): * Try dev_read_addr_size() first (map via ), else fall back to qcom_smem_map_memory() with "memory-region". * Check "qcom,rpm-msg-ram" presence to add second region. - Additionally, SMEM_HOST_COUNT is increased to support newer SMEM versions that include more remote processors. This avoids failures during processor ID checks. Signed-off-by: Aswin Murugan Reviewed-by: Varadarajan Narayanan Link: https://patch.msgid.link/20251112165851.1561418-1-aswin.murugan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/smem/msm_smem.c | 56 +++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/smem/msm_smem.c b/drivers/smem/msm_smem.c index ccd145f9afb..b6b92d3530d 100644 --- a/drivers/smem/msm_smem.c +++ b/drivers/smem/msm_smem.c @@ -88,7 +88,7 @@ DECLARE_GLOBAL_DATA_PTR; #define SMEM_GLOBAL_HOST 0xfffe /* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 10 +#define SMEM_HOST_COUNT 25 /** * struct smem_proc_comm - proc_comm communication struct (legacy) @@ -821,23 +821,34 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, static int qcom_smem_map_memory(struct qcom_smem *smem, struct udevice *dev, const char *name, int i) { - struct fdt_resource r; int ret; - int node = dev_of_offset(dev); + struct ofnode_phandle_args args; + struct resource r; - ret = fdtdec_lookup_phandle(gd->fdt_blob, node, name); - if (ret < 0) { - dev_err(dev, "No %s specified\n", name); + if (!dev_read_prop(dev, name, NULL)) { + dev_err(dev, "%s prop not found\n", name); return -EINVAL; } - ret = fdt_get_resource(gd->fdt_blob, ret, "reg", 0, &r); - if (ret) - return ret; + ret = dev_read_phandle_with_args(dev, name, NULL, 0, 0, &args); + if (ret) { + dev_err(dev, "%s phandle read failed\n", name); + return -EINVAL; + } + if (!ofnode_valid(args.node)) { + dev_err(dev, "Invalid node from phandle args\n"); + return -EINVAL; + } + + ret = ofnode_read_resource(args.node, 0, &r); + if (ret) { + dev_err(dev, "Can't get mmap base address(%d)\n", ret); + return ret; + } smem->regions[i].aux_base = (u32)r.start; - smem->regions[i].size = fdt_resource_size(&r); - smem->regions[i].virt_base = devm_ioremap(dev, r.start, fdt_resource_size(&r)); + smem->regions[i].size = resource_size(&r); + smem->regions[i].virt_base = devm_ioremap(dev, r.start, resource_size(&r)); if (!smem->regions[i].virt_base) return -ENOMEM; @@ -852,10 +863,14 @@ static int qcom_smem_probe(struct udevice *dev) int num_regions; u32 version; int ret; - int node = dev_of_offset(dev); + fdt_addr_t addr; + fdt_size_t size; + + if (__smem) + return 0; num_regions = 1; - if (fdtdec_lookup_phandle(gd->fdt_blob, node, "qcomrpm-msg-ram") >= 0) + if (dev_read_prop(dev, "qcom,rpm-msg-ram", NULL)) num_regions++; array_size = num_regions * sizeof(struct smem_region); @@ -866,9 +881,18 @@ static int qcom_smem_probe(struct udevice *dev) smem->dev = dev; smem->num_regions = num_regions; - ret = qcom_smem_map_memory(smem, dev, "memory-region", 0); - if (ret) - return ret; + addr = dev_read_addr_size(dev, &size); + if (addr == FDT_ADDR_T_NONE) { + ret = qcom_smem_map_memory(smem, dev, "memory-region", 0); + if (ret) + return ret; + } else { + smem->regions[0].aux_base = (u32)addr; + smem->regions[0].size = size; + smem->regions[0].virt_base = devm_ioremap(dev, addr, size); + if (!smem->regions[0].virt_base) + return -ENOMEM; + } if (num_regions > 1) { ret = qcom_smem_map_memory(smem, dev, From 57a5305948f397cf60fc73c5276988deb4fb376a Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 19 Nov 2025 08:55:23 -0600 Subject: [PATCH 13/35] dragonboard820c: Stop disabling device tree relocation Remove setting of fdt_high to ~0, which disables device tree relocation, from the default environment. Doing so prevents U-Boot from correcting problems such as having an unaligned device tree and leads to various failure modes in the OS. Signed-off-by: Tom Rini Link: https://patch.msgid.link/20251119145523.843230-1-trini@konsulko.com Signed-off-by: Casey Connolly --- include/configs/dragonboard820c.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/configs/dragonboard820c.h b/include/configs/dragonboard820c.h index c6d9182ccc9..8e408d8aec3 100644 --- a/include/configs/dragonboard820c.h +++ b/include/configs/dragonboard820c.h @@ -27,7 +27,6 @@ #define CFG_EXTRA_ENV_SETTINGS \ "loadaddr=0x95000000\0" \ - "fdt_high=0xffffffffffffffff\0" \ "initrd_high=0xffffffffffffffff\0" \ "linux_image=uImage\0" \ "kernel_addr_r=0x95000000\0"\ From c9c61c1f4e74ff377d3e43ccf90d5f00e554f2c9 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Fri, 14 Nov 2025 15:47:21 +0100 Subject: [PATCH 14/35] phy: qcom: snps-femto-v2: assert reset in probe The power on function for the phy only deasserts the reset, so the phy might be in a weird state that we don't clean up properly. Assert the reset in probe() so that when we power on we will have the phy in a clean state. Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251114144722.173021-2-casey.connolly@linaro.org Signed-off-by: Casey Connolly --- drivers/phy/qcom/phy-qcom-snps-femto-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qcom/phy-qcom-snps-femto-v2.c b/drivers/phy/qcom/phy-qcom-snps-femto-v2.c index 04f0f0e7817..e782de07ebc 100644 --- a/drivers/phy/qcom/phy-qcom-snps-femto-v2.c +++ b/drivers/phy/qcom/phy-qcom-snps-femto-v2.c @@ -174,7 +174,7 @@ static int qcom_snps_hsphy_phy_probe(struct udevice *dev) return ret; } - reset_deassert_bulk(&priv->resets); + reset_assert_bulk(&priv->resets); return 0; } From 7f1a1fa051073bfee356922614bf00116d9d9254 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 19 Nov 2025 20:53:12 +0530 Subject: [PATCH 15/35] configs: qcom_qcs615: Correct debug UART clock frequency Adjust the debug UART clock frequency from 14745600 Hz to 7372800 Hz for the QCS615 platform. This correction ensures proper UART communication timing and resolves baud rate miscalculations that affects early boot console output. Signed-off-by: Balaji Selvanathan Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20251119152312.4175482-1-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- configs/qcom_qcs615_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/qcom_qcs615_defconfig b/configs/qcom_qcs615_defconfig index 2468267b955..f0362aa6976 100644 --- a/configs/qcom_qcs615_defconfig +++ b/configs/qcom_qcs615_defconfig @@ -12,7 +12,7 @@ CONFIG_DEBUG_UART=y CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_DEBUG_UART_BASE=0x880000 CONFIG_DEBUG_UART_MSM_GENI=y -CONFIG_DEBUG_UART_CLOCK=14745600 +CONFIG_DEBUG_UART_CLOCK=7372800 CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs615-ride" From 4ad3992cc357b24a0fbf6bccf5409fa353e20343 Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Sun, 7 Dec 2025 18:49:19 +0000 Subject: [PATCH 16/35] phy: Add MSM8996 support to Qualcomm QUSB2 phy This change is imported from Linux driver and tested with SM6125 SoC. Note, the msm8996_phy_cfg struct is same as sdm660_phy_cfg but qusb2_phy_cfg::se_clk_scheme_default differs only. Signed-off-by: Biswapriyo Nath Reviewed-by: Casey Connolly Reviewed-by: Sumit Garg Link: https://patch.msgid.link/20251207184919.12202-1-nathbappai@gmail.com Signed-off-by: Casey Connolly --- drivers/phy/qcom/phy-qcom-qusb2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/phy/qcom/phy-qcom-qusb2.c b/drivers/phy/qcom/phy-qcom-qusb2.c index d98f6108e69..9e821365c15 100644 --- a/drivers/phy/qcom/phy-qcom-qusb2.c +++ b/drivers/phy/qcom/phy-qcom-qusb2.c @@ -224,6 +224,18 @@ static const unsigned int qusb2_v2_regs_layout[] = { [QUSB2PHY_INTR_CTRL] = 0x230, }; +static const struct qusb2_phy_cfg msm8996_phy_cfg = { + .tbl = msm8996_init_tbl, + .tbl_num = ARRAY_SIZE(msm8996_init_tbl), + .regs = sm6115_regs_layout, + + .has_pll_test = true, + .se_clk_scheme_default = true, + .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN), + .mask_core_ready = PLL_LOCKED, + .autoresume_en = BIT(3), +}; + static const struct qusb2_phy_cfg sm6115_phy_cfg = { .tbl = sm6115_init_tbl, .tbl_num = ARRAY_SIZE(sm6115_init_tbl), @@ -450,6 +462,8 @@ static struct phy_ops qusb2phy_ops = { }; static const struct udevice_id qusb2phy_ids[] = { + { .compatible = "qcom,msm8996-qusb2-phy", + .data = (ulong)&msm8996_phy_cfg }, { .compatible = "qcom,qusb2-phy" }, { .compatible = "qcom,qcm2290-qusb2-phy", .data = (ulong)&sm6115_phy_cfg }, From edd1fb0c3695d64b8b0b49471595ac0211148409 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 10 Dec 2025 16:54:52 +0100 Subject: [PATCH 17/35] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK When 'max-clk' is not specified, the SDHCI core retrieves the base clock from the SDHCI_CAPABILITIES register (bits [15:8]). However, this field is unreliable on MSM SDHCI controllers, as noted by the Linux driver using the SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN flag. In addition, the field is only 8 bits wide and cannot represent base clocks above 255 MHz. On platforms like Agatti/QCM2290, the firmware sets the SDHCI clock to 384 MHz, but the capabilities register reports 200 MHz. As a result, the core calculates a divider of 4, producing a 96 MHz SDCLK instead of the intended ~52 MHz. This overclocking can cause sporadic CRC errors with certain eMMC. To fix this, use the actual clock rate reported by the SDHCI core clock instead of relying on the capabilities register for divider calculation. Signed-off-by: Loic Poulain Reviewed-by: Sumit Garg Link: https://patch.msgid.link/20251210155454.1561611-1-loic.poulain@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/mmc/msm_sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index ac77fb06bf7..ec003991928 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -114,6 +114,9 @@ static int msm_sdc_clk_init(struct udevice *dev) return -EINVAL; } + /* This is the base clock sdhci core will use to configure the SDCLK */ + prv->host.max_clk = clk_rate; + writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, prv->host.ioaddr + var_info->core_vendor_spec); From 3ddc67573fab30fb4805cb6b2d44eff5386c84df Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 10 Dec 2025 16:54:53 +0100 Subject: [PATCH 18/35] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table Add support for configuring the SDCC1 apps clock on QCM2290 by introducing a frequency table and enabling dynamic rate setting. Previously, the clock was assumed to be fixed at 384 MHz by firmware, which limited flexibility and correctness when selecting optimal rates for SD/MMC operations. Suggested-by: Sumit Garg Signed-off-by: Loic Poulain Reviewed-by: Sumit Garg Link: https://patch.msgid.link/20251210155454.1561611-2-loic.poulain@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-qcm2290.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clock-qcm2290.c b/drivers/clk/qcom/clock-qcm2290.c index fad104fb91a..5a599085b50 100644 --- a/drivers/clk/qcom/clock-qcm2290.c +++ b/drivers/clk/qcom/clock-qcm2290.c @@ -17,6 +17,8 @@ #define QUPV3_WRAP0_S4_CMD_RCGR 0x1f608 #define SDCC2_APPS_CLK_CMD_RCGR 0x1e00c +#define SDCC1_APPS_CLK_CMD_RCGR 0x38028 + static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { F(7372800, CFG_CLK_SRC_GPLL0_AUX2, 1, 384, 15625), @@ -55,6 +57,25 @@ static const struct pll_vote_clk gpll7_clk = { .vote_bit = BIT(7), }; +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, CFG_CLK_SRC_CXO, 16, 3, 25), + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(20000000, CFG_CLK_SRC_GPLL0_AUX2, 5, 1, 3), + F(25000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 1, 2), + F(50000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_AUX2, 3, 0, 0), + F(192000000, CFG_CLK_SRC_GPLL6, 2, 0, 0), + F(384000000, CFG_CLK_SRC_GPLL6, 1, 0, 0), + {} +}; + +static const struct pll_vote_clk gpll6_clk = { + .status = 0x6000, + .status_bit = BIT(31), + .ena_vote = 0x79000, + .vote_bit = BIT(7), +}; + static const struct gate_clk qcm2290_clks[] = { GATE_CLK(GCC_AHB2PHY_USB_CLK, 0x1d008, 0x00000001), GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1a084, 0x00000001), @@ -109,8 +130,12 @@ static ulong qcm2290_set_rate(struct clk *clk, ulong rate) 8); return freq->freq; case GCC_SDCC1_APPS_CLK: - /* The firmware turns this on for us and always sets it to this rate */ - return 384000000; + clk_enable_gpll0(priv->base, &gpll6_clk); + freq = qcom_find_freq(ftbl_gcc_sdcc1_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, SDCC1_APPS_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, + 8); + return freq->freq; default: return 0; } From 338c4b820804323c9c02521df5796c82b6dc1e81 Mon Sep 17 00:00:00 2001 From: Sumit Garg Date: Wed, 10 Dec 2025 16:54:54 +0100 Subject: [PATCH 19/35] mmc: msm_sdhci: Add DLL control hook to disable DLL below 100 MHz Introduce an SDHCI ops hook (config_dll) for MSM SDHCI and implement a minimal DLL control routine that ensures the core DLL is disabled when the bus clock is at or below 100 MHz. This approach mirrors the Linux MSM SDHCI driver. Signed-off-by: Sumit Garg Signed-off-by: Loic Poulain Link: https://patch.msgid.link/20251210155454.1561611-3-loic.poulain@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/mmc/msm_sdhci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index ec003991928..38dc36a2194 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -36,6 +36,11 @@ #define CORE_VENDOR_SPEC_POR_VAL 0xa9c +#define CORE_DLL_PDN BIT(29) +#define CORE_DLL_RST BIT(30) + +#define MHZ(X) ((X) * 1000000UL) + struct msm_sdhc_plat { struct mmc_config cfg; struct mmc mmc; @@ -51,6 +56,7 @@ struct msm_sdhc { struct msm_sdhc_variant_info { bool mci_removed; + u32 core_dll_config; u32 core_vendor_spec; u32 core_vendor_spec_capabilities0; }; @@ -149,6 +155,34 @@ static int msm_sdc_mci_init(struct msm_sdhc *prv) return 0; } +static int msm_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enable) +{ + struct udevice *dev = mmc_to_dev(host->mmc); + const struct msm_sdhc_variant_info *var_info = (void *)dev_get_driver_data(dev); + u32 config; + + if (enable && clock < MHZ(100)) { + /* + * DLL is not required for clock <= 100MHz + * Thus, make sure DLL is disabled when not required + */ + config = readl(host->ioaddr + var_info->core_dll_config); + config |= CORE_DLL_RST; + writel(config, host->ioaddr + var_info->core_dll_config); + + config = readl(host->ioaddr + var_info->core_dll_config); + config |= CORE_DLL_PDN; + writel(config, host->ioaddr + var_info->core_dll_config); + } + + return 0; +} + +struct sdhci_ops msm_sdhci_ops = { + .config_dll = &msm_sdhci_config_dll, + .set_control_reg = &sdhci_set_control_reg, +}; + static int msm_sdc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); @@ -223,6 +257,7 @@ static int msm_sdc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->mmc->dev = dev; + host->ops = &msm_sdhci_ops; ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); if (ret) return ret; @@ -288,6 +323,7 @@ static int msm_sdc_bind(struct udevice *dev) static const struct msm_sdhc_variant_info msm_sdhc_mci_var = { .mci_removed = false, + .core_dll_config = 0x100, .core_vendor_spec = 0x10c, .core_vendor_spec_capabilities0 = 0x11c, }; @@ -295,6 +331,7 @@ static const struct msm_sdhc_variant_info msm_sdhc_mci_var = { static const struct msm_sdhc_variant_info msm_sdhc_v5_var = { .mci_removed = true, + .core_dll_config = 0x200, .core_vendor_spec = 0x20c, .core_vendor_spec_capabilities0 = 0x21c, }; From 9be4f2f5f4d0b8327befde42c743336fa63fc43b Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 14 Jan 2026 14:57:32 +0100 Subject: [PATCH 20/35] mach-snapdragon: of_fixup: support new flat dwc3 node Qualcomm DTs are being updated to use a new format where the dwc3 glue node and controller are combined into a single DT node. Update the fixup code to handle this case. Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260114135739.1546815-1-casey.connolly@linaro.org Signed-off-by: Casey Connolly --- arch/arm/mach-snapdragon/of_fixup.c | 40 +++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-snapdragon/of_fixup.c b/arch/arm/mach-snapdragon/of_fixup.c index eec2c0c757e..5b6076ea8e5 100644 --- a/arch/arm/mach-snapdragon/of_fixup.c +++ b/arch/arm/mach-snapdragon/of_fixup.c @@ -32,7 +32,7 @@ * DT here. This improves compatibility with upstream DT and simplifies the * porting process for new devices. */ -static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np) +static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np, bool flat) { struct device_node *dwc3; int ret, len, hsphy_idx = 1; @@ -41,6 +41,19 @@ static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np debug("Fixing up %s\n", glue_np->name); + /* New DT flattens the glue and controller into a single node. */ + if (flat) { + dwc3 = glue_np; + debug("%s uses flat DT\n", glue_np->name); + } else { + /* Find the DWC3 node itself */ + dwc3 = of_find_compatible_node(glue_np, NULL, "snps,dwc3"); + if (!dwc3) { + log_err("Failed to find dwc3 node\n"); + return -ENOENT; + } + } + /* Tell the glue driver to configure the wrapper for high-speed only operation */ ret = of_write_prop(glue_np, "qcom,select-utmi-as-pipe-clk", 0, NULL); if (ret) { @@ -48,13 +61,6 @@ static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np return ret; } - /* Find the DWC3 node itself */ - dwc3 = of_find_compatible_node(glue_np, NULL, "snps,dwc3"); - if (!dwc3) { - log_err("Failed to find dwc3 node\n"); - return -ENOENT; - } - phandles = of_get_property(dwc3, "phys", &len); len /= sizeof(*phandles); if (len == 1) { @@ -104,13 +110,25 @@ static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np static void fixup_usb_nodes(struct device_node *root) { - struct device_node *glue_np = root; + struct device_node *glue_np = root, *tmp; int ret; + bool flat; + + while (true) { + flat = false; + /* First check for the old DT format with glue node then the new flattened format */ + tmp = of_find_compatible_node(glue_np, NULL, "qcom,dwc3"); + if (!tmp) { + tmp = of_find_compatible_node(glue_np, NULL, "qcom,snps-dwc3"); + flat = !!tmp; + } + if (!tmp) + break; + glue_np = tmp; - while ((glue_np = of_find_compatible_node(glue_np, NULL, "qcom,dwc3"))) { if (!of_device_is_available(glue_np)) continue; - ret = fixup_qcom_dwc3(root, glue_np); + ret = fixup_qcom_dwc3(root, glue_np, flat); if (ret) log_warning("Failed to fixup node %s: %d\n", glue_np->name, ret); } From 7966d35b1fee1a3f4032379b08af7440a79c763b Mon Sep 17 00:00:00 2001 From: Aswin Murugan Date: Wed, 7 Jan 2026 21:05:04 +0530 Subject: [PATCH 21/35] spmi: msm: refine handling of multiple APID mappings PMIC Arbiter may expose multiple owned and non-owned APIDs per SID/PID. - Keep current mapping if it is OWNED and a NON-OWNED appears. - Always update when a NEW OWNED APID appears (make writable). - If current is NON-OWNED and a new NON-OWNED appears, update to it (remain read-only). This avoids write-access violations when not using the newly discovered owned channels. Signed-off-by: Aswin Murugan Link: https://patch.msgid.link/20260107153504.550450-1-aswin.murugan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/spmi/spmi-msm.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c index faae54e9fef..f3cd98c3db8 100644 --- a/drivers/spmi/spmi-msm.c +++ b/drivers/spmi/spmi-msm.c @@ -274,10 +274,25 @@ static void msm_spmi_channel_map_v5(struct msm_spmi_priv *priv, unsigned int i, priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID; if (owner != priv->owner) priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY; - } else if ((owner == priv->owner) && prev_read_only) { - /* Read only and we found one we own, switch */ + + } else if (owner == priv->owner) { + /* + * Found a channel owned by our EE - ALWAYS switch to it! + * even if we already have a mapping, we must prefer the one + * owned by our EE to avoid hardware access violations. + */ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID; + /* Clear READ_ONLY flag since we own this channel */ + + } else if (prev_read_only) { + /* + * Previous mapping was read-only and this one is also not ours. + * Update to this channel. + */ + priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID | SPMI_CHANNEL_READ_ONLY; + } + /* else: Previous was writable and owned by us, this one isn't - keep previous */ } static int msm_spmi_probe(struct udevice *dev) From cb07205adb5b66cc20783a86b26ea6b07a71386d Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Wed, 7 Jan 2026 15:20:38 +0530 Subject: [PATCH 22/35] configs: Fix fastboot buffer address for QCS615 and QCM6490 boards The default value of CONFIG_FASTBOOT_BUF_ADDR is 0, which causes NULL pointer dereference during fastboot commands when users dont provide "-l" option in fastboot usb command. Set it to safe and sufficiently large region in RAM of the QCS615 and QCM6490 boards, to prevent crashes. Signed-off-by: Balaji Selvanathan Reviewed-by: Varadarajan Narayanan Link: https://patch.msgid.link/20260107095038.2491697-1-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- configs/qcm6490_defconfig | 2 ++ configs/qcom_qcs615_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configs/qcm6490_defconfig b/configs/qcm6490_defconfig index 54eb5dedaec..618098c8860 100644 --- a/configs/qcm6490_defconfig +++ b/configs/qcm6490_defconfig @@ -13,3 +13,5 @@ CONFIG_TEXT_BASE=0x9fc00000 CONFIG_REMAKE_ELF=y CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs6490-rb3gen2" + +CONFIG_FASTBOOT_BUF_ADDR=0xd8800000 diff --git a/configs/qcom_qcs615_defconfig b/configs/qcom_qcs615_defconfig index f0362aa6976..27666a8129d 100644 --- a/configs/qcom_qcs615_defconfig +++ b/configs/qcom_qcs615_defconfig @@ -20,3 +20,5 @@ CONFIG_REMAKE_ELF=y # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0x9fc00000 + +CONFIG_FASTBOOT_BUF_ADDR=0xa1600000 From 142df62cb68dae574632640682b9e035ff076720 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 20:49:55 +0100 Subject: [PATCH 23/35] clk/qcom: sc7280: add more QUP clocks Add more clocks for UART2, i2c9 and a few others. This is enough to get the rubikpi 3 working. Link: https://patch.msgid.link/20260108195007.3156604-1-casey.connolly@linaro.org Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-sc7280.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 55a233df394..7b6ed826023 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -63,6 +63,11 @@ static ulong sc7280_set_rate(struct clk *clk, ulong rate) debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate); switch (clk->id) { + case GCC_QUPV3_WRAP0_S2_CLK: /* UART2 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x17270, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; case GCC_QUPV3_WRAP0_S5_CLK: /* UART5 */ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate); clk_rcg_set_rate_mnd(priv->base, 0x17600, @@ -132,9 +137,13 @@ static const struct gate_clk sc7280_clks[] = { GATE_CLK(GCC_AGGRE_NOC_PCIE_CENTER_SF_AXI_CLK, 0x52008, BIT(28)), GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)), GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x52008, BIT(12)), GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x52008, BIT(14)), GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x52008, BIT(16)), GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x52008, BIT(17)), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x52008, BIT(23)), GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)), GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)), GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)), @@ -190,6 +199,9 @@ static int sc7280_enable(struct clk *clk) case GCC_QUPV3_WRAP0_S3_CLK: clk_rcg_set_rate_mnd(priv->base, 0x173a0, 1, 0, 0, CFG_CLK_SRC_CXO, 16); break; + case GCC_QUPV3_WRAP1_S1_CLK: + clk_rcg_set_rate_mnd(priv->base, 0x18140, 1, 0, 0, CFG_CLK_SRC_CXO, 16); + break; } return qcom_gate_clk_en(priv, clk->id); From d38ec14953ebe682d4b8af025050a32b5ecb32eb Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 20:52:55 +0100 Subject: [PATCH 24/35] i2c: geni: bail when clocks can't be enabled Failing to enable clocks will lead to bus hangs and the board crashing in some cases, let's actually deal with this error and fail probe rather than hoping the clocks are already enabled. Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260108195301.3159260-1-casey.connolly@linaro.org Signed-off-by: Casey Connolly --- drivers/i2c/geni_i2c.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c index d29e00fdf41..fbe5ab0ad0c 100644 --- a/drivers/i2c/geni_i2c.c +++ b/drivers/i2c/geni_i2c.c @@ -494,7 +494,9 @@ static int geni_i2c_probe(struct udevice *dev) return ret; } - geni_i2c_enable_clocks(dev, geni); + ret = geni_i2c_enable_clocks(dev, geni); + if (ret) + return ret; proto = readl(geni->base + GENI_FW_REVISION_RO); proto &= FW_REV_PROTOCOL_MSK; From 83dd2675d04f5247d6796fa6294d717069fae19c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 8 Jan 2026 21:28:43 +0100 Subject: [PATCH 25/35] soc: qcom: rpmh-rsc: reclaim the TCS to avoid spurious irq in Linux If we don't reclaim and clear the IRQ bits, we might get a spurious interrupt from this TCS in Linux: WARNING: CPU: 0 PID: 0 at drivers/soc/qcom/rpmh-rsc.c:451 tcs_tx_done+0x98/0x270 ... Call trace: tcs_tx_done+0x98/0x270 (P) __handle_irq_event_percpu+0x60/0x220 handle_irq_event+0x54/0xc0 handle_fasteoi_irq+0xa8/0x1c0 handle_irq_desc+0x3c/0x68 generic_handle_domain_irq+0x24/0x40 gic_handle_irq+0x5c/0xd0 ... Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-1-d1b5b300b665@linaro.org Signed-off-by: Casey Connolly --- drivers/soc/qcom/rpmh-rsc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index aee9e55194e..bc0c3dd005a 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -400,6 +400,13 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) udelay(1); } + __tcs_set_trigger(drv, tcs_id, false); + + /* Reclaim the TCS */ + write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0); + writel_relaxed(BIT(tcs_id), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]); + generic_clear_bit(tcs_id, drv->tcs_in_use); + if (i == USEC_PER_SEC) { log_err("%s: error writing %#x to %d:%#x\n", drv->name, msg->cmds[0].addr, tcs_id, drv->regs[RSC_DRV_CMD_ADDR]); From 16889f764bdceb4cb497bdeda5f80f59a880de70 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 21:28:44 +0100 Subject: [PATCH 26/35] soc/qcom: rpmh: document rsc registers Add some comments explaining a few of the RSC registers Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-2-d1b5b300b665@linaro.org Signed-off-by: Casey Connolly --- drivers/soc/qcom/rpmh-rsc.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index bc0c3dd005a..f51ef0b4af9 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -36,15 +36,31 @@ enum { RSC_DRV_TCS_OFFSET, RSC_DRV_CMD_OFFSET, +/* DRV HW Solver Configuration Information Register */ DRV_SOLVER_CONFIG, +/* DRV TCS Configuration Information Register */ DRV_PRNT_CHLD_CONFIG, +/* Offsets for common TCS Registers, one bit per TCS */ RSC_DRV_IRQ_ENABLE, RSC_DRV_IRQ_STATUS, - RSC_DRV_IRQ_CLEAR, - RSC_DRV_CMD_WAIT_FOR_CMPL, + RSC_DRV_IRQ_CLEAR, /* w/o; write 1 to clear */ +/* + * Offsets for per TCS Registers. + * + * TCSes start at 0x10 from tcs_base and are stored one after another. + * Multiply tcs_id by RSC_DRV_TCS_OFFSET to find a given TCS and add one + * of the below to find a register. + */ + RSC_DRV_CMD_WAIT_FOR_CMPL, /* 1 bit per command */ RSC_DRV_CONTROL, - RSC_DRV_STATUS, - RSC_DRV_CMD_ENABLE, + RSC_DRV_STATUS, /* zero if tcs is busy */ + RSC_DRV_CMD_ENABLE, /* 1 bit per command */ +/* + * Offsets for per command in a TCS. + * + * Commands (up to 16) start at 0x30 in a TCS; multiply command index + * by RSC_DRV_CMD_OFFSET and add one of the below to find a register. + */ RSC_DRV_CMD_MSGID, RSC_DRV_CMD_ADDR, RSC_DRV_CMD_DATA, From 5942ad0ddb54e7042d2f465d563779da4e42bc47 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 21:28:45 +0100 Subject: [PATCH 27/35] soc/qcom: rpmh: correctly wait for TCS flush Several bugs were discovered in the rpmh-rsc driver which collectively meant we were never actually waiting for the TCS to flush, these were likely missed because U-Boot runs single threaded and the RPMh had typically processed the single command we sent by the time we went to send the next one. However a future patch will implement rpmh read support which requires us to properly wait for the RPMh command response so we can return the value. Fix these issues so we correctly ensure the TCS is done before returning. Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-3-d1b5b300b665@linaro.org Signed-off-by: Casey Connolly --- drivers/soc/qcom/rpmh-rsc.c | 44 +++++++++++++++++++------------------ drivers/soc/qcom/rpmh.c | 1 + 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index f51ef0b4af9..05fff174f83 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -284,29 +284,35 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, u32 msgid; u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE; u32 cmd_enable = 0; + u32 cmd_complete = 0; struct tcs_cmd *cmd; int i, j; + if (msg->wait_for_compl) + cmd_msgid |= CMD_MSGID_RESP_REQ; + + cmd_complete = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], tcs_id); + for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) { cmd = &msg->cmds[i]; cmd_enable |= BIT(j); + /* U-Boot: always wait for completion */ + cmd_complete |= (!!msg->wait_for_compl) << j; msgid = cmd_msgid; - /* - * Additionally, if the cmd->wait is set, make the command - * response reqd even if the overall request was fire-n-forget. - */ - msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0; write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data); - debug("tcs(m): %d [%s] cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d\n", + debug("tcs(%d): [%s] cmd_id: %d: msgid: %#x addr: %#x data: %#x complete: %#x\n", tcs_id, msg->state == RPMH_ACTIVE_ONLY_STATE ? "active" : "?", j, msgid, - cmd->addr, cmd->data, cmd->wait); + cmd->addr, cmd->data, cmd_complete); } cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id); write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable); + /* U-Boot: Tell the DRV to wait for completion (?) so we can poll on DRV_STATUS */ + /* This register applies to the entire TCS group not per command */ + write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], tcs_id, cmd_complete); } /** @@ -376,26 +382,22 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger) int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) { struct tcs_group *tcs; - int tcs_id, i; - u32 addr; + int tcs_id, i = 0; + u32 val; tcs = get_tcs_for_msg(drv, msg); if (IS_ERR(tcs)) return PTR_ERR(tcs); - /* u-boot is single-threaded, always use the first TCS as we'll never conflict */ + /* U-Boot is single-threaded, always use the first TCS as we'll never conflict */ tcs_id = tcs->offset; + if (!read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], tcs_id)) { + pr_err("%s: TCS %d is busy!\n", __func__, tcs_id); + return -EBUSY; + } tcs->req[tcs_id - tcs->offset] = msg; generic_set_bit(tcs_id, drv->tcs_in_use); - if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) { - /* - * Clear previously programmed WAKE commands in selected - * repurposed TCS to avoid triggering them. tcs->slots will be - * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate() - */ - write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0); - } /* * These two can be done after the lock is released because: @@ -408,10 +410,10 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) __tcs_buffer_write(drv, tcs_id, 0, msg); __tcs_set_trigger(drv, tcs_id, true); - /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done */ + /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done. */ for (i = 0; i < USEC_PER_SEC; i++) { - addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, 0); - if (addr != msg->cmds[0].addr) + val = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_STATUS], tcs_id, 0); + if (val & CMD_STATUS_COMPL) break; udelay(1); } diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 96f14a9afdf..91b90626af3 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -22,6 +22,7 @@ .state = s, \ .cmds = name.cmd, \ .num_cmds = 0, \ + .wait_for_compl = true \ }, \ .cmd = { { 0 } }, \ .dev = device, \ From dc1cd6ed4b369aff26a10ecec2f65459fef043e9 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 21:28:46 +0100 Subject: [PATCH 28/35] soc/qcom: rpmh: add RPMh read Implement support for RPMh reads, these allow reading out the current votes for RPMh controlled resources such as regulators and interconnects. Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-4-d1b5b300b665@linaro.org Signed-off-by: Casey Connolly --- drivers/soc/qcom/rpmh-rsc.c | 14 ++++++++++++-- drivers/soc/qcom/rpmh.c | 37 +++++++++++++++++++++++++++++++++++-- include/soc/qcom/rpmh.h | 4 +++- include/soc/qcom/tcs.h | 1 + 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 05fff174f83..dce61f26229 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -282,12 +282,15 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, const struct tcs_request *msg) { u32 msgid; - u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE; + u32 cmd_msgid = CMD_MSGID_LEN; u32 cmd_enable = 0; u32 cmd_complete = 0; struct tcs_cmd *cmd; int i, j; + if (!msg->is_read) + cmd_msgid |= CMD_MSGID_WRITE; + if (msg->wait_for_compl) cmd_msgid |= CMD_MSGID_RESP_REQ; @@ -302,7 +305,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr); - write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data); + if (!msg->is_read) + write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data); debug("tcs(%d): [%s] cmd_id: %d: msgid: %#x addr: %#x data: %#x complete: %#x\n", tcs_id, msg->state == RPMH_ACTIVE_ONLY_STATE ? "active" : "?", j, msgid, cmd->addr, cmd->data, cmd_complete); @@ -418,6 +422,12 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) udelay(1); } + /* U-Boot: read the response now we know it's available */ + if (msg->is_read) { + msg->cmds[0].data = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_RESP_DATA], tcs_id, 0); + log_debug("data response: %#x\n", msg->cmds[0].data); + } + __tcs_set_trigger(drv, tcs_id, false); /* Reclaim the TCS */ diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 91b90626af3..8c222324c66 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -68,7 +68,7 @@ static int __rpmh_write(const struct udevice *dev, enum rpmh_state state, } static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state, - const struct tcs_cmd *cmd, u32 n) + const struct tcs_cmd *cmd, u32 n, bool is_read) { if (!cmd || !n || n > MAX_RPMH_PAYLOAD) return -EINVAL; @@ -78,12 +78,45 @@ static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state, req->msg.state = state; req->msg.cmds = req->cmd; req->msg.num_cmds = n; + req->msg.is_read = is_read; debug("rpmh_msg: %d, %d cmds [first %#x/%#x]\n", state, n, cmd->addr, cmd->data); return 0; } +/** + * rpmh_read: Read a resource value + * + * @dev: The device making the request + * @cmd: The payload having address of resource to read + * + * Reads the value for the resource address given in tcs_cmd->addr + * and returns the tcs_cmd->data filled with same. + * + * May sleep. Do not call from atomic contexts. + * + * Return: 0 on success, negative errno on failure + */ +int rpmh_read(const struct udevice *dev, enum rpmh_state state, struct tcs_cmd *cmd) +{ + DEFINE_RPMH_MSG_ONSTACK(dev, state, rpm_msg); + int ret; + + ret = __fill_rpmh_msg(&rpm_msg, state, cmd, 1, true); + if (ret) + return ret; + + ret = __rpmh_write(dev, state, &rpm_msg); + if (ret) + return ret; + + /* Read back the response into the cmd data structure */ + cmd->data = rpm_msg.cmd[0].data; + + return (ret > 0) ? 0 : ret; +} + /** * rpmh_write: Write a set of RPMH commands and block until response * @@ -100,7 +133,7 @@ int rpmh_write(const struct udevice *dev, enum rpmh_state state, DEFINE_RPMH_MSG_ONSTACK(dev, state, rpm_msg); int ret; - ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n); + ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n, false); if (ret) return ret; diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h index 3421fbf1ee3..40812a315bc 100644 --- a/include/soc/qcom/rpmh.h +++ b/include/soc/qcom/rpmh.h @@ -13,12 +13,14 @@ #if IS_ENABLED(CONFIG_QCOM_RPMH) int rpmh_write(const struct udevice *dev, enum rpmh_state state, const struct tcs_cmd *cmd, u32 n); - +int rpmh_read(const struct udevice *dev, enum rpmh_state state, struct tcs_cmd *cmd); #else static inline int rpmh_write(const struct device *dev, enum rpmh_state state, const struct tcs_cmd *cmd, u32 n) { return -ENODEV; } +static inline int rpmh_read(const struct udevice *dev, struct tcs_cmd *cmd) +{ return -ENODEV; } #endif /* CONFIG_QCOM_RPMH */ diff --git a/include/soc/qcom/tcs.h b/include/soc/qcom/tcs.h index 3acca067c72..22bafe2598a 100644 --- a/include/soc/qcom/tcs.h +++ b/include/soc/qcom/tcs.h @@ -55,6 +55,7 @@ struct tcs_cmd { */ struct tcs_request { enum rpmh_state state; + bool is_read; u32 wait_for_compl; u32 num_cmds; struct tcs_cmd *cmds; From 3afd2b9f97db8519fe6d987d69e7f70de0af6321 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 21:28:47 +0100 Subject: [PATCH 29/35] power: regulator: qcom-rpmh: read votes from rpmh Make use of the new RPMh read support to fetch regulator values that may have been voted on by a previous bootloader stage. This allows commands like "regulator status" to report the actual votes programmed into hardware (though not necessarily the actual states of the regulators once the votes have been aggregated). Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-5-d1b5b300b665@linaro.org Signed-off-by: Casey Connolly --- drivers/power/regulator/qcom-rpmh-regulator.c | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index b16cbccbfc4..cabdf089819 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -37,8 +37,11 @@ enum rpmh_regulator_mode { }; #define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0 +#define RPMH_REGULATOR_VOLTAGE_MASK 0x1FFF #define RPMH_REGULATOR_REG_ENABLE 0x4 +#define RPMH_REGULATOR_ENABLE_MASK 0x1 #define RPMH_REGULATOR_REG_VRM_MODE 0x8 +#define RPMH_REGULATOR_MODE_MASK 0x7 #define PMIC4_LDO_MODE_RETENTION 4 #define PMIC4_LDO_MODE_LPM 5 @@ -205,6 +208,38 @@ static int rpmh_regulator_send_request(struct rpmh_vreg *vreg, return ret; } +static int rpmh_regulator_read_data(struct rpmh_vreg *vreg, struct tcs_cmd *cmd) +{ + return rpmh_read(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd); +} + +static int rpmh_regulator_vrm_get_voltage(struct udevice *rdev, int *uV) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE, + }; + const struct linear_range *uv_range = &vreg->hw_data->voltage_range; + int min_uV = uv_range->min; + int max_uV = uv_range->min + uv_range->max_sel * uv_range->step; + + int ret, _uV = 0; + + ret = rpmh_regulator_read_data(vreg, &cmd); + if (!ret) + _uV = (cmd.data & RPMH_REGULATOR_VOLTAGE_MASK) * 1000; + else + dev_err(vreg->dev, "failed to read VOLTAGE ret = %d\n", ret); + + if (!_uV || (_uV >= min_uV && _uV <= max_uV)) + *uV = _uV; + else + dev_info(vreg->dev, "read voltage %d is out-of-range[%d:%d]\n", + _uV, min_uV, max_uV); + + return ret; +} + static int _rpmh_regulator_vrm_set_value(struct udevice *rdev, int uv, bool wait_for_ack) { @@ -249,8 +284,13 @@ static int rpmh_regulator_vrm_set_value(struct udevice *rdev, static int rpmh_regulator_vrm_get_value(struct udevice *rdev) { struct rpmh_vreg *vreg = dev_get_priv(rdev); + int ret, uV; - debug("%s: get_value %d\n", rdev->name, vreg->uv); + if (vreg->uv < 0) { + ret = rpmh_regulator_vrm_get_voltage(rdev, &uV); + if (!ret && uV != 0) + vreg->uv = uV; + } return vreg->uv; } @@ -258,9 +298,23 @@ static int rpmh_regulator_vrm_get_value(struct udevice *rdev) static int rpmh_regulator_is_enabled(struct udevice *rdev) { struct rpmh_vreg *vreg = dev_get_priv(rdev); + int ret; debug("%s: is_enabled %d\n", rdev->name, vreg->enabled); + if (vreg->enabled < 0) { + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE, + }; + ret = rpmh_regulator_read_data(vreg, &cmd); + /* + * Don't override if disabled since we will also vote the right voltage + * while enabling + */ + if (!ret && cmd.data) + vreg->enabled = cmd.data & RPMH_REGULATOR_ENABLE_MASK; + } + return vreg->enabled > 0; } @@ -340,12 +394,32 @@ static int rpmh_regulator_vrm_set_mode(struct udevice *rdev, return ret; } +static int rpmh_regulator_vrm_get_pmic_mode(struct rpmh_vreg *vreg, int *pmic_mode) +{ + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE, + }; + int ret; + + ret = rpmh_regulator_read_data(vreg, &cmd); + if (!ret) + *pmic_mode = cmd.data & RPMH_REGULATOR_MODE_MASK; + else + return -EINVAL; + + return 0; +} + static int rpmh_regulator_vrm_get_mode(struct udevice *rdev) { struct rpmh_vreg *vreg = dev_get_priv(rdev); + int mode; debug("%s: get_mode %d\n", rdev->name, vreg->mode); + if (!rpmh_regulator_vrm_get_pmic_mode(vreg, &mode)) + vreg->mode = mode; + return vreg->mode; } static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = { From deb2b9c4033b5c3cc684ca62c79db61a7ca3d199 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Thu, 8 Jan 2026 21:28:48 +0100 Subject: [PATCH 30/35] power: regulator: qcom-rpmh: correctly map pmic mode Currently we don't properly map between the regulator mode ID enum and the appropriate register values in the mode map, as a result we always unintentionally vote for retention mode if we actually attempt to set it. In the set_mode path we did find the appropriate entry in the mode map but we wrote the id instead of the register values. Clean this up and properly map id -> mode and vice versa. Link: https://patch.msgid.link/20260108-rpmh-regulator-fixes-v1-6-d1b5b300b665@linaro.org Signed-off-by: Casey Connolly --- drivers/power/regulator/qcom-rpmh-regulator.c | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index cabdf089819..3f0f1845469 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -369,9 +369,11 @@ static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg, } if (bypassed) - cmd.data = PMIC4_BOB_MODE_PASS; + // XXX: should have a version check for PMIC4 but we don't have any yet + // and we don't use bypass mode + cmd.data = PMIC5_BOB_MODE_PASS; else - cmd.data = pmic_mode->id; + cmd.data = pmic_mode->register_value; return rpmh_regulator_send_request(vreg, &cmd, true); } @@ -399,15 +401,23 @@ static int rpmh_regulator_vrm_get_pmic_mode(struct rpmh_vreg *vreg, int *pmic_mo struct tcs_cmd cmd = { .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE, }; - int ret; + struct dm_regulator_mode *pmic_mode_map = vreg->hw_data->pmic_mode_map; + int ret, register_value; ret = rpmh_regulator_read_data(vreg, &cmd); if (!ret) - *pmic_mode = cmd.data & RPMH_REGULATOR_MODE_MASK; + register_value = cmd.data & RPMH_REGULATOR_MODE_MASK; else return -EINVAL; - return 0; + for (int i = 0; i < vreg->hw_data->n_modes; i++) { + if (pmic_mode_map[i].register_value == register_value) { + *pmic_mode = pmic_mode_map[i].id; + return 0; + } + } + + return -EINVAL; } static int rpmh_regulator_vrm_get_mode(struct udevice *rdev) From 500d2e5e554650f02bd7e23c9539d4d6580a6d90 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Thu, 8 Jan 2026 23:13:01 +0100 Subject: [PATCH 31/35] doc: board: qualcomm: document Pixel 3 / 3 XL support U-Boot does work on Qualcomm 845-based Pixel 3 and 3 XL. Reviewed-by: Simon Glass Reviewed-by: Casey Connolly Signed-off-by: David Heidelberg Reviewed-by: Petr Vorel Link: https://patch.msgid.link/20260108-pixel-config-v4-1-76a2212b69a5@ixit.cz Signed-off-by: Casey Connolly --- doc/board/qualcomm/board.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/board/qualcomm/board.rst b/doc/board/qualcomm/board.rst index 642c5095261..e5dbc9816b9 100644 --- a/doc/board/qualcomm/board.rst +++ b/doc/board/qualcomm/board.rst @@ -38,6 +38,25 @@ with appended dtb, so let's mimic linux to satisfy stock bootloader. Boards ------ +Pixel 3 (blueline) and Pixel 3 XL (crosshatch) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +blueline refers to the Google Pixel 3, and crosshatch to the Pixel 3 XL, both +powered by the Qualcomm SDM845 SoC. + +These devices use the common qcom_defconfig with the google-pixel.config +fragment for configuration. + +Use the following commands:: + + make CROSS_COMPILE=aarch64-linux-gnu- O=.output qcom_defconfig google-pixel.config qcom-phone.config + +The DTB is called: + + - "sdm845-google-blueline.dtb" (Pixel 3) + - "sdm845-google-crosshatch.dtb" (Pixel 3 XL) + +More information can be found on the `Google Pixel 3 page`_. + starqlte ^^^^^^^^ @@ -131,5 +150,6 @@ Other devices with boot image version 2 can be built like this example:: fastboot flash boot boot.img fastboot erase dtbo +.. _Google Pixel 3 page: https://en.wikipedia.org/wiki/Pixel_3 .. _Samsung S9 page: https://en.wikipedia.org/wiki/Samsung_Galaxy_S9 .. _DragonBoard 845c page: https://www.96boards.org/product/rb3-platform/ From 338dbbba8787ecc74c4d532b37c5fd1c7ab83e00 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Thu, 8 Jan 2026 23:13:02 +0100 Subject: [PATCH 32/35] configs: Add google-pixel fragment config for Pixel 3, 3 XL, 5 Introduce a fragment config for the Pixel 3, Pixel 3 XL, Pixel 5. On these devices, U-Boot is chainloaded via fastboot. However, due to additional requirements added by Google, the image header must have a specific value for the text offset. This is solved by setting CONFIG_TEXT_BASE to 0x80080000 in U-Boot. Reviewed-by: Simon Glass Signed-off-by: David Heidelberg Reviewed-by: Petr Vorel Link: https://patch.msgid.link/20260108-pixel-config-v4-2-76a2212b69a5@ixit.cz Signed-off-by: Casey Connolly --- board/qualcomm/google-pixel.config | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 board/qualcomm/google-pixel.config diff --git a/board/qualcomm/google-pixel.config b/board/qualcomm/google-pixel.config new file mode 100644 index 00000000000..999d4e45268 --- /dev/null +++ b/board/qualcomm/google-pixel.config @@ -0,0 +1,5 @@ +# Enables chainloading of U-Boot on Google Pixel phones using +# newer bootloaders (Android Q/R) +# Use for following devices: Pixel 3 (blueline), Pixel 3 XL (crosshatch), +# Pixel 5 (redfin)... +CONFIG_TEXT_BASE=0x80080000 From 3422e915aca58faf32a80eaa3a05e7894307f81c Mon Sep 17 00:00:00 2001 From: Swathi Tamilselvan Date: Tue, 13 Jan 2026 09:52:13 +0530 Subject: [PATCH 33/35] clk: qcom: sa8775p: Add QUP serial engine clock support Add clock gate definitions and entries for QUP (Qualcomm Universal Peripheral) serial engine clocks across all four wrappers on SA8775P. This enables proper clock management for I2C, SPI, and UART peripherals connected to the QUP blocks. This resolves the "unknown clock ID 133" error for UART10 and provides complete QUP clock infrastructure for the platform. Signed-off-by: Swathi Tamilselvan Signed-off-by: Balaji Selvanathan Link: https://patch.msgid.link/20260113042213.3107106-1-balaji.selvanathan@oss.qualcomm.com Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-sa8775p.c | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/clk/qcom/clock-sa8775p.c b/drivers/clk/qcom/clock-sa8775p.c index 527cecf5c82..5a6fbd417ff 100644 --- a/drivers/clk/qcom/clock-sa8775p.c +++ b/drivers/clk/qcom/clock-sa8775p.c @@ -18,6 +18,31 @@ #define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038 #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020 +#define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) +#define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) +#define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) +#define GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT BIT(13) +#define GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT BIT(14) +#define GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT BIT(15) + +#define GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT BIT(22) +#define GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT BIT(23) +#define GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT BIT(24) +#define GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT BIT(25) +#define GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT BIT(26) +#define GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT BIT(27) +#define GCC_QUPV3_WRAP1_S6_CLK_ENA_BIT BIT(27) + +#define GCC_QUPV3_WRAP2_S0_CLK_ENA_BIT BIT(4) +#define GCC_QUPV3_WRAP2_S1_CLK_ENA_BIT BIT(5) +#define GCC_QUPV3_WRAP2_S2_CLK_ENA_BIT BIT(6) +#define GCC_QUPV3_WRAP2_S3_CLK_ENA_BIT BIT(7) +#define GCC_QUPV3_WRAP2_S4_CLK_ENA_BIT BIT(8) +#define GCC_QUPV3_WRAP2_S5_CLK_ENA_BIT BIT(9) +#define GCC_QUPV3_WRAP2_S6_CLK_ENA_BIT BIT(29) + +#define GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT BIT(25) + static ulong sa8775p_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -50,6 +75,35 @@ static const struct gate_clk sa8775p_clks[] = { GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1b024, 1), GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1b05c, 1), GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1b060, 1), + + /* QUP Wrapper 0 clocks */ + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x4b008, GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x4b008, GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x4b008, GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x4b008, GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x4b008, GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x4b008, GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT), + + /* QUP Wrapper 1 clocks (includes uart10) */ + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x4b008, GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x4b008, GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x4b008, GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x4b008, GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT), /* uart10 */ + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x4b008, GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x4b008, GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x4b018, GCC_QUPV3_WRAP1_S6_CLK_ENA_BIT), + + /* QUP Wrapper 2 clocks */ + GATE_CLK(GCC_QUPV3_WRAP2_S0_CLK, 0x4b010, GCC_QUPV3_WRAP2_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP2_S1_CLK, 0x4b010, GCC_QUPV3_WRAP2_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP2_S2_CLK, 0x4b010, GCC_QUPV3_WRAP2_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP2_S3_CLK, 0x4b010, GCC_QUPV3_WRAP2_S3_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP2_S4_CLK, 0x4b010, GCC_QUPV3_WRAP2_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP2_S5_CLK, 0x4b010, GCC_QUPV3_WRAP2_S5_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP2_S6_CLK, 0x4b018, GCC_QUPV3_WRAP2_S6_CLK_ENA_BIT), + + /* QUP Wrapper 3 clocks */ + GATE_CLK(GCC_QUPV3_WRAP3_S0_CLK, 0x4b000, GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT), }; static int sa8775p_enable(struct clk *clk) From f4886799a0afd20ab4df663247bff3c1a78a2b85 Mon Sep 17 00:00:00 2001 From: Balaji Selvanathan Date: Tue, 13 Jan 2026 12:28:55 +0530 Subject: [PATCH 34/35] clk: qcom: sa8775p: Fix USB clock configuration and add resets Correct USB30 primary clock RCG configuration and add missing USB3_PRIM_PHY_AUX_CMD_RCGR RCG configuration. Above taken from Linux commit 08c51ceb12f7 ("clk: qcom: add the GCC driver for sa8775p") Add missing USB3_PRIM_PHY_PIPE_CLK gate clock definition. Extend reset map with USB-related BCR entries and video BCR for comprehensive reset control support. Signed-off-by: Balaji Selvanathan Link: https://patch.msgid.link/20260113065856.3287772-1-balaji.selvanathan@oss.qualcomm.com [casey: indentation fix] Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-sa8775p.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/clock-sa8775p.c b/drivers/clk/qcom/clock-sa8775p.c index 5a6fbd417ff..4957abf6f58 100644 --- a/drivers/clk/qcom/clock-sa8775p.c +++ b/drivers/clk/qcom/clock-sa8775p.c @@ -15,8 +15,9 @@ #include #include "clock-qcom.h" -#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038 -#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020 +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0x1b040 +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0x1b028 +#define USB3_PRIM_PHY_AUX_CMD_RCGR 0x1b06c #define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) #define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) @@ -59,8 +60,8 @@ static ulong sa8775p_set_rate(struct clk *clk, ulong rate) case GCC_USB30_PRIM_MASTER_CLK: WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate); clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, - 1, 0, 0, CFG_CLK_SRC_GPLL0_ODD, 8); - clk_rcg_set_rate(priv->base, 0xf064, 0, 0); + 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); + clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); return rate; default: return 0; @@ -75,6 +76,7 @@ static const struct gate_clk sa8775p_clks[] = { GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1b024, 1), GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1b05c, 1), GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1b060, 1), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x1b064, 1), /* QUP Wrapper 0 clocks */ GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x4b008, GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT), @@ -157,6 +159,24 @@ static const struct qcom_reset_map sa8775p_gcc_resets[] = { [GCC_TSCSS_BCR] = { 0x21000 }, [GCC_UFS_CARD_BCR] = { 0x81000 }, [GCC_UFS_PHY_BCR] = { 0x83000 }, + [GCC_USB20_PRIM_BCR] = {0x1c000}, + [GCC_USB2_PHY_PRIM_BCR] = {0x5c028}, + [GCC_USB2_PHY_SEC_BCR] = {0x5c02c}, + [GCC_USB30_PRIM_BCR] = {0x1b000}, + [GCC_USB30_SEC_BCR] = {0x2f000}, + [GCC_USB3_DP_PHY_PRIM_BCR] = {0x5c008}, + [GCC_USB3_DP_PHY_SEC_BCR] = {0x5c014}, + [GCC_USB3_PHY_PRIM_BCR] = {0x5c000}, + [GCC_USB3_PHY_SEC_BCR] = {0x5c00c}, + [GCC_USB3_PHY_TERT_BCR] = {0x5c030}, + [GCC_USB3_UNIPHY_MP0_BCR] = {0x5c018}, + [GCC_USB3_UNIPHY_MP1_BCR] = {0x5c01c}, + [GCC_USB3PHY_PHY_PRIM_BCR] = {0x5c004}, + [GCC_USB3PHY_PHY_SEC_BCR] = {0x5c010}, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = {0x5c020}, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = {0x5c024}, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = {0x76000}, + [GCC_VIDEO_BCR] = {0x34000} }; static const struct qcom_power_map sa8775p_gdscs[] = { From cd8ee4fff82788546df06fae7bbe6d22a710737b Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Fri, 16 Jan 2026 18:09:44 +0100 Subject: [PATCH 35/35] usb: dwc3-generic: support Qualcomm flattened DT Qualcomm devicetrees are moving away from having a glue node with dwc3 as a subnode and now may just have a single flattened node. Rockchip already have a glue_get_ctrl_dev op which returns the node for the glue device itself, commonise this and reuse it for the new Qualcomm node. Lastly adjust the qscratch base address since it now requires an offset from the dwc3 base. Link: https://patch.msgid.link/20260116-casey-usb-role-switch-v2-1-83a1a6501a11@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/dwc3/dwc3-generic.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 02c02b1d80e..22b9ef0b24e 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -476,7 +476,14 @@ static void dwc3_qcom_glue_configure(struct udevice *dev, int index, enum usb_dr_mode mode) { struct dwc3_glue_data *glue = dev_get_plat(dev); - void __iomem *qscratch_base = map_physmem(glue->regs, 0x400, MAP_NOCACHE); + fdt_addr_t regs = glue->regs; + void __iomem *qscratch_base; + + /* Offset for qscratch base when using flat DT */ + if (device_is_compatible(dev, "qcom,snps-dwc3")) + regs += SDM845_QSCRATCH_BASE_OFFSET; + + qscratch_base = map_physmem(regs, 0x400, MAP_NOCACHE); if (IS_ERR_OR_NULL(qscratch_base)) { log_err("%s: Invalid qscratch base address\n", dev->name); return; @@ -489,11 +496,8 @@ static void dwc3_qcom_glue_configure(struct udevice *dev, int index, dwc3_qcom_vbus_override_enable(qscratch_base, true); } -struct dwc3_glue_ops qcom_ops = { - .glue_configure = dwc3_qcom_glue_configure, -}; - -static int dwc3_rk_glue_get_ctrl_dev(struct udevice *dev, ofnode *node) +/* In cases where there is no dwc3 node and it's flattened into the glue node */ +static int dwc3_flat_dt_get_ctrl_dev(struct udevice *dev, ofnode *node) { *node = dev_ofnode(dev); if (!ofnode_valid(*node)) @@ -502,8 +506,17 @@ static int dwc3_rk_glue_get_ctrl_dev(struct udevice *dev, ofnode *node) return 0; } +struct dwc3_glue_ops qcom_ops = { + .glue_configure = dwc3_qcom_glue_configure, +}; + +struct dwc3_glue_ops qcom_flat_dt_ops = { + .glue_configure = dwc3_qcom_glue_configure, + .glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev, +}; + struct dwc3_glue_ops rk_ops = { - .glue_get_ctrl_dev = dwc3_rk_glue_get_ctrl_dev, + .glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev, }; static int dwc3_glue_bind_common(struct udevice *parent, ofnode node) @@ -712,6 +725,7 @@ static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&rk_ops }, { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops }, { .compatible = "qcom,dwc3", .data = (ulong)&qcom_ops }, + { .compatible = "qcom,snps-dwc3", .data = (ulong)&qcom_flat_dt_ops }, { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops }, { .compatible = "fsl,imx8mq-dwc3" }, { .compatible = "intel,tangier-dwc3" },