Merge tag 'qcom-more-for-2025.07' of https://source.denx.de/u-boot/custodians/u-boot-snapdragon

More Qualcomm fixes for 2025.07

* Adjust fdtfile logic to support more boards
* Support linux,code variable in qcom-pmic button driver
* Minor CLK API adjustments and apq8096/msm8916 fixes
* vbus regulator register fixes
* dragonboard410c KASLR support and other fixes
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 3ab75f0..5547d6d 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -409,52 +409,39 @@
 		return;
 	}
 
-	/* The last compatible is always the SoC compatible */
-	ret = ofnode_read_string_index(root, "compatible", compat_count - 1, &last_compat);
-	if (ret < 0) {
-		log_warning("Can't read second compatible\n");
-		return;
-	}
-
-	/* Copy the second compat (e.g. "qcom,sdm845") into buf */
-	strlcpy(buf, last_compat, sizeof(buf) - 1);
-	tmp = buf;
-
-	/* strsep() is destructive, it replaces the comma with a \0 */
-	if (!strsep(&tmp, ",")) {
-		log_warning("second compatible '%s' has no ','\n", buf);
-		return;
-	}
-
-	/* tmp now points to just the "sdm845" part of the string */
-	env_set("soc", tmp);
-
-	/* Now figure out the "board" part from the first compatible */
-	memset(buf, 0, sizeof(buf));
 	strlcpy(buf, first_compat, sizeof(buf) - 1);
 	tmp = buf;
 
 	/* The Qualcomm reference boards (RBx, HDK, etc)  */
 	if (!strncmp("qcom", buf, strlen("qcom"))) {
+		char *soc;
+
 		/*
 		 * They all have the first compatible as "qcom,<soc>-<board>"
 		 * (e.g. "qcom,qrb5165-rb5"). We extract just the part after
 		 * the dash.
 		 */
-		if (!strsep(&tmp, "-")) {
+		if (!strsep(&tmp, ",")) {
+			log_warning("compatible '%s' has no ','\n", buf);
+			return;
+		}
+		soc = strsep(&tmp, "-");
+		if (!soc) {
 			log_warning("compatible '%s' has no '-'\n", buf);
 			return;
 		}
-		/* tmp is now "rb5" */
+
+		env_set("soc", soc);
 		env_set("board", tmp);
 	} else {
 		if (!strsep(&tmp, ",")) {
 			log_warning("compatible '%s' has no ','\n", buf);
 			return;
 		}
-		/* for thundercomm we just want the bit after the comma (e.g. "db845c"),
-		 * for all other boards we replace the comma with a '-' and take both
-		 * (e.g. "oneplus-enchilada")
+		/*
+		 * For thundercomm we just want the bit after the comma
+		 * (e.g. "db845c"), for all other boards we replace the comma
+		 * with a '-' and take both (e.g. "oneplus-enchilada")
 		 */
 		if (!strncmp("thundercomm", buf, strlen("thundercomm"))) {
 			env_set("board", tmp);
@@ -462,6 +449,28 @@
 			*(tmp - 1) = '-';
 			env_set("board", buf);
 		}
+
+		/* The last compatible is always the SoC compatible */
+		ret = ofnode_read_string_index(root, "compatible",
+					       compat_count - 1, &last_compat);
+		if (ret < 0) {
+			log_warning("Can't read second compatible\n");
+			return;
+		}
+
+		/* Copy the last compat (e.g. "qcom,sdm845") into buf */
+		memset(buf, 0, sizeof(buf));
+		strlcpy(buf, last_compat, sizeof(buf) - 1);
+		tmp = buf;
+
+		/* strsep() is destructive, it replaces the comma with a \0 */
+		if (!strsep(&tmp, ",")) {
+			log_warning("second compatible '%s' has no ','\n", buf);
+			return;
+		}
+
+		/* tmp now points to just the "sdm845" part of the string */
+		env_set("soc", tmp);
 	}
 
 	/* Now build the full path name */
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.env b/board/qualcomm/dragonboard410c/dragonboard410c.env
index 38399d6..ab25343 100644
--- a/board/qualcomm/dragonboard410c/dragonboard410c.env
+++ b/board/qualcomm/dragonboard410c/dragonboard410c.env
@@ -2,5 +2,5 @@
 initrd_high=0xffffffffffffffff
 fastboot=fastboot -l $fastboot_addr_r usb 0
 boot_targets=usb mmc1 mmc0 pxe
-button_cmd_0_name=vol_down
+button_cmd_0_name=Volume Down
 button_cmd_0=run fastboot
diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig
index 449d48a..d267b6e 100644
--- a/configs/dragonboard410c_defconfig
+++ b/configs/dragonboard410c_defconfig
@@ -4,7 +4,6 @@
 CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK=y
 CONFIG_ARCH_SNAPDRAGON=y
 CONFIG_TEXT_BASE=0x8f600000
-CONFIG_SYS_MALLOC_LEN=0x802000
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
 CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x8007fff0
 CONFIG_ENV_SIZE=0x2000
@@ -56,6 +55,8 @@
 CONFIG_PINCTRL_QCOM_APQ8016=y
 CONFIG_DM_PMIC=y
 CONFIG_PMIC_QCOM=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_MSM=y
 CONFIG_MSM_SERIAL=y
 CONFIG_SPMI_MSM=y
 CONFIG_USB=y
diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c
index e3bb9bd..85addfe 100644
--- a/drivers/button/button-qcom-pmic.c
+++ b/drivers/button/button-qcom-pmic.c
@@ -143,6 +143,21 @@
 
 	priv->base = base;
 
+	ret = dev_read_u32(dev, "linux,code", &priv->code);
+	if (ret == 0) {
+		/* convert key, if read OK */
+		switch (priv->code) {
+		case KEY_VOLUMEDOWN:
+			priv->code = KEY_DOWN;
+			uc_plat->label = "Volume Down";
+			break;
+		case KEY_VOLUMEUP:
+			priv->code = KEY_UP;
+			uc_plat->label = "Volume Up";
+			break;
+		}
+	}
+
 	/* Do a sanity check */
 	ret = pmic_reg_read(priv->pmic, priv->base + REG_TYPE);
 	if (ret != 0x1 && ret != 0xb) {
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
index 6a53f90..b7bd9c9 100644
--- a/drivers/clk/qcom/clock-apq8016.c
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -23,10 +23,7 @@
 #define APCS_GPLL_ENA_VOTE		(0x45000)
 #define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004)
 
-#define SDCC_BCR(n)			((n * 0x1000) + 0x41000)
-#define SDCC_CMD_RCGR(n)		(((n + 1) * 0x1000) + 0x41004)
-#define SDCC_APPS_CBCR(n)		((n * 0x1000) + 0x41018)
-#define SDCC_AHB_CBCR(n)		((n * 0x1000) + 0x4101C)
+#define SDCC_CMD_RCGR(n)		(((n) * 0x1000) + 0x42004)
 
 /* BLSP1 AHB clock (root clock for BLSP) */
 #define BLSP1_AHB_CBCR			0x1008
@@ -54,9 +51,13 @@
 };
 
 static const struct gate_clk apq8016_clks[] = {
-	GATE_CLK(GCC_PRNG_AHB_CLK,	0x45004, BIT(8)),
-	GATE_CLK(GCC_USB_HS_AHB_CLK,    0x41008, BIT(0)),
-	GATE_CLK(GCC_USB_HS_SYSTEM_CLK,	0x41004, BIT(0)),
+	GATE_CLK_POLLED(GCC_PRNG_AHB_CLK,	0x45004, BIT(8), 0x13004),
+	GATE_CLK_POLLED(GCC_SDCC1_AHB_CLK,	0x4201c, BIT(0), 0x4201c),
+	GATE_CLK_POLLED(GCC_SDCC1_APPS_CLK,	0x42018, BIT(0), 0x42018),
+	GATE_CLK_POLLED(GCC_SDCC2_AHB_CLK,	0x4301c, BIT(0), 0x4301c),
+	GATE_CLK_POLLED(GCC_SDCC2_APPS_CLK,	0x43018, BIT(0), 0x43018),
+	GATE_CLK_POLLED(GCC_USB_HS_AHB_CLK,	0x41008, BIT(0), 0x41008),
+	GATE_CLK_POLLED(GCC_USB_HS_SYSTEM_CLK,	0x41004, BIT(0), 0x41004),
 };
 
 /* SDHCI */
@@ -67,12 +68,10 @@
 	if (rate == 200000000)
 		div = 4;
 
-	clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot));
 	/* 800Mhz/div, gpll0 */
 	clk_rcg_set_rate_mnd(priv->base, SDCC_CMD_RCGR(slot), div, 0, 0,
 			     CFG_CLK_SRC_GPLL0, 8);
 	clk_enable_gpll0(priv->base, &gpll0_vote_clk);
-	clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot));
 
 	return rate;
 }
diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index 7687bbe..6b46d9d 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -74,6 +74,33 @@
 	} while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL));
 }
 
+int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id)
+{
+	if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) {
+		log_err("gcc@%#08llx: unknown clock ID %lu!\n",
+			priv->base, id);
+		return -ENOENT;
+	}
+
+	setbits_le32(priv->base + priv->data->clks[id].reg, priv->data->clks[id].en_val);
+	if (priv->data->clks[id].cbcr_reg) {
+		unsigned int count;
+		u32 val;
+
+		for (count = 0; count < 200; count++) {
+			val = readl(priv->base + priv->data->clks[id].cbcr_reg);
+			val &= BRANCH_CHECK_MASK;
+			if (val == BRANCH_ON_VAL || val == BRANCH_NOC_FSM_ON_VAL)
+				break;
+			udelay(1);
+		}
+		if (WARN(count == 200, "WARNING: Clock @ %#lx [%#010x] stuck at off\n",
+			 priv->data->clks[id].cbcr_reg, val))
+			return -EBUSY;
+	}
+	return 0;
+}
+
 #define APPS_CMD_RCGR_UPDATE BIT(0)
 
 /* Update clock command via CMD_RCGR */
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
index f43edea..1b60882 100644
--- a/drivers/clk/qcom/clock-qcom.h
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -52,13 +52,20 @@
 struct gate_clk {
 	uintptr_t reg;
 	u32 en_val;
+	uintptr_t cbcr_reg;
 	const char *name;
 };
 
+/*
+ * GATE_CLK() is deprecated: Use GATE_CLK_POLLED() instead to ensure the clock
+ * is running before we start making use of devices or registers.
+ */
 #ifdef DEBUG
-#define GATE_CLK(clk, reg, val) [clk] = { reg, val, #clk }
+#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, #clk }
+#define GATE_CLK_POLLED(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, #clk }
 #else
-#define GATE_CLK(clk, reg, val) [clk] = { reg, val, NULL }
+#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, NULL }
+#define GATE_CLK_POLLED(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, NULL }
 #endif
 
 struct qcom_reset_map {
@@ -107,19 +114,6 @@
 		      int source);
 void clk_phy_mux_enable(phys_addr_t base, uint32_t cmd_rcgr, bool enabled);
 
-static inline int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id)
-{
-	u32 val;
-	if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) {
-		log_err("gcc@%#08llx: unknown clock ID %lu!\n",
-			priv->base, id);
-		return -ENOENT;
-	}
-
-	val = readl(priv->base + priv->data->clks[id].reg);
-	writel(val | priv->data->clks[id].en_val, priv->base + priv->data->clks[id].reg);
-
-	return 0;
-}
+int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id);
 
 #endif
diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c
index 2d58ef5..07f118d 100644
--- a/drivers/power/regulator/qcom_usb_vbus_regulator.c
+++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c
@@ -15,14 +15,33 @@
 #include <power/pmic.h>
 #include <power/regulator.h>
 
-#define CMD_OTG				0x50
+enum pm8x50b_vbus {
+	PM8150B,
+	PM8550B,
+};
+
 #define OTG_EN				BIT(0)
-// The 0 bit in this register's bit field is undocumented
-#define OTG_CFG				0x56
+
 #define OTG_EN_SRC_CFG			BIT(1)
 
+struct qcom_otg_regs {
+	u32 otg_cmd;
+	u32 otg_cfg;
+};
 struct qcom_usb_vbus_priv {
 	phys_addr_t base;
+	struct qcom_otg_regs *regs;
+};
+
+static const struct qcom_otg_regs qcom_otg[] = {
+	[PM8150B] = {
+		.otg_cmd = 0x40,
+		.otg_cfg = 0x53,
+	},
+	[PM8550B] = {
+		.otg_cmd = 0x50,
+		.otg_cfg = 0x56,
+	},
 };
 
 static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev)
@@ -38,8 +57,9 @@
 
 static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev)
 {
+	const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)];
 	struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
-	int otg_en_reg = priv->base + CMD_OTG;
+	int otg_en_reg = priv->base + regs->otg_cmd;
 	int ret;
 
 	ret = pmic_reg_read(dev->parent, otg_en_reg);
@@ -53,8 +73,9 @@
 
 static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable)
 {
+	const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)];
 	struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
-	int otg_en_reg = priv->base + CMD_OTG;
+	int otg_en_reg = priv->base + regs->otg_cmd;
 	int ret;
 
 	if (enable) {
@@ -76,8 +97,9 @@
 
 static int qcom_usb_vbus_regulator_probe(struct udevice *dev)
 {
+	const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)];
 	struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
-	int otg_cfg_reg = priv->base + OTG_CFG;
+	int otg_cfg_reg = priv->base + regs->otg_cfg;
 	int ret;
 
 	/* Disable HW logic for VBUS enable */
@@ -96,7 +118,8 @@
 };
 
 static const struct udevice_id qcom_usb_vbus_regulator_ids[] = {
-	{ .compatible = "qcom,pm8150b-vbus-reg"},
+	{ .compatible = "qcom,pm8150b-vbus-reg", .data = PM8150B },
+	{ .compatible = "qcom,pm8550b-vbus-reg", .data = PM8550B },
 	{ },
 };