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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEtlGhRjxqvtBpDFXNBYMxKxlfZLYFAmg/DEUACgkQBYMxKxlf
 ZLaJ6A//awuGA5mY6mPRuk0HrSKMl+5JM7Vw//mLaZaNUl/1FnPVh/cWiiO74hRA
 OaUZqDd31Hkf9ow3of1xhyriQnw29bc8mfEWCAa4Zau2RZmIK8Ej3NP5fLg1ynsW
 Oq5VifegyuCTpBy1Dlh8FtLIZ+oK9aHe1DTg/8yKbMYJPtfWP0FlJznYyA0niQGD
 SHhm696ubPvDuozllln9ctoLjqCLQfunfCJXz+95HiXz9XSBZrm4374LcjhVm6CC
 NJmnLCDwNibwjPRBOydZ6ErjHc8CY8hi9yMd7jxtkrtyn6vldLbbNLHAplSzqXvD
 2k25NginU8u8sMePpCPIJaEx0uMdyCsf/DbFVZM7xEg/xApq47JRfiS9QqTVBDqD
 tQr7/Tr5HSF4EtcejIkcTS01OtzQszePY4b9qlSKpkRT4EnnwD66ao27Kry6MqOg
 TpXm25WLJuApZiORwlfDoOa2kdCBVbrwf1hrQyq7yZ1OwD/3ywIzrGrvuOo2d4J4
 dJPDmYxwOFXmzc8EUwGD0U65f/no90vWXsQ9jo2hrx873d+Yu6l/TvxGsI3W+92j
 Wlg2I5InIi/DcW98YjrZT5kcf50m4YIgiWVEQh0AnvpIOmtlt6PTKRr1niwSK9fo
 gwjgclB1RG9fc5lT+B7vH4jN9JwjOJcUYn5HY5knsMVNQ3H6r+4=
 =OiS4
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Tom Rini 2025-06-03 09:00:52 -06:00
commit fdc0dcbb2c
8 changed files with 129 additions and 61 deletions

View File

@ -409,52 +409,39 @@ static void configure_env(void)
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 @@ static void configure_env(void)
*(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 */

View File

@ -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

View File

@ -4,7 +4,6 @@ CONFIG_COUNTER_FREQUENCY=19200000
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_PINCONF=y
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

View File

@ -143,6 +143,21 @@ static int qcom_pwrkey_probe(struct udevice *dev)
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) {

View File

@ -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 struct vote_clk gcc_blsp1_ahb_clk = {
};
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 @@ static int apq8016_clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate)
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;
}

View File

@ -74,6 +74,33 @@ void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk)
} 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 */

View File

@ -52,13 +52,20 @@ struct freq_tbl {
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 @@ void clk_rcg_set_rate(phys_addr_t base, uint32_t cmd_rcgr, int div,
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

View File

@ -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_of_to_plat(struct udevice *dev)
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_get_enable(struct udevice *dev)
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_set_enable(struct udevice *dev, bool enable)
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 dm_regulator_ops qcom_usb_vbus_regulator_ops = {
};
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 },
{ },
};