From e51d4d23c7149c5efa532b8c406de551c928aa93 Mon Sep 17 00:00:00 2001 From: Abbarapu Venkatesh Yadav Date: Fri, 10 Oct 2025 10:42:00 +0530 Subject: qcom_defconfig: Enable meminfo command with mapping Enable meminfo command to be able to see where things are mapped. Signed-off-by: Abbarapu Venkatesh Yadav Link: https://lore.kernel.org/r/20251010051200.2313081-1-venkyada@qti.qualcomm.com Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 8d1269b4634..4c00cf91166 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -29,6 +29,8 @@ CONFIG_CMD_EEPROM=y CONFIG_SYS_I2C_EEPROM_BUS=2 CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2 CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=5 +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MEMINFO_MAP=y # CONFIG_CMD_BIND is not set CONFIG_CMD_CLK=y CONFIG_CMD_DFU=y -- cgit v1.2.3 From bf83c6036e850035d4b99870cd8e8bf01be3ff53 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sun, 5 Oct 2025 17:44:43 +0200 Subject: gpio: qcom: qcom_spmi_gpio: add compatible for pm6150l Add support for the GPIOs in the PM6150L to the new driver. Signed-off-by: Jens Reidel Reviewed-by: Neil Armstrong Reviewed-by: Casey Connolly Link: https://lore.kernel.org/r/20251005154443.71477-1-adrian@mainlining.org Signed-off-by: Casey Connolly --- drivers/gpio/qcom_spmi_gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c index 22c8072534e..69222b4df55 100644 --- a/drivers/gpio/qcom_spmi_gpio.c +++ b/drivers/gpio/qcom_spmi_gpio.c @@ -743,6 +743,7 @@ static int qcom_spmi_pmic_gpio_probe(struct udevice *dev) } static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = { + { .compatible = "qcom,pm6150l-gpio" }, { .compatible = "qcom,pm8550-gpio" }, { .compatible = "qcom,pm8550b-gpio" }, { .compatible = "qcom,pm8550ve-gpio" }, -- cgit v1.2.3 From 603b45b0f1189b3620ff3cd59b3e7df2a36bd6b2 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Fri, 3 Oct 2025 14:39:27 -0600 Subject: phy: qcom: Rework Kconfig logic around MSM8916_USB_PHY This PHY driver is required by USB_EHCI_MSM and not useful on its own. Rather than have it be a prompted option, it should (and currently is) select'd by USB_EHCI_MSM. Remove the prompt for this option and then correct the dependency chain (it must select PHY). Signed-off-by: Tom Rini Reviewed-by: Casey Connolly Link: https://lore.kernel.org/r/20251003203927.1030052-1-trini@konsulko.com Signed-off-by: Casey Connolly --- drivers/phy/qcom/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig index 61e5e2fca41..0dd69f7ffd0 100644 --- a/drivers/phy/qcom/Kconfig +++ b/drivers/phy/qcom/Kconfig @@ -1,8 +1,8 @@ config MSM8916_USB_PHY - bool "Qualcomm MSM8916 USB PHY support" - depends on PHY + bool + select PHY help - Support the USB PHY in msm8916 + Support the Qualcomm MSM8916 USB PHY This PHY is found on qualcomm dragonboard410c development board. -- cgit v1.2.3 From 0e591130256d0a44436092ac1730ced29b6a1696 Mon Sep 17 00:00:00 2001 From: David Wronek Date: Fri, 3 Oct 2025 12:01:09 +0200 Subject: clk/stub: add sdm670 rpmh clock Necessary for MMC to successfully probe all clocks. Reviewed-by: Neil Armstrong Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20251003-sdm670-v2-1-52c0fa481286@mainlining.org Signed-off-by: Casey Connolly --- drivers/clk/clk-stub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c index 5f5aca41d5b..d02107ff32a 100644 --- a/drivers/clk/clk-stub.c +++ b/drivers/clk/clk-stub.c @@ -50,6 +50,7 @@ static struct clk_ops stub_clk_ops = { static const struct udevice_id stub_clk_ids[] = { { .compatible = "qcom,rpmcc" }, + { .compatible = "qcom,sdm670-rpmh-clk" }, { .compatible = "qcom,sdm845-rpmh-clk" }, { .compatible = "qcom,sc7280-rpmh-clk" }, { .compatible = "qcom,sm8150-rpmh-clk" }, -- cgit v1.2.3 From 8111e1357e6dd1537f4bb1b00721e0356009d89f Mon Sep 17 00:00:00 2001 From: David Wronek Date: Fri, 3 Oct 2025 12:01:10 +0200 Subject: clk/qcom: sdm845: add support for sdm670 The global clock controller on SDM670 is similar to SDM845, so let's add support here. Reviewed-by: Neil Armstrong Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20251003-sdm670-v2-2-52c0fa481286@mainlining.org Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-sdm845.c | 127 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c index 5c8702ef2fe..c9a057cf6f9 100644 --- a/drivers/clk/qcom/clock-sdm845.c +++ b/drivers/clk/qcom/clock-sdm845.c @@ -23,6 +23,7 @@ #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf018 #define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf030 #define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf05c +#define SDCC1_APPS_CLK_CMD_RCGR 0x26028 #define SDCC2_APPS_CLK_CMD_RCGR 0x1400c static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { @@ -44,6 +45,18 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { { } }; +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_EVEN, 5, 1, 3), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 1, 2), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(192000000, CFG_CLK_SRC_GPLL6, 2, 0, 0), + F(384000000, CFG_CLK_SRC_GPLL6, 1, 0, 0), + { } +}; + static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), @@ -55,6 +68,22 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { { } }; +static ulong sdm670_clk_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + switch (clk->id) { + case GCC_SDCC1_APPS_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; + } +} + static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -76,6 +105,54 @@ static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate) } } +static const struct gate_clk sdm670_clks[] = { + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x0502c, 0x00000001), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, 0x00000400), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, 0x00000800), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, 0x00001000), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, 0x00002000), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, 0x00004000), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, 0x00008000), + GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x5200c, 0x00010000), + GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x5200c, 0x00020000), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, 0x00400000), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, 0x00800000), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, 0x02000000), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, 0x04000000), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, 0x08000000), + GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x5200c, 0x10000000), + GATE_CLK(GCC_QUPV3_WRAP1_S7_CLK, 0x5200c, 0x20000000), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, 0x00000040), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, 0x00000080), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, 0x00100000), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, 0x00200000), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x26008, 0x00000001), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x26004, 0x00000001), + GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x2600c, 0x00000001), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, 0x00000001), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, 0x00000001), + GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, 0x00000001), + GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, 0x00000001), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77010, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x7700c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77058, 0x00000001), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7708c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x77018, 0x00000001), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77014, 0x00000001), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77054, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f00c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f014, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f010, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c008, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f04c, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f050, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f054, 0x00000001), + GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001), +}; + static const struct gate_clk sdm845_clks[] = { GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001), GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x82020, 0x00000001), @@ -140,6 +217,28 @@ static const struct gate_clk sdm845_clks[] = { GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001), }; +static int sdm670_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + debug("%s: clk %s\n", __func__, sdm670_clks[clk->id].name); + + switch (clk->id) { + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB_PHY_CFG_AHB2PHY_CLK); + /* These numbers are just pulled from the frequency tables in the Linux driver */ + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + (4.5 * 2) - 1, 0, 0, 1 << 8, 8); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, + 1, 0, 0, 0, 8); + clk_rcg_set_rate_mnd(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, + 1, 0, 0, 0, 8); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + static int sdm845_clk_enable(struct clk *clk) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -188,6 +287,17 @@ static const struct qcom_reset_map sdm845_gcc_resets[] = { [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, }; +static const struct qcom_power_map sdm670_gdscs[] = { + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, + [HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC] = { 0x7d030 }, + [HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC] = { 0x7d034 }, + [HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC] = { 0x7d038 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = { 0x7d040 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = { 0x7d048 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = { 0x7d044 }, +}; + static const struct qcom_power_map sdm845_gdscs[] = { [PCIE_0_GDSC] = { 0x6b004 }, [PCIE_1_GDSC] = { 0x8d004 }, @@ -292,6 +402,19 @@ static const char *const sdm845_rcg_names[] = { "GCC_UFS_PHY_PHY_AUX", }; +static struct msm_clk_data sdm670_clk_data = { + /* Snapdragon 670 can function without its own exclusive resets. */ + .resets = sdm845_gcc_resets, + .num_resets = ARRAY_SIZE(sdm845_gcc_resets), + .clks = sdm670_clks, + .num_clks = ARRAY_SIZE(sdm670_clks), + .power_domains = sdm670_gdscs, + .num_power_domains = ARRAY_SIZE(sdm670_gdscs), + + .enable = sdm670_clk_enable, + .set_rate = sdm670_clk_set_rate, +}; + static struct msm_clk_data sdm845_clk_data = { .resets = sdm845_gcc_resets, .num_resets = ARRAY_SIZE(sdm845_gcc_resets), @@ -310,6 +433,10 @@ static struct msm_clk_data sdm845_clk_data = { }; static const struct udevice_id gcc_sdm845_of_match[] = { + { + .compatible = "qcom,gcc-sdm670", + .data = (ulong)&sdm670_clk_data, + }, { .compatible = "qcom,gcc-sdm845", .data = (ulong)&sdm845_clk_data, -- cgit v1.2.3 From f977cee37252c6f1d215f76c2905cd8823b03fdb Mon Sep 17 00:00:00 2001 From: David Wronek Date: Fri, 3 Oct 2025 12:01:11 +0200 Subject: pinctrl: qcom: add sdm670 pinctrl driver Add a pinctrl driver for the TLMM block found in the SDM670 SoC. Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20251003-sdm670-v2-3-52c0fa481286@mainlining.org Signed-off-by: Casey Connolly --- drivers/pinctrl/qcom/Kconfig | 7 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-sdm670.c | 247 ++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-sdm670.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 21f81b66099..45f900e9383 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -68,6 +68,13 @@ config PINCTRL_QCOM_SC7280 help Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC, +config PINCTRL_QCOM_SDM670 + bool "Qualcomm SDM670 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SDM670 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SDM660 bool "Qualcomm SDM630/660 Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 6cb53838e71..f43868363d6 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.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 +obj-$(CONFIG_PINCTRL_QCOM_SDM670) += pinctrl-sdm670.o obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c new file mode 100644 index 00000000000..830fe7d826f --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm SDM670 pinctrl + * + * (C) Copyright 2025 David Wronek + */ + +#include +#include "pinctrl-qcom.h" + +#define NORTH 0x00500000 +#define SOUTH 0x00900000 +#define WEST 0x00100000 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function sdm670_pinctrl_functions[] = { + { "gpio", 0 }, + { "blsp_uart2", 3 }, /* gpio 4 and 5, used for debug uart */ +}; + +static const unsigned int sdm670_pin_offsets[] = { + [0] = SOUTH, + [1] = SOUTH, + [2] = SOUTH, + [3] = SOUTH, + [4] = NORTH, + [5] = NORTH, + [6] = NORTH, + [7] = NORTH, + [8] = WEST, + [9] = WEST, + [10] = NORTH, + [11] = NORTH, + [12] = SOUTH, + [13] = WEST, + [14] = WEST, + [15] = WEST, + [16] = WEST, + [17] = WEST, + [18] = WEST, + [19] = WEST, + [20] = WEST, + [21] = WEST, + [22] = WEST, + [23] = WEST, + [24] = WEST, + [25] = WEST, + [26] = WEST, + [27] = WEST, + [28] = WEST, + [29] = WEST, + [30] = WEST, + [31] = WEST, + [32] = WEST, + [33] = WEST, + [34] = WEST, + [35] = NORTH, + [36] = NORTH, + [37] = NORTH, + [38] = NORTH, + [39] = NORTH, + [40] = NORTH, + [41] = SOUTH, + [42] = SOUTH, + [43] = SOUTH, + [44] = SOUTH, + [45] = SOUTH, + [46] = SOUTH, + [47] = SOUTH, + [48] = SOUTH, + [49] = NORTH, + [50] = NORTH, + [51] = NORTH, + [52] = NORTH, + [53] = NORTH, + [54] = NORTH, + [55] = NORTH, + [56] = NORTH, + [57] = NORTH, + [65] = NORTH, + [66] = NORTH, + [67] = NORTH, + [68] = NORTH, + [75] = NORTH, + [76] = NORTH, + [77] = NORTH, + [78] = NORTH, + [79] = NORTH, + [80] = NORTH, + [81] = NORTH, + [82] = NORTH, + [83] = NORTH, + [84] = NORTH, + [85] = SOUTH, + [86] = SOUTH, + [87] = SOUTH, + [88] = SOUTH, + [89] = SOUTH, + [90] = SOUTH, + [91] = SOUTH, + [92] = SOUTH, + [93] = SOUTH, + [94] = SOUTH, + [95] = SOUTH, + [96] = SOUTH, + [97] = WEST, + [98] = WEST, + [99] = NORTH, + [100] = WEST, + [101] = WEST, + [102] = WEST, + [103] = WEST, + [105] = NORTH, + [106] = NORTH, + [107] = NORTH, + [108] = NORTH, + [109] = NORTH, + [110] = NORTH, + [111] = NORTH, + [112] = NORTH, + [113] = NORTH, + [114] = WEST, + [115] = WEST, + [116] = SOUTH, + [117] = NORTH, + [118] = NORTH, + [119] = NORTH, + [120] = NORTH, + [121] = NORTH, + [122] = NORTH, + [123] = NORTH, + [124] = NORTH, + [125] = NORTH, + [126] = NORTH, + [127] = WEST, + [128] = WEST, + [129] = WEST, + [130] = WEST, + [131] = WEST, + [132] = WEST, + [133] = NORTH, + [134] = NORTH, + [135] = WEST, + [136] = WEST, + [137] = WEST, + [138] = WEST, + [139] = WEST, + [140] = WEST, + [141] = WEST, + [142] = WEST, + [143] = WEST, + [144] = SOUTH, + [145] = SOUTH, + [146] = WEST, + [147] = WEST, + [148] = WEST, + [149] = WEST, +}; + +#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, offset) \ +{ \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ +} + +static const struct msm_special_pin_data sdm670_special_pins_data[] = { + UFS_RESET("ufs_reset", 0x99d000), + SDC_QDSD_PINGROUP("sdc1_rclk", NORTH + 0x99000, 15, 0), + SDC_QDSD_PINGROUP("sdc1_clk", NORTH + 0x99000, 13, 6), + SDC_QDSD_PINGROUP("sdc1_cmd", NORTH + 0x99000, 11, 3), + SDC_QDSD_PINGROUP("sdc1_data", NORTH + 0x99000, 9, 0), + SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0x9a000, 14, 6), + SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0x9a000, 11, 3), + SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0x9a000, 9, 0), +}; + +static const char *sdm670_get_function_name(struct udevice *dev, unsigned int selector) +{ + return sdm670_pinctrl_functions[selector].name; +} + +static const char *sdm670_get_pin_name(struct udevice *dev, unsigned int selector) +{ + if (selector >= 150 && selector <= 157) + snprintf(pin_name, MAX_PIN_NAME_LEN, + sdm670_special_pins_data[selector - 150].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sdm670_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector) +{ + if (selector >= 0 && selector < ARRAY_SIZE(sdm670_pinctrl_functions)) + return sdm670_pinctrl_functions[selector].val; + return -EINVAL; +} + +struct msm_pinctrl_data sdm670_data = { + .pin_data = { + .pin_offsets = sdm670_pin_offsets, + .pin_count = ARRAY_SIZE(sdm670_pin_offsets) + ARRAY_SIZE(sdm670_special_pins_data), + .special_pins_start = 150, + .special_pins_data = sdm670_special_pins_data, + }, + .functions_count = ARRAY_SIZE(sdm670_pinctrl_functions), + .get_function_name = sdm670_get_function_name, + .get_function_mux = sdm670_get_function_mux, + .get_pin_name = sdm670_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { + .compatible = "qcom,sdm670-tlmm", + .data = (ulong)&sdm670_data + }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_ssdm670) = { + .name = "pinctrl_sdm670", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; -- cgit v1.2.3 From 4cebdcae3539c419eabca77b1102d7a9fec3a913 Mon Sep 17 00:00:00 2001 From: David Wronek Date: Fri, 3 Oct 2025 12:01:12 +0200 Subject: qcom_defconfig: enable pinctrl for sdm670 Enable the SDM670 pinctrl driver. Reviewed-by: Neil Armstrong Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20251003-sdm670-v2-4-52c0fa481286@mainlining.org Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 4c00cf91166..eb201228c40 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -112,6 +112,7 @@ 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_SDM845=y CONFIG_PINCTRL_QCOM_SM6115=y CONFIG_PINCTRL_QCOM_SM8150=y -- cgit v1.2.3 From 731dc5eb9536dca4841c75b25825af29fa122238 Mon Sep 17 00:00:00 2001 From: David Wronek Date: Fri, 3 Oct 2025 12:01:13 +0200 Subject: gpio: qcom_spmi: add pm660l This is used for the volume keys on some SDM670 devices. Reviewed-by: Neil Armstrong Signed-off-by: David Wronek Link: https://lore.kernel.org/r/20251003-sdm670-v2-5-52c0fa481286@mainlining.org Signed-off-by: Casey Connolly --- drivers/gpio/qcom_spmi_gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c index 69222b4df55..3f7c5703e22 100644 --- a/drivers/gpio/qcom_spmi_gpio.c +++ b/drivers/gpio/qcom_spmi_gpio.c @@ -744,6 +744,7 @@ static int qcom_spmi_pmic_gpio_probe(struct udevice *dev) static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = { { .compatible = "qcom,pm6150l-gpio" }, + { .compatible = "qcom,pm660l-gpio" }, { .compatible = "qcom,pm8550-gpio" }, { .compatible = "qcom,pm8550b-gpio" }, { .compatible = "qcom,pm8550ve-gpio" }, -- cgit v1.2.3 From e4b35d364e8639160d3ab2d73b3c53cc4ab69880 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 24 Sep 2025 13:30:07 +0200 Subject: pinctrl: qcom: sc7280: Fix offset of UFS_RESET There's no WEST, SOUTH or NORTH in sc7280 pinctrl. Fix the offset of the ufs_reset pin. Fixes: 51ec7fdb64b ("pinctrl: qcom: add sc7280 pinctrl driver") Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250924-2025-10-misc-v1-1-7e75842ca714@fairphone.com Signed-off-by: Casey Connolly --- drivers/pinctrl/qcom/pinctrl-sc7280.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c index fe87947fbbf..d62b2cc6fb6 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c @@ -10,10 +10,6 @@ #include "pinctrl-qcom.h" -#define WEST 0x00000000 -#define SOUTH 0x00400000 -#define NORTH 0x00800000 - #define MAX_PIN_NAME_LEN 32 static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); @@ -47,7 +43,7 @@ static const struct pinctrl_function msm_pinctrl_functions[] = { } static const struct msm_special_pin_data sc7280_special_pins_data[] = { - [0] = UFS_RESET("ufs_reset", SOUTH + 0xbe000), + [0] = UFS_RESET("ufs_reset", 0xbe000), [1] = SDC_PINGROUP("sdc1_rclk", 0xb3004, 0, 6), [2] = SDC_PINGROUP("sdc1_clk", 0xb3000, 13, 6), [3] = SDC_PINGROUP("sdc1_cmd", 0xb3000, 11, 3), -- cgit v1.2.3 From 43a2fc67d3830fd2bc9e0736605b2d324eaa4f3c Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 24 Sep 2025 13:30:08 +0200 Subject: clk/qcom: sm8250: Remove unused defines Clean up some defines which are not used in the driver. Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250924-2025-10-misc-v1-2-7e75842ca714@fairphone.com Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-sm8250.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c index cc481258d22..37268c4eaf5 100644 --- a/drivers/clk/qcom/clock-sm8250.c +++ b/drivers/clk/qcom/clock-sm8250.c @@ -18,14 +18,9 @@ #define GCC_SE12_UART_RCG_REG 0x184D0 #define GCC_SDCC2_APPS_CLK_SRC_REG 0x1400c -#define APCS_GPLL0_ENA_VOTE 0x79000 #define APCS_GPLL9_STATUS 0x1c000 #define APCS_GPLLX_ENA_REG 0x52018 -#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020 -#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038 -#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf064 - static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = { F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), -- cgit v1.2.3 From beaabce9cc27a14ebc5c6cb9e498e3e4dc17d062 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 24 Sep 2025 13:30:09 +0200 Subject: serial: msm-geni: Update kconfig name for DEBUG_UART_MSM_GENI The previous description "Qualcomm snapdragon" barely tells the user anything, update the name so that it's clear which configs the user can choose between, namely the older QUP driver, or the newer GENI driver. Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250924-2025-10-misc-v1-3-7e75842ca714@fairphone.com Signed-off-by: Casey Connolly --- drivers/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bc05d2f1508..650612fd17f 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -328,7 +328,7 @@ config DEBUG_UART_MSM be available until the real driver-model serial is running. config DEBUG_UART_MSM_GENI - bool "Qualcomm snapdragon" + bool "Qualcomm GENI UART debug" depends on ARCH_SNAPDRAGON help Select this to enable a debug UART using the serial_msm driver. You -- cgit v1.2.3 From 759646df3aed6a133111bfd41f206b05ac56cf6d Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 24 Sep 2025 13:30:10 +0200 Subject: doc: board/qualcomm: Clean up debug options for QUP UART CONFIG_BAUDRATE is not relevant for the QUP driver, and neither is CONFIG_DEBUG_UART_SKIP_INIT so remove them from the doc. Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250924-2025-10-misc-v1-4-7e75842ca714@fairphone.com Signed-off-by: Casey Connolly --- doc/board/qualcomm/debugging.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/board/qualcomm/debugging.rst b/doc/board/qualcomm/debugging.rst index c3289c9e4e3..42821f6546c 100644 --- a/doc/board/qualcomm/debugging.rst +++ b/doc/board/qualcomm/debugging.rst @@ -42,7 +42,6 @@ Older boards (db410c and db820c) Open ``configs/dragonboard_defconfig`` - CONFIG_BAUDRATE=115200 CONFIG_DEBUG_UART=y CONFIG_DEBUG_UART_ANNOUNCE=y # db410c - 0x78b0000 @@ -50,7 +49,6 @@ Open ``configs/dragonboard_defconfig`` CONFIG_DEBUG_UART_BASE=0x75b0000 CONFIG_DEBUG_UART_MSM=y CONFIG_DEBUG_UART_CLOCK=7372800 - #CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_LOG=y CONFIG_HEXDUMP=y -- cgit v1.2.3 From 202f5975c2c852dbf658ffffa00b00752048de85 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 24 Sep 2025 13:30:11 +0200 Subject: board/qualcomm: add debug config fragment for MSM8953 Add a fragment similar to others to enable earlycon. Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250924-2025-10-misc-v1-5-7e75842ca714@fairphone.com Signed-off-by: Casey Connolly --- board/qualcomm/debug-msm8953.config | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 board/qualcomm/debug-msm8953.config diff --git a/board/qualcomm/debug-msm8953.config b/board/qualcomm/debug-msm8953.config new file mode 100644 index 00000000000..1ccd70d0d3f --- /dev/null +++ b/board/qualcomm/debug-msm8953.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x78af000 +CONFIG_DEBUG_UART_MSM=y +CONFIG_DEBUG_UART_CLOCK=7372800 -- cgit v1.2.3 From 1cab8d1e22d992ee59a066b25d12baff4e1446ea Mon Sep 17 00:00:00 2001 From: Paul Sajna Date: Tue, 23 Sep 2025 19:05:19 -0700 Subject: qcom_defconfig: enable watchdog command CONFIG_WDT and CONFIG_WDT_QCOM were previously added in https://source.denx.de/u-boot/u-boot/-/commit/530764de9fc8539cd2354501e9c42804bc4c4dac U-Boot and Linux pet the watchdog by default, but it's helpful to also have the command to control the watchdog, (CONFIG_CMD_WDT) so it can be manually disabled by the user, for example, if the kernel is expected to stall during debugging with kgdb. Signed-off-by: Paul Sajna Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250923-qcom_config_enable_cmd_wdt-v1-1-70cccf9f01e3@postmarketos.org Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index eb201228c40..87dad8876f0 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -46,6 +46,7 @@ CONFIG_CMD_EFIDEBUG=y CONFIG_CMD_RNG=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_LOG=y +CONFIG_CMD_WDT=y CONFIG_OF_LIVE=y CONFIG_OF_UPSTREAM_BUILD_VENDOR=y CONFIG_ENV_USE_DEFAULT_ENV_TEXT_FILE=y -- cgit v1.2.3 From 4bae5827928c3f731c34e36589061f3d2f9c1159 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:34 +0200 Subject: clk/qcom: Add SM6350 clock driver Add Clock driver for the GCC block found in the SM6350 SoC. Reviewed-by: Casey Connolly Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clock-sm6350.c | 193 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 drivers/clk/qcom/clock-sm6350.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 34e41461e72..347d16de3db 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -103,6 +103,14 @@ config CLK_QCOM_SM6115 on the Snapdragon SM6115 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_SM6350 + bool "Qualcomm SM6350 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon SM6350 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_SM8150 bool "Qualcomm SM8150 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index b3d95b0faa3..a85c77ad1e7 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o +obj-$(CONFIG_CLK_QCOM_SM6350) += clock-sm6350.o obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o diff --git a/drivers/clk/qcom/clock-sm6350.c b/drivers/clk/qcom/clock-sm6350.c new file mode 100644 index 00000000000..ee6653848c7 --- /dev/null +++ b/drivers/clk/qcom/clock-sm6350.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm sm6350 + * + * (C) Copyright 2024 Linaro Ltd. + * (C) Copyright 2025 Luca Weiss + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clock-qcom.h" + +#undef CFG_CLK_SRC_GPLL0_ODD +#define CFG_CLK_SRC_GPLL0_ODD (2 << 8) +#define CFG_CLK_SRC_GPLL6_EVEN (2 << 8) + +#define GCC_SE12_UART_RCG_REG 0x223a8 +#define GCC_SDCC2_APPS_CLK_SRC_REG 0x2000c + +#define APCS_GPLL7_STATUS 0x7000 +#define APCS_GPLLX_ENA_REG 0x52010 + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s3_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL6_EVEN, 3, 0, 0), + {} +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_ODD, 8, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_ODD, 4, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_ODD, 2, 0, 0), + F(202000000, CFG_CLK_SRC_GPLL7, 4, 0, 0), + {} +}; + +static struct pll_vote_clk gpll7_vote_clk = { + .status = APCS_GPLL7_STATUS, + .status_bit = BIT(31), + .ena_vote = APCS_GPLLX_ENA_REG, + .vote_bit = BIT(7), +}; + +static ulong sm6350_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", __func__, + priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_QUPV3_WRAP1_S3_CLK: /*UART9*/ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap1_s3_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, GCC_SE12_UART_RCG_REG, + freq->pre_div, freq->m, freq->n, freq->src, + 16); + + return freq->freq; + case GCC_SDCC2_APPS_CLK: + /* Enable GPLL7 so that we can point SDCC2_APPS_CLK_SRC at it */ + clk_enable_gpll0(priv->base, &gpll7_vote_clk); + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + WARN(freq->src != CFG_CLK_SRC_GPLL7, + "SDCC2_APPS_CLK_SRC not set to GPLL7, requested rate %lu\n", + rate); + clk_rcg_set_rate_mnd(priv->base, GCC_SDCC2_APPS_CLK_SRC_REG, + freq->pre_div, freq->m, freq->n, + CFG_CLK_SRC_GPLL7, 8); + + return rate; + default: + return 0; + } +} + +static const struct gate_clk sm6350_clks[] = { + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x3e014, 0x00000001), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x3e010, 0x00000001), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1101c, 0x00000001), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x52000, 0x00800000), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x52000, 0x00040000), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x52000, 0x00080000), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x20008, 0x00000001), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x20004, 0x00000001), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x3a00c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x3a034, 0x00000001), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x3a0a4, 0x00000001), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x3a0ac, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x3a014, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x3a018, 0x00000001), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x3a010, 0x00000001), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x3a09c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1a00c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1a018, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1a014, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c010, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1a050, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1a054, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x1a058, 0x00000001), +}; + +static int sm6350_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %s\n", __func__, sm6350_clks[clk->id].name); + + switch (clk->id) { + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map sm6350_gcc_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = { 0x1d000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x1e000 }, + [GCC_SDCC1_BCR] = { 0x4b000 }, + [GCC_SDCC2_BCR] = { 0x20000 }, + [GCC_UFS_PHY_BCR] = { 0x3a000 }, + [GCC_USB30_PRIM_BCR] = { 0x1a000 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x1c000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x1c008 }, +}; + +static const struct qcom_power_map sm6350_gdscs[] = { + [USB30_PRIM_GDSC] = { 0x1a004 }, + [UFS_PHY_GDSC] = { 0x3a004 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = { 0xb7040 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = { 0xb7044 }, +}; + +static struct msm_clk_data sm6350_gcc_data = { + .resets = sm6350_gcc_resets, + .num_resets = ARRAY_SIZE(sm6350_gcc_resets), + .clks = sm6350_clks, + .num_clks = ARRAY_SIZE(sm6350_clks), + .power_domains = sm6350_gdscs, + .num_power_domains = ARRAY_SIZE(sm6350_gdscs), + + .enable = sm6350_enable, + .set_rate = sm6350_set_rate, +}; + +static const struct udevice_id gcc_sm6350_of_match[] = { + { + .compatible = "qcom,gcc-sm6350", + .data = (ulong)&sm6350_gcc_data, + }, + {} +}; + +U_BOOT_DRIVER(gcc_sm6350) = { + .name = "gcc_sm6350", + .id = UCLASS_NOP, + .of_match = gcc_sm6350_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit v1.2.3 From 4ca964ac8c2f006d1f950962c50868cd43467ddc Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:35 +0200 Subject: clk/stub: add sm6350-rpmh clock Stub the RPMh clock controller on SM6350. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- drivers/clk/clk-stub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c index d02107ff32a..14a7b9948e6 100644 --- a/drivers/clk/clk-stub.c +++ b/drivers/clk/clk-stub.c @@ -53,6 +53,7 @@ static const struct udevice_id stub_clk_ids[] = { { .compatible = "qcom,sdm670-rpmh-clk" }, { .compatible = "qcom,sdm845-rpmh-clk" }, { .compatible = "qcom,sc7280-rpmh-clk" }, + { .compatible = "qcom,sm6350-rpmh-clk" }, { .compatible = "qcom,sm8150-rpmh-clk" }, { .compatible = "qcom,sm8250-rpmh-clk" }, { .compatible = "qcom,sm8550-rpmh-clk" }, -- cgit v1.2.3 From 5af87d808841bfa48242deae4d86b7858d36479b Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:36 +0200 Subject: drivers: pinctrl: Add Qualcomm SM6350 TLMM driver Add support for TLMM pin controller block (Top Level Mode Multiplexer) on SM6350 SoC, with support for special pins. Correct pin configuration is required for working debug UART and eMMC/SD cards. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- drivers/pinctrl/qcom/Kconfig | 7 +++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-sm6350.c | 104 ++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-sm6350.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 45f900e9383..1f5616f01cd 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -96,6 +96,13 @@ config PINCTRL_QCOM_SM6115 Say Y here to enable support for pinctrl on the Snapdragon SM6115 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_SM6350 + bool "Qualcomm SM6350 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM6350 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SM8150 bool "Qualcomm SM8150 Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index f43868363d6..df55d00f334 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_QCOM_SDM660) += pinctrl-sdm660.o obj-$(CONFIG_PINCTRL_QCOM_SDM670) += pinctrl-sdm670.o obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o +obj-$(CONFIG_PINCTRL_QCOM_SM6350) += pinctrl-sm6350.o obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c new file mode 100644 index 00000000000..1cbed77b55f --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm sm6350 pinctrl + * + * (C) Copyright 2024 Linaro Ltd. + * (C) Copyright 2025 Luca Weiss + * + */ + +#include + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + {"qup13_f2", 1}, + {"gpio", 0}, +}; + +#define SDC_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, offset) \ + { \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data sm6350_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", 0xae000), + [1] = SDC_PINGROUP("sdc1_rclk", 0xa1000, 15, 0), + [2] = SDC_PINGROUP("sdc1_clk", 0xa0000, 13, 6), + [3] = SDC_PINGROUP("sdc1_cmd", 0xa0000, 11, 3), + [4] = SDC_PINGROUP("sdc1_data", 0xa0000, 9, 0), + [5] = SDC_PINGROUP("sdc2_clk", 0xa2000, 14, 6), + [6] = SDC_PINGROUP("sdc2_cmd", 0xa2000, 11, 3), + [7] = SDC_PINGROUP("sdc2_data", 0xa2000, 9, 0), +}; + +static const char *sm6350_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm6350_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 156 && selector <= 163) + snprintf(pin_name, MAX_PIN_NAME_LEN, + sm6350_special_pins_data[selector - 156].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sm6350_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm6350_data = { + .pin_data = { + .pin_count = 164, + .special_pins_start = 156, + .special_pins_data = sm6350_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm6350_get_function_name, + .get_function_mux = sm6350_get_function_mux, + .get_pin_name = sm6350_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm6350-tlmm", .data = (ulong)&sm6350_data }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm6350) = { + .name = "pinctrl_sm6350", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; -- cgit v1.2.3 From 11003e47800f572c4506d6bd1e7c049b2f90fd16 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:37 +0200 Subject: iommu: qcom-smmu: Add qcom,sm6350-smmu-500 compatible This SoC doesn't have the generic compatible. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- drivers/iommu/qcom-hyp-smmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c index 2e51ce4f242..161e0b60091 100644 --- a/drivers/iommu/qcom-hyp-smmu.c +++ b/drivers/iommu/qcom-hyp-smmu.c @@ -388,8 +388,9 @@ static struct iommu_ops qcom_smmu_ops = { }; static const struct udevice_id qcom_smmu500_ids[] = { - { .compatible = "qcom,sdm845-smmu-500" }, { .compatible = "qcom,sc7280-smmu-500" }, + { .compatible = "qcom,sdm845-smmu-500" }, + { .compatible = "qcom,sm6350-smmu-500" }, { .compatible = "qcom,smmu-500", }, { /* sentinel */ } }; -- cgit v1.2.3 From a206bd063b828362457e9cf87332e7052eda7c44 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:38 +0200 Subject: phy: qcom: Add SM6350 to QMP UFS PHY driver The UFS on SM6350 can reuse the SDM845 configuration, just like in Linux. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- drivers/phy/qcom/phy-qcom-qmp-ufs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c index f3c606847fb..1c790be2e48 100644 --- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -1593,6 +1593,7 @@ static struct phy_ops qmp_ufs_ops = { static const struct udevice_id qmp_ufs_ids[] = { { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg, }, { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, + { .compatible = "qcom,sm6350-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = (ulong)&sm8150_ufsphy_cfg }, { .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg }, { .compatible = "qcom,qcs8300-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg }, -- cgit v1.2.3 From a6b78ac5d0a6f0f6d072dc9f3af3b6659aee47e9 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:39 +0200 Subject: regulator: qcom-rpmh-regulator: add support for pm6150l regulators Add the pm6150l regulator data found on the Qualcomm SM6350 platform. The tables are imported from the Linux driver. The SMPS regulators were not added now. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- drivers/power/regulator/qcom-rpmh-regulator.c | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index 954deca5ed7..06466142560 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -456,6 +456,16 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), }; +static const struct rpmh_vreg_hw_data pmic5_nldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000), + .n_voltages = 124, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), +}; + static const struct rpmh_vreg_hw_data pmic5_nldo515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, @@ -493,6 +503,23 @@ static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = { .supply_name = _supply_name, \ } +static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { + /* smps1 - smps8 are not added to u-boot yet */ + RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + {} +}; + static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), {} @@ -705,6 +732,10 @@ static int rpmh_regulators_bind(struct udevice *dev) } static const struct udevice_id rpmh_regulator_ids[] = { + { + .compatible = "qcom,pm6150l-rpmh-regulators", + .data = (ulong)pm6150l_vreg_data, + }, { .compatible = "qcom,pm8150-rpmh-regulators", .data = (ulong)pm8150_vreg_data, -- cgit v1.2.3 From 8f12776f1bfcb8f97afe1d0b8c754ccd5814b2b0 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:40 +0200 Subject: gpio: qcom: Support GPIOs on PM6350 PMIC The GPIOs on PM6350 work fine using the qcom_spmi_gpio driver and enables the use of the Volume Up button Fairphone 4 smartphone. Signed-off-by: Luca Weiss --- drivers/gpio/qcom_spmi_gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c index 3f7c5703e22..5ba65fe4d4d 100644 --- a/drivers/gpio/qcom_spmi_gpio.c +++ b/drivers/gpio/qcom_spmi_gpio.c @@ -744,6 +744,7 @@ static int qcom_spmi_pmic_gpio_probe(struct udevice *dev) static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = { { .compatible = "qcom,pm6150l-gpio" }, + { .compatible = "qcom,pm6350-gpio" }, { .compatible = "qcom,pm660l-gpio" }, { .compatible = "qcom,pm8550-gpio" }, { .compatible = "qcom,pm8550b-gpio" }, -- cgit v1.2.3 From 9049b05a6e726fb2692bcf588b4856137cfcbf07 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:41 +0200 Subject: qcom_defconfig: Enable SM6350 clock and pinctrl drivers Enable the drivers so that SM6350 devices can boot with qcom_defconfig. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- configs/qcom_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 87dad8876f0..9c2855a3d2f 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -63,6 +63,7 @@ CONFIG_CLK_QCOM_QCS8300=y CONFIG_CLK_QCOM_SA8775P=y CONFIG_CLK_QCOM_SDM845=y CONFIG_CLK_QCOM_SM6115=y +CONFIG_CLK_QCOM_SM6350=y CONFIG_CLK_QCOM_SM8150=y CONFIG_CLK_QCOM_SM8250=y CONFIG_CLK_QCOM_SM8550=y @@ -116,6 +117,7 @@ CONFIG_PINCTRL_QCOM_SC7280=y CONFIG_PINCTRL_QCOM_SDM670=y CONFIG_PINCTRL_QCOM_SDM845=y CONFIG_PINCTRL_QCOM_SM6115=y +CONFIG_PINCTRL_QCOM_SM6350=y CONFIG_PINCTRL_QCOM_SM8150=y CONFIG_PINCTRL_QCOM_SM8250=y CONFIG_PINCTRL_QCOM_SM8550=y -- cgit v1.2.3 From efbdf3dbb06b9230fcbfd514b1386cd144809e2a Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:47:42 +0200 Subject: board/qualcomm: add debug config fragment for SM6350 Add a fragment similar to others to enable earlycon. Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss --- board/qualcomm/debug-sm6350.config | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 board/qualcomm/debug-sm6350.config diff --git a/board/qualcomm/debug-sm6350.config b/board/qualcomm/debug-sm6350.config new file mode 100644 index 00000000000..1379ddeac93 --- /dev/null +++ b/board/qualcomm/debug-sm6350.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x98c000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 -- cgit v1.2.3 From dcc5a60745c01caf0a5a0a38bae66e0862ef523b Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 17 Sep 2025 14:52:22 +0200 Subject: gpio: qcom: Support GPIOs on PM7325 PMIC The GPIOs on PM7325 work fine using the qcom_spmi_gpio driver and enables the use of the Volume Up button Fairphone 5 smartphone. Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250917-spmi-gpio-pm7325-v1-1-6b75c2c62d8b@fairphone.com Signed-off-by: Casey Connolly --- drivers/gpio/qcom_spmi_gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c index 5ba65fe4d4d..1a7c7c48dfc 100644 --- a/drivers/gpio/qcom_spmi_gpio.c +++ b/drivers/gpio/qcom_spmi_gpio.c @@ -746,6 +746,7 @@ static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = { { .compatible = "qcom,pm6150l-gpio" }, { .compatible = "qcom,pm6350-gpio" }, { .compatible = "qcom,pm660l-gpio" }, + { .compatible = "qcom,pm7325-gpio" }, { .compatible = "qcom,pm8550-gpio" }, { .compatible = "qcom,pm8550b-gpio" }, { .compatible = "qcom,pm8550ve-gpio" }, -- cgit v1.2.3 From c2938270813be8de81bd06132b2bbafb8f41c979 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sun, 14 Sep 2025 17:56:20 +0300 Subject: qcom_defconfig: Enable pinctrl driver for SDM630/660 Pin controller driver for SDM630/636/660 SoCs was added in b4420a0c9ed ("drivers: pinctrl: Add Qualcomm SDM630/660 TLMM driver"), but not enabled in qcom_defconfig. Correct that omission. Signed-off-by: Alexey Minnekhanov Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250914145620.1962735-1-alexeymin@minlexx.ru Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 9c2855a3d2f..5c4152cd19b 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -114,6 +114,7 @@ CONFIG_PINCTRL_QCOM_QCM2290=y CONFIG_PINCTRL_QCOM_QCS404=y CONFIG_PINCTRL_QCOM_SA8775P=y CONFIG_PINCTRL_QCOM_SC7280=y +CONFIG_PINCTRL_QCOM_SDM660=y CONFIG_PINCTRL_QCOM_SDM670=y CONFIG_PINCTRL_QCOM_SDM845=y CONFIG_PINCTRL_QCOM_SM6115=y -- cgit v1.2.3 From 4e26c1e2fa6ad6c8ea6353d59734fb805a9eeaca Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Sep 2025 13:31:21 +0200 Subject: board: dragonboard410c: Drop now unneeded bootph-all for console This is applied for all devices upstream in Linux now (when using the console-specific pinctrl templates). Signed-off-by: Stephan Gerhold Tested-by: Alexey Minnekhanov Acked-by: Sumit Garg Link: https://lore.kernel.org/r/20250908-db410c-autoboot-fixes-v2-1-316ed98e0143@linaro.org Signed-off-by: Casey Connolly --- arch/arm/dts/apq8016-sbc-u-boot.dtsi | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/arm/dts/apq8016-sbc-u-boot.dtsi b/arch/arm/dts/apq8016-sbc-u-boot.dtsi index 26d4506815e..de77a31cf11 100644 --- a/arch/arm/dts/apq8016-sbc-u-boot.dtsi +++ b/arch/arm/dts/apq8016-sbc-u-boot.dtsi @@ -9,12 +9,3 @@ reg = <0 0x80000000 0 0x40000000>; }; }; - -/* - * When running as a first-stage bootloader, we need to re-configure the UART pins - * because SBL de-initialises them. Indicate that the UART pins should be configured - * during all boot stages. - */ -&blsp_uart2_console_default { - bootph-all; -}; -- cgit v1.2.3 From 080d19b6e64e11b70b33ad5ef98dbd6e37ec9bbd Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Sep 2025 13:31:22 +0200 Subject: Revert "serial: serial_msm: Delay initialization to let pins stabilize" There have been issues with autoboot on DB410c for years, where autoboot gets interrupted by spurious input on the UART console. Back in 2021, I've tried to fix this by inserting a delay before UART initialization, but it has turned out this is not working reliably either. It looks like the root cause has always been the lack of bias-pull-up, which was causing the RX line to be floating when UART is disconnected. The delay does not seem to be needed anymore when applying bias-pull-up, so drop it again in favor of the proper fix. This reverts commit ad7e967738a9c639e07cf50b83ffccdf9a8537b0. Signed-off-by: Stephan Gerhold Tested-by: Alexey Minnekhanov Acked-by: Sumit Garg Link: https://lore.kernel.org/r/20250908-db410c-autoboot-fixes-v2-2-316ed98e0143@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 757e5eaf974..c8df91fca58 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -17,7 +17,6 @@ #include #include #include -#include #include /* Serial registers - this driver works in uartdm mode*/ @@ -207,8 +206,6 @@ static int calc_csr_bitrate(struct msm_serial_data *priv) static void uart_dm_init(struct msm_serial_data *priv) { - /* Delay initialization for a bit to let pins stabilize if necessary */ - mdelay(5); int bitrate = calc_csr_bitrate(priv); if (bitrate < 0) { log_warning("Couldn't calculate bit clock divider! Using default\n"); -- cgit v1.2.3 From a8f5b34ec5787ab44471446ffc6391b0fd94ff42 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Sep 2025 13:31:23 +0200 Subject: serial: msm: Cleanup register naming Some of the register definitions are inconsistently named (likely copied as-is from Qualcomm's Little Kernel/LK bootloader, which uses the MSM_BOOT_UART naming scheme). Rename them to be in line with the other register definitions and move them up to be next to the related register. No functional change. Signed-off-by: Stephan Gerhold Tested-by: Alexey Minnekhanov Acked-by: Sumit Garg Link: https://lore.kernel.org/r/20250908-db410c-autoboot-fixes-v2-3-316ed98e0143@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index c8df91fca58..aa4d10e7c51 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -29,7 +29,9 @@ #define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */ #define UARTDM_RXFS_BUF_MASK 0x7 #define UARTDM_MR1 0x00 +#define UARTDM_MR1_RX_RDY_CTL BIT(7) #define UARTDM_MR2 0x04 +#define UARTDM_MR2_8_N_1_MODE 0x34 /* * This is documented on page 1817 of the apq8016e technical reference manual. * section 6.2.5.3.26 @@ -48,6 +50,8 @@ #define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */ #define UARTDM_CR 0xA8 /* Command register */ +#define UARTDM_CR_CMD_RESET_RX (1 << 4) /* Reset receiver */ +#define UARTDM_CR_CMD_RESET_TX (2 << 4) /* Reset transmitter */ #define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */ #define UARTDM_CR_CMD_RESET_STALE_INT (8 << 4) /* Clears stale irq */ #define UARTDM_CR_CMD_RESET_TX_READY (3 << 8) /* Clears TX Ready irq*/ @@ -61,11 +65,6 @@ #define UARTDM_TF 0x100 /* UART Transmit FIFO register */ #define UARTDM_RF 0x140 /* UART Receive FIFO register */ -#define MSM_BOOT_UART_DM_8_N_1_MODE 0x34 -#define MSM_BOOT_UART_DM_CMD_RESET_RX 0x10 -#define MSM_BOOT_UART_DM_CMD_RESET_TX 0x20 -#define MSM_UART_MR1_RX_RDY_CTL BIT(7) - DECLARE_GLOBAL_DATA_PTR; struct msm_serial_data { @@ -218,10 +217,10 @@ static void uart_dm_init(struct msm_serial_data *priv) writel(bitrate, priv->base + UARTDM_CSR); /* Enable RS232 flow control to support RS232 db9 connector */ - writel(MSM_UART_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1); - writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2); - writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR); - writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR); + writel(UARTDM_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1); + writel(UARTDM_MR2_8_N_1_MODE, priv->base + UARTDM_MR2); + writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR); + writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR); /* Make sure BAM/single character mode is disabled */ writel(0x0, priv->base + UARTDM_DMEN); -- cgit v1.2.3 From eac35b90271537836c6fc37dd4e4e3cba7244b93 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Sep 2025 13:31:24 +0200 Subject: serial: msm: Reset after writing to DMEN According to the documentation of the UART controller in the APQ8016E TRM, clearing bits inside UARTDM_DMEN requires resetting the transmitter and/or receiver. We do reset inside uart_dm_init(), but before writing to UARTDM_DMEN. This doesn't seem to cause problems in practice, but let's move the reset to the end of uart_dm_init() to better match the recommendations in the documentation. Reviewed-by: Neil Armstrong Signed-off-by: Stephan Gerhold Tested-by: Alexey Minnekhanov Acked-by: Sumit Garg Link: https://lore.kernel.org/r/20250908-db410c-autoboot-fixes-v2-4-316ed98e0143@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index aa4d10e7c51..5523ec4afe1 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -219,11 +219,12 @@ static void uart_dm_init(struct msm_serial_data *priv) /* Enable RS232 flow control to support RS232 db9 connector */ writel(UARTDM_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1); writel(UARTDM_MR2_8_N_1_MODE, priv->base + UARTDM_MR2); - writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR); - writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR); /* Make sure BAM/single character mode is disabled */ writel(0x0, priv->base + UARTDM_DMEN); + + writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR); + writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR); } static int msm_serial_probe(struct udevice *dev) { -- cgit v1.2.3 From 5b83a081a7621e1be033518d771ea9a2ae0de962 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Sep 2025 13:31:25 +0200 Subject: serial: msm: Re-enable after resetting The documentation for the UART controller in the APQ8016E specifies that both RESET and ENABLE commands must be issued to set up the receiver and transmitter, but at the moment we only issue RESET. This doesn't seem to cause issues in practice (looks like the reset already re-enables the receiver/transmitter), but let's add the two writes to RX_ENABLE/TX_ENABLE to better match the recommendations in the documentation. Reviewed-by: Neil Armstrong Signed-off-by: Stephan Gerhold Tested-by: Alexey Minnekhanov Acked-by: Sumit Garg Link: https://lore.kernel.org/r/20250908-db410c-autoboot-fixes-v2-5-316ed98e0143@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 5523ec4afe1..2c08a84b027 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -50,6 +50,8 @@ #define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */ #define UARTDM_CR 0xA8 /* Command register */ +#define UARTDM_CR_RX_ENABLE (1 << 0) /* Enable receiver */ +#define UARTDM_CR_TX_ENABLE (1 << 2) /* Enable transmitter */ #define UARTDM_CR_CMD_RESET_RX (1 << 4) /* Reset receiver */ #define UARTDM_CR_CMD_RESET_TX (2 << 4) /* Reset transmitter */ #define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */ @@ -225,6 +227,8 @@ static void uart_dm_init(struct msm_serial_data *priv) writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR); writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR); + writel(UARTDM_CR_RX_ENABLE, priv->base + UARTDM_CR); + writel(UARTDM_CR_TX_ENABLE, priv->base + UARTDM_CR); } static int msm_serial_probe(struct udevice *dev) { -- cgit v1.2.3 From ff701837850e72f7333872d69c8dc8e77c66c870 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Sep 2025 13:31:26 +0200 Subject: serial: msm: Use single character mode The UART DM controller supports different channel data packing modes, either the 4-character packing mode (where 32-bit are read/written at once) or the single-character mode (where only a single character is read/written at a time). The 4-character mode can be more efficient, but the single-character mode is much easier to implement. At the moment, serial_msm uses the 4-character mode. Since the dm_serial_ops operate on one character at the time, the code goes through quite some hoops in order to break this down to single characters. This code is prone to race conditions (e.g. priv->chars_cnt is read from the registers, then a command is issued, what if another char came in inbetween?). It also seems to cause another subtle issue with autoboot: Unlike the previous autoboot failures that happened when UART was disconnected, this problem occurs when UART is connected and open in a terminal: For EFI boot, the console size is queried in efi_console.c query_console_serial() by sending an ANSI escape code via UART. For some reason, with the current driver we get yet another 0x00 byte (UART break event?) when reading the reply from serial input. Because of that, reading the console size fails in efi_console.c, the actual reply remains in the UART buffer, and later the boot flow aborts because it detects input after printing a prompt. Rather than trying to fix the issue in the current complicated approach, switch the driver to use the single-character mode. This is simple and straightforward to implement without race conditions: - We write one character at a time to UARTDM_TF, as long as the TX FIFO has space available (TX_READY). To flush the console before starting Linux, we wait for TX_EMPTY. - We read one character at a time from UARTDM_RF and strip off the additional error information (assuming there is something in the RX FIFO, as indicated by RX_READY). In this mode, querying the serial console size works and autoboot is no longer interrupted. The overall code is also much shorter. Reviewed-by: Neil Armstrong Signed-off-by: Stephan Gerhold Tested-by: Alexey Minnekhanov Acked-by: Sumit Garg Link: https://lore.kernel.org/r/20250908-db410c-autoboot-fixes-v2-6-316ed98e0143@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm.c | 102 +++++++------------------------------------- 1 file changed, 16 insertions(+), 86 deletions(-) diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 2c08a84b027..18d15b7b15b 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -21,13 +21,9 @@ /* Serial registers - this driver works in uartdm mode*/ -#define UARTDM_DMRX 0x34 /* Max RX transfer length */ -#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */ -#define UARTDM_NCF_TX 0x40 /* Number of chars to TX */ +#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */ +#define UARTDM_DMEN_TXRX_SC_ENABLE (BIT(4) | BIT(5)) -#define UARTDM_RXFS 0x50 /* RX channel status register */ -#define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */ -#define UARTDM_RXFS_BUF_MASK 0x7 #define UARTDM_MR1 0x00 #define UARTDM_MR1_RX_RDY_CTL BIT(7) #define UARTDM_MR2 0x04 @@ -45,118 +41,56 @@ #define UARTDM_CSR 0xA0 #define UARTDM_SR 0xA4 /* Status register */ -#define UARTDM_SR_RX_READY (1 << 0) /* Word is the receiver FIFO */ +#define UARTDM_SR_RX_READY (1 << 0) /* Receiver FIFO has data */ +#define UARTDM_SR_TX_READY (1 << 2) /* Transmitter FIFO has space */ #define UARTDM_SR_TX_EMPTY (1 << 3) /* Transmitter underrun */ -#define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */ #define UARTDM_CR 0xA8 /* Command register */ #define UARTDM_CR_RX_ENABLE (1 << 0) /* Enable receiver */ #define UARTDM_CR_TX_ENABLE (1 << 2) /* Enable transmitter */ #define UARTDM_CR_CMD_RESET_RX (1 << 4) /* Reset receiver */ #define UARTDM_CR_CMD_RESET_TX (2 << 4) /* Reset transmitter */ -#define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */ -#define UARTDM_CR_CMD_RESET_STALE_INT (8 << 4) /* Clears stale irq */ -#define UARTDM_CR_CMD_RESET_TX_READY (3 << 8) /* Clears TX Ready irq*/ -#define UARTDM_CR_CMD_FORCE_STALE (4 << 8) /* Causes stale event */ -#define UARTDM_CR_CMD_STALE_EVENT_DISABLE (6 << 8) /* Disable stale event */ - -#define UARTDM_IMR 0xB0 /* Interrupt mask register */ -#define UARTDM_ISR 0xB4 /* Interrupt status register */ -#define UARTDM_ISR_TX_READY 0x80 /* TX FIFO empty */ #define UARTDM_TF 0x100 /* UART Transmit FIFO register */ #define UARTDM_RF 0x140 /* UART Receive FIFO register */ +#define UARTDM_RF_CHAR 0xff /* higher bits contain error information */ DECLARE_GLOBAL_DATA_PTR; struct msm_serial_data { phys_addr_t base; - unsigned chars_cnt; /* number of buffered chars */ - uint32_t chars_buf; /* buffered chars */ uint32_t clk_rate; /* core clock rate */ }; -static int msm_serial_fetch(struct udevice *dev) -{ - struct msm_serial_data *priv = dev_get_priv(dev); - unsigned sr; - - if (priv->chars_cnt) - return priv->chars_cnt; - - /* Clear error in case of buffer overrun */ - if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN) - writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR); - - /* We need to fetch new character */ - sr = readl(priv->base + UARTDM_SR); - - if (sr & UARTDM_SR_RX_READY) { - /* There are at least 4 bytes in fifo */ - priv->chars_buf = readl(priv->base + UARTDM_RF); - priv->chars_cnt = 4; - } else { - /* Check if there is anything in fifo */ - priv->chars_cnt = readl(priv->base + UARTDM_RXFS); - /* Extract number of characters in UART packing buffer*/ - priv->chars_cnt = (priv->chars_cnt >> - UARTDM_RXFS_BUF_SHIFT) & - UARTDM_RXFS_BUF_MASK; - if (!priv->chars_cnt) - return 0; - - /* There is at least one charcter, move it to fifo */ - writel(UARTDM_CR_CMD_FORCE_STALE, - priv->base + UARTDM_CR); - - priv->chars_buf = readl(priv->base + UARTDM_RF); - writel(UARTDM_CR_CMD_RESET_STALE_INT, - priv->base + UARTDM_CR); - writel(0x7, priv->base + UARTDM_DMRX); - } - - return priv->chars_cnt; -} - static int msm_serial_getc(struct udevice *dev) { struct msm_serial_data *priv = dev_get_priv(dev); - char c; - if (!msm_serial_fetch(dev)) + if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_RX_READY)) return -EAGAIN; - c = priv->chars_buf & 0xFF; - priv->chars_buf >>= 8; - priv->chars_cnt--; - - return c; + return readl(priv->base + UARTDM_RF) & UARTDM_RF_CHAR; } static int msm_serial_putc(struct udevice *dev, const char ch) { struct msm_serial_data *priv = dev_get_priv(dev); - if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) && - !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY)) + if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_READY)) return -EAGAIN; - writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR); - - writel(1, priv->base + UARTDM_NCF_TX); writel(ch, priv->base + UARTDM_TF); - return 0; } static int msm_serial_pending(struct udevice *dev, bool input) { - if (input) { - if (msm_serial_fetch(dev)) - return 1; - } + struct msm_serial_data *priv = dev_get_priv(dev); - return 0; + if (input) + return !!(readl(priv->base + UARTDM_SR) & UARTDM_SR_RX_READY); + else + return !(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY); } static const struct dm_serial_ops msm_serial_ops = { @@ -222,8 +156,8 @@ static void uart_dm_init(struct msm_serial_data *priv) writel(UARTDM_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1); writel(UARTDM_MR2_8_N_1_MODE, priv->base + UARTDM_MR2); - /* Make sure BAM/single character mode is disabled */ - writel(0x0, priv->base + UARTDM_DMEN); + /* Enable single character mode */ + writel(UARTDM_DMEN_TXRX_SC_ENABLE, priv->base + UARTDM_DMEN); writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR); writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR); @@ -320,13 +254,9 @@ static inline void _debug_uart_putc(int ch) { struct msm_serial_data *priv = &init_serial_data; - while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) && - !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY)) + while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_READY)) ; - writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR); - - writel(1, priv->base + UARTDM_NCF_TX); writel(ch, priv->base + UARTDM_TF); } -- cgit v1.2.3 From 834cbecce790a6b8abb4869a7c416cf8b7ecaa51 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Sun, 31 Aug 2025 02:45:59 +0200 Subject: clk/qcom: add driver for SM7150 GCC Add a clock driver for the SM7150 SoC. This driver can enable necessary clocks for UART, UFS, USB, and MMC. Signed-off-by: Danila Tikhonov Co-developed-by: Jens Reidel Signed-off-by: Jens Reidel Reviewed-by: Casey Connolly Link: https://lore.kernel.org/r/20250831004602.699953-2-adrian@mainlining.org Signed-off-by: Casey Connolly --- drivers/clk/qcom/Kconfig | 7 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clock-sm7150.c | 250 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 drivers/clk/qcom/clock-sm7150.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 347d16de3db..8504ed5d656 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -109,6 +109,13 @@ config CLK_QCOM_SM6350 help Say Y here to enable support for the Global Clock Controller on the Snapdragon SM6350 SoC. This driver supports the clocks + +config CLK_QCOM_SM7150 + bool "Qualcomm SM7150 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon SM7150 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. config CLK_QCOM_SM8150 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index a85c77ad1e7..82a5b166196 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o obj-$(CONFIG_CLK_QCOM_SM6350) += clock-sm6350.o +obj-$(CONFIG_CLK_QCOM_SM7150) += clock-sm7150.o obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o diff --git a/drivers/clk/qcom/clock-sm7150.c b/drivers/clk/qcom/clock-sm7150.c new file mode 100644 index 00000000000..8fe2076e55e --- /dev/null +++ b/drivers/clk/qcom/clock-sm7150.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm SM7150 + * + * (C) Copyright 2025 Danila Tikhonov + * (C) Copyright 2025 Jens Reidel + * + * Based on Linux Kernel driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clock-qcom.h" + +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034 +#define USB3_PRIM_PHY_AUX_CLK_CMD_RCGR 0xf060 + +#define SE8_UART_APPS_CMD_RCGR 0x18278 +#define GCC_SDCC2_APPS_CLK_SRC_REG 0x1400c + +#define APCS_GPLL7_STATUS 0x27000 +#define APCS_GPLLX_ENA_REG 0x52000 + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL0, 1, 16, 75), + { } +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(208000000, CFG_CLK_SRC_GPLL7, 4, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, CFG_CLK_SRC_GPLL0, 4.5, 0, 0), + F(133333333, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), + F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(20000000, CFG_CLK_SRC_GPLL0_EVEN, 15, 0, 0), + F(40000000, CFG_CLK_SRC_GPLL0_EVEN, 7.5, 0, 0), + F(60000000, CFG_CLK_SRC_GPLL0, 10, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb3_prim_phy_aux_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + { } +}; + +static ulong sm7150_clk_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_QUPV3_WRAP1_S2_CLK: /* UART8 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, SE8_UART_APPS_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; + case GCC_USB30_PRIM_MASTER_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_USB3_PRIM_PHY_AUX_CLK_SRC: + freq = qcom_find_freq(ftbl_gcc_usb3_prim_phy_aux_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB3_PRIM_PHY_AUX_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_SDCC2_APPS_CLK: + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, GCC_SDCC2_APPS_CLK_SRC_REG, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + default: + return 0; + } +} + +static const struct gate_clk sm7150_clks[] = { + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, BIT(0)), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, BIT(0)), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x502c, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, BIT(10)), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, BIT(11)), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, BIT(12)), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, BIT(14)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x5200c, BIT(16)), + GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x5200c, BIT(17)), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, BIT(22)), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, BIT(23)), + GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x5200c, BIT(24)), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, BIT(25)), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, BIT(26)), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, BIT(27)), + GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x5200c, BIT(28)), + GATE_CLK(GCC_QUPV3_WRAP1_S7_CLK, 0x5200c, BIT(29)), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, BIT(6)), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, BIT(7)), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, BIT(20)), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, BIT(21)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x12008, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x1200c, BIT(0)), + GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x12040, BIT(0)), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)), + GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, BIT(0)), + GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, BIT(0)), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77014, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77038, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77090, BIT(0)), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x77094, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7701c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7708c, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f010, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f018, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f014, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c010, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f050, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f054, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f058, BIT(0)), + GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, BIT(0)), +}; + +static int sm7150_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %s\n", __func__, sm7150_clks[clk->id].name); + + switch (clk->id) { + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map sm7150_gcc_resets[] = { + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x26000 }, +}; + +static const struct qcom_power_map sm7150_gdscs[] = { + [PCIE_0_GDSC] = { 0x6b004 }, + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, +}; + +static const phys_addr_t sm7150_rcg_addrs[] = { + 0x10f01c, // USB30_PRIM_MASTER_CLK_CMD_RCGR + 0x10f034, // USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR + 0x10f060, // USB3_PRIM_PHY_AUX_CLK_CMD_RCGR, +}; + +static const char *const sm7150_rcg_names[] = { + "USB30_PRIM_MASTER_CLK", + "USB30_PRIM_MOCK_UTMI_CLK", + "USB3_PRIM_PHY_AUX_CLK", +}; + +static struct msm_clk_data sm7150_gcc_data = { + .resets = sm7150_gcc_resets, + .num_resets = ARRAY_SIZE(sm7150_gcc_resets), + .clks = sm7150_clks, + .num_clks = ARRAY_SIZE(sm7150_clks), + + .power_domains = sm7150_gdscs, + .num_power_domains = ARRAY_SIZE(sm7150_gdscs), + + .enable = sm7150_clk_enable, + .set_rate = sm7150_clk_set_rate, + + .dbg_rcg_addrs = sm7150_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sm7150_rcg_addrs), + .dbg_rcg_names = sm7150_rcg_names, +}; + +static const struct udevice_id gcc_sm7150_of_match[] = { + { .compatible = "qcom,sm7150-gcc", .data = (ulong)&sm7150_gcc_data, }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(gcc_sm7150) = { + .name = "gcc_sm7150", + .id = UCLASS_NOP, + .of_match = gcc_sm7150_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; -- cgit v1.2.3 From 23fc229eb422cb48c0786869cb90bd3f2b24839b Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Sun, 31 Aug 2025 02:46:00 +0200 Subject: pinctrl: qcom: add SM7150 pinctrl driver This SoC features a pinctrl block with north, south, and west tiles accessible to the AP. Signed-off-by: Danila Tikhonov Co-developed-by: Jens Reidel Signed-off-by: Jens Reidel Link: https://lore.kernel.org/r/20250831004602.699953-3-adrian@mainlining.org Signed-off-by: Casey Connolly --- drivers/pinctrl/qcom/Kconfig | 6 ++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-sm7150.c | 142 ++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-sm7150.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 1f5616f01cd..320aba33347 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -101,6 +101,12 @@ config PINCTRL_QCOM_SM6350 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" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM7150 SoC, as well as the associated GPIO driver. config PINCTRL_QCOM_SM8150 diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index df55d00f334..06582ac2068 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_QCOM_SDM670) += pinctrl-sdm670.o obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o obj-$(CONFIG_PINCTRL_QCOM_SM6350) += pinctrl-sm6350.o +obj-$(CONFIG_PINCTRL_QCOM_SM7150) += pinctrl-sm7150.o obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c new file mode 100644 index 00000000000..435ba39b1db --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Pinctrl driver for Qualcomm SM7150 + * + * (C) Copyright 2025 Danila Tikhonov + * (C) Copyright 2025 Jens Reidel + * + * Based on Linux Kernel driver + */ + +#include + +#include "pinctrl-qcom.h" + +#define WEST 0x00000000 +#define NORTH 0x00400000 +#define SOUTH 0x00800000 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + { "qup12", 1 }, + { "gpio", 0 }, + { "sdc2_clk", 0 } /* special pin GPIO124 */ +}; + +#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, offset) \ + { \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data msm_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", 0x9f000), + [1] = SDC_QDSD_PINGROUP("sdc1_rclk", WEST + 0x9a000, 15, 0), + [2] = SDC_QDSD_PINGROUP("sdc1_clk", WEST + 0x9a000, 13, 6), + [3] = SDC_QDSD_PINGROUP("sdc1_cmd", WEST + 0x9a000, 11, 3), + [4] = SDC_QDSD_PINGROUP("sdc1_data", WEST + 0x9a000, 9, 0), + [5] = SDC_QDSD_PINGROUP("sdc2_clk", SOUTH + 0x98000, 14, 6), + [6] = SDC_QDSD_PINGROUP("sdc2_cmd", SOUTH + 0x98000, 11, 3), + [7] = SDC_QDSD_PINGROUP("sdc2_data", SOUTH + 0x98000, 9, 0), +}; + +static const unsigned int sm7150_pin_offsets[] = { + [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, + [4] = NORTH, [5] = NORTH, [6] = NORTH, [7] = NORTH, + [8] = NORTH, [9] = NORTH, [10] = NORTH, [11] = NORTH, + [12] = SOUTH, [13] = SOUTH, [14] = SOUTH, [15] = SOUTH, + [16] = SOUTH, [17] = SOUTH, [18] = SOUTH, [19] = SOUTH, + [20] = SOUTH, [21] = SOUTH, [22] = SOUTH, [23] = SOUTH, + [24] = SOUTH, [25] = SOUTH, [26] = SOUTH, [27] = SOUTH, + [28] = SOUTH, [29] = NORTH, [30] = SOUTH, [31] = WEST, + [32] = NORTH, [33] = NORTH, [34] = SOUTH, [35] = SOUTH, + [36] = SOUTH, [37] = SOUTH, [38] = SOUTH, [39] = SOUTH, + [40] = SOUTH, [41] = SOUTH, [42] = NORTH, [43] = NORTH, + [44] = NORTH, [45] = NORTH, [46] = NORTH, [47] = NORTH, + [48] = WEST, [49] = WEST, [50] = WEST, [51] = WEST, + [52] = WEST, [53] = WEST, [54] = WEST, [55] = WEST, + [56] = WEST, [57] = WEST, [58] = WEST, [59] = NORTH, + [60] = NORTH, [61] = NORTH, [62] = NORTH, [63] = NORTH, + [64] = NORTH, [65] = NORTH, [66] = NORTH, [67] = NORTH, + [68] = NORTH, [69] = NORTH, [70] = NORTH, [71] = NORTH, + [72] = NORTH, [73] = NORTH, [74] = WEST, [75] = WEST, + [76] = WEST, [77] = WEST, [78] = WEST, [79] = WEST, + [80] = WEST, [81] = WEST, [82] = WEST, [83] = WEST, + [84] = WEST, [85] = WEST, [86] = NORTH, [87] = NORTH, + [88] = NORTH, [89] = NORTH, [90] = NORTH, [91] = NORTH, + [92] = NORTH, [93] = NORTH, [94] = SOUTH, [95] = WEST, + [96] = WEST, [97] = WEST, [98] = WEST, [99] = WEST, + [100] = WEST, [101] = NORTH, [102] = NORTH, [103] = NORTH, + [104] = WEST, [105] = NORTH, [106] = NORTH, [107] = WEST, + [108] = SOUTH, [109] = SOUTH, [110] = NORTH, [111] = NORTH, + [112] = NORTH, [113] = NORTH, [114] = NORTH, [115] = NORTH, + [116] = NORTH, [117] = NORTH, [118] = NORTH, +}; + +static const char *sm7150_get_function_name(struct udevice *dev, unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm7150_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 119 && selector <= 126) + snprintf(pin_name, MAX_PIN_NAME_LEN, + msm_special_pins_data[selector - 119].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sm7150_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm7150_data = { + .pin_data = { + .pin_offsets = sm7150_pin_offsets, + .pin_count = 126, + .special_pins_start = 119, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm7150_get_function_name, + .get_function_mux = sm7150_get_function_mux, + .get_pin_name = sm7150_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm7150-tlmm", .data = (ulong)&sm7150_data }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm7150) = { + .name = "pinctrl_sm7150", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; -- cgit v1.2.3 From 3a44e56290f68992ac5c4a587ea0674eb88ac622 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Sun, 31 Aug 2025 02:46:01 +0200 Subject: phy: qcom-qmp-ufs: Import SM7150 tables from Linux Import the init sequence for the UFS on SM7150. Signed-off-by: Danila Tikhonov Signed-off-by: Jens Reidel Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250831004602.699953-4-adrian@mainlining.org Signed-off-by: Casey Connolly --- drivers/phy/qcom/phy-qcom-qmp-ufs.c | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c index 1c790be2e48..907f34744eb 100644 --- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -221,6 +221,36 @@ static const struct qmp_ufs_init_tbl sm8150_ufsphy_hs_g4_rx[] = { QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x3c), }; +static const struct qmp_ufs_init_tbl sm7150_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), +}; + +static const struct qmp_ufs_init_tbl sm7150_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + static const struct qmp_ufs_init_tbl sm8150_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11), @@ -1018,6 +1048,36 @@ static const struct qmp_ufs_cfg sm8150_ufsphy_cfg = { .no_pcs_sw_reset = false, }; +static const struct qmp_ufs_cfg sm7150_ufsphy_cfg = { + .lanes = 1, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sdm845_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes), + .tx = sdm845_ufsphy_tx, + .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx), + .rx = sm7150_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm7150_ufsphy_rx), + .pcs = sm7150_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm7150_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sdm845_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .reset_list = qmp_ufs_reset_l, + .num_resets = ARRAY_SIZE(qmp_ufs_reset_l), + .regs = ufsphy_v3_regs_layout, + + .no_pcs_sw_reset = true, +}; + static const struct qmp_ufs_cfg sm8250_ufsphy_cfg = { .lanes = 2, @@ -1594,6 +1654,7 @@ static const struct udevice_id qmp_ufs_ids[] = { { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg, }, { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, { .compatible = "qcom,sm6350-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, + { .compatible = "qcom,sm7150-qmp-ufs-phy", .data = (ulong)&sm7150_ufsphy_cfg }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = (ulong)&sm8150_ufsphy_cfg }, { .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg }, { .compatible = "qcom,qcs8300-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg }, -- cgit v1.2.3 From 30eb854a56cdf74fba00d6a8fb7bfc1004d476e6 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Sun, 31 Aug 2025 02:46:02 +0200 Subject: configs: qcom_defconfig: Enable SM7150 GCC and Pinctrl Enable the necessary drivers so that SM7150 devices can boot with qcom_defconfig. Signed-off-by: Danila Tikhonov Signed-off-by: Jens Reidel Reviewed-by: Casey Connolly Link: https://lore.kernel.org/r/20250831004602.699953-5-adrian@mainlining.org Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 5c4152cd19b..bb795fe6608 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -64,6 +64,7 @@ CONFIG_CLK_QCOM_SA8775P=y CONFIG_CLK_QCOM_SDM845=y CONFIG_CLK_QCOM_SM6115=y CONFIG_CLK_QCOM_SM6350=y +CONFIG_CLK_QCOM_SM7150=y CONFIG_CLK_QCOM_SM8150=y CONFIG_CLK_QCOM_SM8250=y CONFIG_CLK_QCOM_SM8550=y @@ -119,6 +120,7 @@ CONFIG_PINCTRL_QCOM_SDM670=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 -- cgit v1.2.3 From 077ae372da91a77299e7464aea94024083db1976 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Wed, 27 Aug 2025 01:17:52 +0200 Subject: clk/stub: add sc7180-rpmh clock Stub the RPMh clock controller on SC7180. Signed-off-by: Jens Reidel Reviewed-by: Casey Connolly Link: https://lore.kernel.org/r/20250826231752.60633-1-adrian@mainlining.org Signed-off-by: Casey Connolly --- drivers/clk/clk-stub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c index 14a7b9948e6..117266ac778 100644 --- a/drivers/clk/clk-stub.c +++ b/drivers/clk/clk-stub.c @@ -52,6 +52,7 @@ static const struct udevice_id stub_clk_ids[] = { { .compatible = "qcom,rpmcc" }, { .compatible = "qcom,sdm670-rpmh-clk" }, { .compatible = "qcom,sdm845-rpmh-clk" }, + { .compatible = "qcom,sc7180-rpmh-clk" }, { .compatible = "qcom,sc7280-rpmh-clk" }, { .compatible = "qcom,sm6350-rpmh-clk" }, { .compatible = "qcom,sm8150-rpmh-clk" }, -- cgit v1.2.3 From ada314a7caf543390cd59a34db00fd97bba672ec Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Tue, 22 Jul 2025 17:34:56 +0200 Subject: configs: qualcomm: use fragments for debug UART The QCM6490 and QCS9100 targets always enable debug UART, but this is not really optimal for typical users. Move these debug UART options to config fragments so that they aren't enabled by default. Signed-off-by: Casey Connolly Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20250722-b4-qcom-tooling-improvements-v5-6-df143f1247fc@linaro.org Signed-off-by: Casey Connolly --- board/qualcomm/debug-qcm6490.config | 5 +++++ board/qualcomm/debug-qcs9100.config | 5 +++++ configs/qcm6490_defconfig | 6 ------ configs/qcs9100_defconfig | 6 ------ 4 files changed, 10 insertions(+), 12 deletions(-) create mode 100644 board/qualcomm/debug-qcm6490.config create mode 100644 board/qualcomm/debug-qcs9100.config diff --git a/board/qualcomm/debug-qcm6490.config b/board/qualcomm/debug-qcm6490.config new file mode 100644 index 00000000000..9ea54758794 --- /dev/null +++ b/board/qualcomm/debug-qcm6490.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x994000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 diff --git a/board/qualcomm/debug-qcs9100.config b/board/qualcomm/debug-qcs9100.config new file mode 100644 index 00000000000..8ca042b440d --- /dev/null +++ b/board/qualcomm/debug-qcs9100.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0xA8C000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 diff --git a/configs/qcm6490_defconfig b/configs/qcm6490_defconfig index 5ddc5ab3ef8..54eb5dedaec 100644 --- a/configs/qcm6490_defconfig +++ b/configs/qcm6490_defconfig @@ -8,12 +8,6 @@ # Otherwise buildman thinks this isn't an ARM platform CONFIG_ARM=y -CONFIG_DEBUG_UART=y -CONFIG_DEBUG_UART_ANNOUNCE=y -CONFIG_DEBUG_UART_BASE=0x994000 -CONFIG_DEBUG_UART_MSM_GENI=y -CONFIG_DEBUG_UART_CLOCK=14745600 - # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0x9fc00000 CONFIG_REMAKE_ELF=y diff --git a/configs/qcs9100_defconfig b/configs/qcs9100_defconfig index cd48973599b..216dfa3211e 100644 --- a/configs/qcs9100_defconfig +++ b/configs/qcs9100_defconfig @@ -5,12 +5,6 @@ #include "qcom_defconfig" -CONFIG_DEBUG_UART=y -CONFIG_DEBUG_UART_ANNOUNCE=y -CONFIG_DEBUG_UART_BASE=0xA8C000 -CONFIG_DEBUG_UART_MSM_GENI=y -CONFIG_DEBUG_UART_CLOCK=14745600 - # Address where U-Boot will be loaded CONFIG_TEXT_BASE=0xaf000000 CONFIG_REMAKE_ELF=y -- cgit v1.2.3 From f3e73dc94b4e9e373fd90d74a69ded9a5bb28f4d Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 14 Jul 2025 15:13:13 +0200 Subject: i2c: geni: fix error message wording in clk_disable Correct the error messages so they accurately describe that we failed to disable the clocks, not to enable them. Signed-off-by: Casey Connolly Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20250714-geni-load-fw-v5-2-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- drivers/i2c/geni_i2c.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c index eabf5c76c21..4eb41ba852f 100644 --- a/drivers/i2c/geni_i2c.c +++ b/drivers/i2c/geni_i2c.c @@ -331,15 +331,13 @@ static int geni_i2c_disable_clocks(struct udevice *dev, struct geni_i2c_priv *ge if (geni->is_master_hub) { ret = clk_disable(&geni->core); if (ret) { - dev_err(dev, "clk_enable core failed %d\n", ret); - return ret; + dev_err(dev, "clk_disable core failed %d\n", ret); } } ret = clk_disable(&geni->se); if (ret) { - dev_err(dev, "clk_enable se failed %d\n", ret); - return ret; + dev_err(dev, "clk_disable se failed %d\n", ret); } return 0; -- cgit v1.2.3 From b95df6ed8c21aee71b4859d9d88c6a6e32c641c8 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 14 Jul 2025 15:13:14 +0200 Subject: misc: introduce Qcom GENI wrapper Qualcomm peripherals like UART, SPI, I2C, etc are all exposed under a common GENI Serial Engine wrapper device. Replace the stub driver we use for this currently with a full-on misc device and implement support for loading peripheral firmware. Each of the peripherals has it's own protocol-specific firmware, this is stored on the internal storage of the device with a well-known partition type GUID. To support this, GENI will bind peripherals in two stages. First the ones that already have firmware loaded (such as the serial port) are bound in the typical way. But devices that require firmware loading are deferred until EVT_LAST_STAGE_INIT. At this point we can be sure that the storage device is available, so we load the firmware and then bind and probe the remaining children. Child devices are expected to determine if firmware loading is necessary and call qcom_geni_load_firmware(). Since Linux currently doesn't support loading firmware (and firmware may not be available), we probe all GENI peripherals to ensure that they always load firmware if necessary. Signed-off-by: Casey Connolly Link: https://patch.msgid.link/20250714-geni-load-fw-v5-3-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- drivers/i2c/Kconfig | 2 +- drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 + drivers/misc/qcom_geni.c | 580 +++++++++++++++++++++++++++++++++++++++ drivers/serial/Kconfig | 1 + drivers/serial/serial_msm_geni.c | 13 - include/soc/qcom/geni-se.h | 36 +++ include/soc/qcom/qup-fw-load.h | 178 ++++++++++++ 8 files changed, 806 insertions(+), 14 deletions(-) create mode 100644 drivers/misc/qcom_geni.c create mode 100644 include/soc/qcom/qup-fw-load.h diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 108b24b3dd2..b394db27ea0 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -661,7 +661,7 @@ config SYS_I2C_QUP config SYS_I2C_GENI bool "Qualcomm Generic Interface (GENI) I2C controller" - depends on ARCH_SNAPDRAGON + depends on ARCH_SNAPDRAGON && QCOM_GENI help Support for the Qualcomm Generic Interface (GENI) I2C interface. The Generic Interface (GENI) is a firmware based Qualcomm Universal diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index e3a207866ea..dde773ab6b1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -83,6 +83,15 @@ config GATEWORKS_SC boards to provide a boot watchdog, power control, temperature monitor, voltage ADCs, and EEPROM. +config QCOM_GENI + bool "Qualcomm Generic Interface (GENI) driver" + depends on MISC + select PARTITION_TYPE_GUID + help + Enable support for Qualcomm GENI and it's peripherals. GENI is responseible + for providing a common interface for various peripherals like UART, I2C, SPI, + etc. + config ROCKCHIP_EFUSE bool "Rockchip e-fuse support" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index dc5eb3af19c..1d950f7a0ab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif +obj-$(CONFIG_QCOM_GENI) += qcom_geni.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c new file mode 100644 index 00000000000..a62ae6a2478 --- /dev/null +++ b/drivers/misc/qcom_geni.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025, Linaro Ltd. + */ + +#define pr_fmt(fmt) "GENI-SE: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct qup_se_rsc { + phys_addr_t base; + phys_addr_t wrapper_base; + struct udevice *dev; + + enum geni_se_xfer_mode mode; + enum geni_se_protocol_type protocol; +}; + +struct geni_se_plat { + bool need_firmware_load; +}; + +/** + * geni_enable_interrupts() Enable interrupts. + * @rsc: Pointer to a structure representing SE-related resources. + * + * Enable the required interrupts during the firmware load process. + * + * Return: None. + */ +static void geni_enable_interrupts(struct qup_se_rsc *rsc) +{ + u32 reg_value; + + /* Enable required interrupts. */ + writel_relaxed(M_COMMON_GENI_M_IRQ_EN, rsc->base + GENI_M_IRQ_ENABLE); + + reg_value = S_CMD_OVERRUN_EN | S_ILLEGAL_CMD_EN | + S_CMD_CANCEL_EN | S_CMD_ABORT_EN | + S_GP_IRQ_0_EN | S_GP_IRQ_1_EN | + S_GP_IRQ_2_EN | S_GP_IRQ_3_EN | + S_RX_FIFO_WR_ERR_EN | S_RX_FIFO_RD_ERR_EN; + writel_relaxed(reg_value, rsc->base + GENI_S_IRQ_ENABLE); + + /* DMA mode configuration. */ + reg_value = DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK | + DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK | + DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK; + writel_relaxed(reg_value, rsc->base + DMA_TX_IRQ_EN_SET); + reg_value = DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK | + DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK | + DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK | + DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK; + writel_relaxed(reg_value, rsc->base + DMA_RX_IRQ_EN_SET); +} + +/** + * geni_flash_fw_revision() - Flash the firmware revision. + * @rsc: Pointer to a structure representing SE-related resources. + * @hdr: Pointer to the ELF header of the Serial Engine. + * + * Flash the firmware revision and protocol into the respective register. + * + * Return: None. + */ +static void geni_flash_fw_revision(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr) +{ + u32 reg_value; + + /* Flash firmware revision register. */ + reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) | + (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT); + writel_relaxed(reg_value, rsc->base + SE_GENI_FW_REVISION); + + reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) | + (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT); + + writel_relaxed(reg_value, rsc->base + SE_S_FW_REVISION); +} + +/** + * geni_configure_xfer_mode() - Set the transfer mode. + * @rsc: Pointer to a structure representing SE-related resources. + * + * Set the transfer mode to either FIFO or DMA according to the mode specified by the protocol + * driver. + * + * Return: 0 if successful, otherwise return an error value. + */ +static int geni_configure_xfer_mode(struct qup_se_rsc *rsc) +{ + /* Configure SE FIFO, DMA or GSI mode. */ + switch (rsc->mode) { + case GENI_GPI_DMA: + geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN, + GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK); + writel_relaxed(0x0, rsc->base + SE_IRQ_EN); + writel_relaxed(SE_GSI_EVENT_EN_BMSK, rsc->base + SE_GSI_EVENT_EN); + break; + + case GENI_SE_FIFO: + geni_clrbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN, + GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK); + writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN); + writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN); + break; + + case GENI_SE_DMA: + geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN, + GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK); + writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN); + writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN); + break; + + default: + dev_err(rsc->dev, "invalid se mode: %d\n", rsc->mode); + return -EINVAL; + } + return 0; +} + +/** + * geni_config_common_control() - Configure common CGC and disable high priority interrupt. + * @rsc: Pointer to a structure representing SE-related resources. + * + * Configure the common CGC and disable high priority interrupts until the current low priority + * interrupts are handled. + * + * Return: None. + */ +static void geni_config_common_control(struct qup_se_rsc *rsc) +{ + /* + * Disable high priority interrupt until current low priority interrupts are handled. + */ + geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CFG, + FAST_SWITCH_TO_HIGH_DISABLE_BMASK); + + /* + * Set AHB_M_CLK_CGC_ON to indicate hardware controls se-wrapper cgc clock. + */ + geni_setbits32(rsc->wrapper_base + QUPV3_SE_AHB_M_CFG, + AHB_M_CLK_CGC_ON_BMASK); + + /* Let hardware to control common cgc. */ + geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CGC_CTRL, + COMMON_CSR_SLV_CLK_CGC_ON_BMASK); +} + +static int load_se_firmware(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr) +{ + const u32 *fw_val_arr, *cfg_val_arr; + const u8 *cfg_idx_arr; + u32 i, reg_value, mask, ramn_cnt; + int ret; + + fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset); + cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset; + cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset); + + geni_config_common_control(rsc); + + /* Allows to drive corresponding data according to hardware value. */ + writel_relaxed(0x0, rsc->base + GENI_OUTPUT_CTRL); + + /* Set SCLK and HCLK to program RAM */ + geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + writel_relaxed(0x0, rsc->base + SE_GENI_CLK_CTRL); + geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + + /* Enable required clocks for DMA CSR, TX and RX. */ + reg_value = DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK | + DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK | + DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK | + DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK; + + geni_setbits32(rsc->base + DMA_GENERAL_CFG, reg_value); + + /* Let hardware control CGC by default. */ + writel_relaxed(DEFAULT_CGC_EN, rsc->base + GENI_CGC_CTRL); + + /* Set version of the configuration register part of firmware. */ + writel_relaxed(hdr->cfg_version, rsc->base + GENI_INIT_CFG_REVISION); + writel_relaxed(hdr->cfg_version, rsc->base + GENI_S_INIT_CFG_REVISION); + + /* Configure GENI primitive table. */ + for (i = 0; i < hdr->cfg_size_in_items; i++) + writel_relaxed(cfg_val_arr[i], + rsc->base + GENI_CFG_REG0 + (cfg_idx_arr[i] * sizeof(u32))); + + /* Configure condition for assertion of RX_RFR_WATERMARK condition. */ + reg_value = readl_relaxed(rsc->base + QUPV3_SE_HW_PARAM_1); + mask = (reg_value >> RX_FIFO_WIDTH_BIT) & RX_FIFO_WIDTH_MASK; + writel_relaxed(mask - 2, rsc->base + GENI_RX_RFR_WATERMARK_REG); + + /* Let hardware control CGC */ + geni_setbits32(rsc->base + GENI_OUTPUT_CTRL, DEFAULT_IO_OUTPUT_CTRL_MSK); + + ret = geni_configure_xfer_mode(rsc); + if (ret) { + dev_err(rsc->dev, "failed to configure xfer mode: %d\n", ret); + return ret; + } + + geni_enable_interrupts(rsc); + + geni_flash_fw_revision(rsc, hdr); + + ramn_cnt = hdr->fw_size_in_items; + if (hdr->fw_size_in_items % 2 != 0) + ramn_cnt++; + + if (ramn_cnt >= MAX_GENI_CFG_RAMn_CNT) { + dev_err(rsc->dev, "firmware size is too large\n"); + return -EINVAL; + } + + /* Program RAM address space. */ + for (i = 0; i < hdr->fw_size_in_items; i++) + writel_relaxed(fw_val_arr[i], rsc->base + SE_GENI_CFG_RAMN + i * sizeof(u32)); + + /* Put default values on GENI's output pads. */ + writel_relaxed(0x1, rsc->base + GENI_FORCE_DEFAULT_REG); + + /* High to low SCLK and HCLK to finish RAM. */ + geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + geni_setbits32(rsc->base + SE_GENI_CLK_CTRL, GENI_CLK_CTRL_SER_CLK_SEL_BMSK); + geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + + /* Serial engine DMA interface is enabled. */ + geni_setbits32(rsc->base + SE_DMA_IF_EN, DMA_IF_EN_DMA_IF_EN_BMSK); + + /* Enable or disable FIFO interface of the serial engine. */ + if (rsc->mode == GENI_SE_FIFO) + geni_clrbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE); + else + geni_setbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE); + + return 0; +} + +/** + * elf_phdr_valid() - Validate an ELF header. + * @phdr: Pointer to the ELF header. + * + * Validate the ELF header by comparing the fields stored in p_flags and the payload type. + * + * Return: true if the validation is successful, false otherwise. + */ +static bool elf_phdr_valid(const Elf32_Phdr *phdr) +{ + if (phdr->p_type != PT_LOAD || !phdr->p_memsz) + return false; + + if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) == MI_PBT_NON_PAGED_SEGMENT && + MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) != MI_PBT_HASH_SEGMENT && + MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) != MI_PBT_NOTUSED_SEGMENT && + MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) != MI_PBT_SHARED_SEGMENT) + return true; + + return false; +} + +/** + * valid_seg_size() - Validate the segment size. + * @pelfseg: Pointer to the ELF header. + * @p_filesz: Pointer to the file size. + * + * Validate the ELF segment size by comparing the file size. + * + * Return: true if the segment is valid, false if the segment is invalid. + */ +static bool valid_seg_size(struct elf_se_hdr *pelfseg, Elf32_Word p_filesz) +{ + if (p_filesz >= pelfseg->fw_offset + pelfseg->fw_size_in_items * sizeof(u32) && + p_filesz >= pelfseg->cfg_idx_offset + pelfseg->cfg_size_in_items * sizeof(u8) && + p_filesz >= pelfseg->cfg_val_offset + pelfseg->cfg_size_in_items * sizeof(u32)) + return true; + return false; +} + +/** + * read_elf() - Read an ELF file. + * @rsc: Pointer to the SE resources structure. + * @fw: Pointer to the firmware buffer. + * @pelfseg: Pointer to the SE-specific ELF header. + * @phdr: Pointer to one of the valid headers from the list in the firmware buffer. + * + * Read the ELF file and output a pointer to the header data, which contains the firmware data and + * any other details. + * + * Return: 0 if successful, otherwise return an error value. + */ +static int read_elf(struct qup_se_rsc *rsc, const void *fw, + struct elf_se_hdr **pelfseg) +{ + Elf32_Phdr *phdr; + const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)fw; + Elf32_Phdr *phdrs = (Elf32_Phdr *)(ehdr + 1); + const u8 *addr; + int i; + + ehdr = (Elf32_Ehdr *)fw; + + if (ehdr->e_phnum < 2) + return -EINVAL; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &phdrs[i]; + if (!elf_phdr_valid(phdr)) + continue; + + if (phdr->p_filesz >= sizeof(struct elf_se_hdr)) { + addr = fw + phdr->p_offset; + *pelfseg = (struct elf_se_hdr *)addr; + + if ((*pelfseg)->magic == MAGIC_NUM_SE && + (*pelfseg)->version == 1 && + valid_seg_size(*pelfseg, phdr->p_filesz) && + (*pelfseg)->serial_protocol == rsc->protocol && + (*pelfseg)->serial_protocol != GENI_SE_NONE) + return 0; + } + } + return -EINVAL; +} + +int qcom_geni_load_firmware(phys_addr_t qup_base, + struct udevice *dev) +{ + struct qup_se_rsc rsc; + struct elf_se_hdr *hdr; + int ret; + void *fw; + + rsc.dev = dev; + rsc.base = qup_base; + rsc.wrapper_base = dev_read_addr(dev->parent); + + /* FIXME: GSI DMA mode if device has property qcom,gsi-dma-allowed */ + rsc.mode = GENI_SE_FIFO; + + switch (device_get_uclass_id(dev)) { + case UCLASS_I2C: + rsc.protocol = GENI_SE_I2C; + break; + case UCLASS_SPI: + rsc.protocol = GENI_SE_SPI; + break; + case UCLASS_SERIAL: + rsc.protocol = GENI_SE_UART; + break; + default: + return -EINVAL; + } + + /* The firmware blob is the private data of the GENI wrapper (parent) */ + fw = dev_get_priv(dev->parent); + + ret = read_elf(&rsc, fw, &hdr); + if (ret) { + dev_err(dev, "Failed to read ELF: %d\n", ret); + return ret; + } + + dev_info(dev, "Loading QUP firmware...\n"); + + return load_se_firmware(&rsc, hdr); +} + +/* + * We need to determine if firmware loading is necessary. Best way to do that is to check the FW + * revision of each QUP and see if it has already been loaded. + */ +static int geni_se_of_to_plat(struct udevice *dev) +{ + ofnode child; + struct resource res; + u32 proto; + struct geni_se_plat *plat = dev_get_plat(dev); + + plat->need_firmware_load = false; + + dev_for_each_subnode(child, dev) { + if (!ofnode_is_enabled(child)) + continue; + + if (ofnode_read_resource(child, 0, &res)) + continue; + + proto = readl(res.start + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + + if (proto == GENI_SE_INVALID_PROTO) + plat->need_firmware_load = true; + } + + return 0; +} + +#define QUPFW_PART_TYPE_GUID "21d1219f-2ed1-4ab4-930a-41a16ae75f7f" + +static int find_qupfw_part(struct udevice **blk_dev, struct disk_partition *part_info) +{ + struct blk_desc *desc; + int ret, partnum; + + uclass_foreach_dev_probe(UCLASS_BLK, *blk_dev) { + if (device_get_uclass_id(*blk_dev) != UCLASS_BLK) + continue; + + desc = dev_get_uclass_plat(*blk_dev); + if (!desc || desc->part_type == PART_TYPE_UNKNOWN) + continue; + for (partnum = 1;; partnum++) { + ret = part_get_info(desc, partnum, part_info); + if (ret) + break; + if (!strcmp(part_info->type_guid, QUPFW_PART_TYPE_GUID)) + return 0; + } + } + + return -ENOENT; +} + +static int probe_children_load_firmware(struct udevice *dev) +{ + struct geni_se_plat *plat; + ofnode child; + struct udevice *child_dev; + struct resource res; + u32 proto; + int ret; + + plat = dev_get_plat(dev); + + dev_for_each_subnode(child, dev) { + if (!ofnode_is_enabled(child)) + continue; + + if (ofnode_read_resource(child, 0, &res)) + continue; + + proto = readl(res.start + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + + if (proto != GENI_SE_INVALID_PROTO) + continue; + + ret = 0; + /* Find the device for this ofnode, or bind it */ + if (device_find_global_by_ofnode(child, &child_dev)) + ret = lists_bind_fdt(dev, child, &child_dev, NULL, false); + if (ret) { + /* Skip nodes that don't have drivers */ + debug("Failed to probe child %s: %d\n", ofnode_get_name(child), ret); + continue; + } + debug("Probing child %s for fw loading\n", child_dev->name); + device_probe(child_dev); + } + + return 0; +} + +#define MAX_FW_BUF_SIZE (128 * 1024) + +/* + * Load firmware for QCOM GENI peripherals from the dedicated partition on storage and bind/probe + * all the peripheral devices that need firmware to be loaded. + */ +static int qcom_geni_fw_initialise(void) +{ + debug("Loading firmware for QCOM GENI SE\n"); + struct udevice *geni_wrapper, *blk_dev; + struct disk_partition part_info; + int ret; + void *fw_buf; + size_t fw_size = MAX_FW_BUF_SIZE; + struct geni_se_plat *plat; + + /* Find the first GENI SE wrapper that needs fw loading */ + for (uclass_first_device(UCLASS_MISC, &geni_wrapper); + geni_wrapper; + uclass_next_device(&geni_wrapper)) { + if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC && + !strcmp(geni_wrapper->driver->name, "geni-se-qup")) { + plat = dev_get_plat(geni_wrapper); + if (plat->need_firmware_load) + break; + } + } + if (!geni_wrapper) { + pr_err("GENI SE wrapper not found\n"); + return 0; + } + + ret = find_qupfw_part(&blk_dev, &part_info); + if (ret) { + pr_err("QUP firmware partition not found\n"); + return 0; + } + + if (part_info.size * part_info.blksz > MAX_FW_BUF_SIZE) { + pr_err("Firmware partition too large\n"); + return -EINVAL; + } + fw_size = part_info.size * part_info.blksz; + + fw_buf = malloc(fw_size); + if (!fw_buf) { + pr_err("Failed to allocate buffer for firmware\n"); + return -ENOMEM; + } + memset(fw_buf, 0, fw_size); + + ret = blk_read(blk_dev, part_info.start, part_info.size, fw_buf); + if (ret < 0) { + pr_err("Failed to read firmware from partition\n"); + free(fw_buf); + return 0; + } + + /* + * OK! Firmware is loaded, now bind and probe remaining children. They will attempt to load + * firmware during probe. Do this for each GENI SE wrapper that needs firmware loading. + */ + for (; geni_wrapper; + uclass_next_device(&geni_wrapper)) { + if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC && + !strcmp(geni_wrapper->driver->name, "geni-se-qup")) { + plat = dev_get_plat(geni_wrapper); + if (plat->need_firmware_load) { + dev_set_priv(geni_wrapper, fw_buf); + probe_children_load_firmware(geni_wrapper); + } + } + } + + return 0; +} + +EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qcom_geni_fw_initialise); + +static const struct udevice_id geni_ids[] = { + { .compatible = "qcom,geni-se-qup" }, + {} +}; + +U_BOOT_DRIVER(geni_se_qup) = { + .name = "geni-se-qup", + .id = UCLASS_MISC, + .of_match = geni_ids, + .of_to_plat = geni_se_of_to_plat, + .plat_auto = sizeof(struct geni_se_plat), + .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 650612fd17f..e33f61b024a 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1001,6 +1001,7 @@ config MSM_SERIAL config MSM_GENI_SERIAL bool "Qualcomm on-chip GENI UART" + depends on QCOM_GENI help Support UART based on Generic Interface (GENI) Serial Engine (SE), used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c index 0eb90f82a34..1ab097f1356 100644 --- a/drivers/serial/serial_msm_geni.c +++ b/drivers/serial/serial_msm_geni.c @@ -605,19 +605,6 @@ U_BOOT_DRIVER(serial_msm_geni) = { .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, }; -static const struct udevice_id geniqup_ids[] = { - { .compatible = "qcom,geni-se-qup" }, - { } -}; - -U_BOOT_DRIVER(geni_se_qup) = { - .name = "geni-se-qup", - .id = UCLASS_NOP, - .of_match = geniqup_ids, - .bind = dm_scan_fdt_dev, - .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, -}; - #ifdef CONFIG_DEBUG_UART_MSM_GENI static struct msm_serial_data init_serial_data = { diff --git a/include/soc/qcom/geni-se.h b/include/soc/qcom/geni-se.h index 698a9256d26..fc9a8e82cd8 100644 --- a/include/soc/qcom/geni-se.h +++ b/include/soc/qcom/geni-se.h @@ -6,6 +6,13 @@ #ifndef _QCOM_GENI_SE #define _QCOM_GENI_SE +enum geni_se_xfer_mode { + GENI_SE_INVALID, + GENI_SE_FIFO, + GENI_SE_DMA, + GENI_GPI_DMA, +}; + /* Protocols supported by GENI Serial Engines */ enum geni_se_protocol_type { GENI_SE_NONE, @@ -14,6 +21,7 @@ enum geni_se_protocol_type { GENI_SE_I2C, GENI_SE_I3C, GENI_SE_SPI_SLAVE, + GENI_SE_INVALID_PROTO = 255, }; #define QUP_HW_VER_REG 0x4 @@ -29,6 +37,7 @@ enum geni_se_protocol_type { #define GENI_SER_S_CLK_CFG 0x4c #define GENI_IF_DISABLE_RO 0x64 #define GENI_FW_REVISION_RO 0x68 +#define GENI_DFS_IF_CFG 0x80 #define SE_GENI_CLK_SEL 0x7c #define SE_GENI_CFG_SEQ_START 0x84 #define SE_GENI_BYTE_GRAN 0x254 @@ -57,15 +66,24 @@ enum geni_se_protocol_type { #define SE_GENI_IOS 0x908 #define SE_DMA_TX_IRQ_STAT 0xc40 #define SE_DMA_TX_IRQ_CLR 0xc44 +#define SE_DMA_TX_IRQ_EN_SET 0xc4c #define SE_DMA_TX_FSM_RST 0xc58 #define SE_DMA_RX_IRQ_STAT 0xd40 #define SE_DMA_RX_IRQ_CLR 0xd44 +#define SE_DMA_RX_IRQ_EN_SET 0xd4c #define SE_DMA_RX_LEN_IN 0xd54 #define SE_DMA_RX_FSM_RST 0xd58 #define SE_GSI_EVENT_EN 0xe18 #define SE_IRQ_EN 0xe1c #define SE_HW_PARAM_0 0xe24 #define SE_HW_PARAM_1 0xe28 +#define SE_DMA_GENERAL_CFG 0xe30 + +/* GENI_DFS_IF_CFG fields */ +#define DFS_IF_EN BIT(0) + +/* SE_DMA_RX_IRQ_EN_SET fields */ +#define RESET_DONE_EN_SET BIT(3) /* GENI_FORCE_DEFAULT_REG fields */ #define FORCE_DEFAULT BIT(0) @@ -262,4 +280,22 @@ enum geni_se_protocol_type { /* QUP SE VERSION value for major number 2 and minor number 5 */ #define QUP_SE_VERSION_2_5 0x20050000 +/* SE_DMA_GENERAL_CFG */ +#define DMA_RX_CLK_CGC_ON BIT(0) +#define DMA_TX_CLK_CGC_ON BIT(1) +#define DMA_AHB_SLV_CFG_ON BIT(2) +#define AHB_SEC_SLV_CLK_CGC_ON BIT(3) +#define DUMMY_RX_NON_BUFFERABLE BIT(4) +#define RX_DMA_ZERO_PADDING_EN BIT(5) +#define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6) +#define RX_DMA_IRQ_DELAY_SHFT 6 + +#define GENI_SE_DMA_DONE_EN BIT(0) +#define GENI_SE_DMA_EOT_EN BIT(1) +#define GENI_SE_DMA_AHB_ERR_EN BIT(2) + +#define GENI_SE_DMA_EOT_BUF BIT(0) + +#define GENI_DMA_MODE_EN BIT(0) + #endif diff --git a/include/soc/qcom/qup-fw-load.h b/include/soc/qcom/qup-fw-load.h new file mode 100644 index 00000000000..a67a93c72a4 --- /dev/null +++ b/include/soc/qcom/qup-fw-load.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef _LINUX_QCOM_QUP_FW_LOAD +#define _LINUX_QCOM_QUP_FW_LOAD + +#include + +/*Magic numbers*/ +#define MAGIC_NUM_SE 0x57464553 + +/* Common SE registers*/ +#define GENI_INIT_CFG_REVISION 0x0 +#define GENI_S_INIT_CFG_REVISION 0x4 +#define GENI_FORCE_DEFAULT_REG 0x20 +#define GENI_CGC_CTRL 0x28 +#define GENI_CFG_REG0 0x100 + +#define QUPV3_SE_HW_PARAM_1 0xE28 +#define RX_FIFO_WIDTH_BIT 24 +#define RX_FIFO_WIDTH_MASK 0x3F + +/*Same registers as GENI_DMA_MODE_EN*/ +#define QUPV3_SE_GENI_DMA_MODE_EN 0x258 +#define GENI_M_IRQ_ENABLE 0x614 +#define GENI_S_IRQ_ENABLE 0x644 +#define GENI_RX_RFR_WATERMARK_REG 0x814 +#define DMA_TX_IRQ_EN_SET 0xC4C +#define DMA_RX_IRQ_EN_SET 0xD4C +#define DMA_GENERAL_CFG 0xE30 +#define SE_GENI_FW_REVISION 0x1000 +#define SE_S_FW_REVISION 0x1004 +#define SE_GENI_CFG_RAMN 0x1010 +#define SE_GENI_CLK_CTRL 0x2000 +#define SE_DMA_IF_EN 0x2004 +#define SE_FIFO_IF_DISABLE 0x2008 + +#define MAX_GENI_CFG_RAMn_CNT 455 + +#define MI_PBT_NON_PAGED_SEGMENT 0x0 +#define MI_PBT_HASH_SEGMENT 0x2 +#define MI_PBT_NOTUSED_SEGMENT 0x3 +#define MI_PBT_SHARED_SEGMENT 0x4 +#define MI_PBT_FLAG_PAGE_MODE_MASK 0x100000 +#define MI_PBT_FLAG_PAGE_MODE_SHIFT 0x14 +#define MI_PBT_FLAG_SEGMENT_TYPE_MASK 0x7000000 +#define MI_PBT_FLAG_SEGMENT_TYPE_SHIFT 0x18 +#define MI_PBT_FLAG_ACCESS_TYPE_MASK 0xE00000 +#define MI_PBT_FLAG_ACCESS_TYPE_SHIFT 0x15 + +#define MI_PBT_PAGE_MODE_VALUE(x) \ + (((x) & MI_PBT_FLAG_PAGE_MODE_MASK) >> \ + MI_PBT_FLAG_PAGE_MODE_SHIFT) + +#define MI_PBT_SEGMENT_TYPE_VALUE(x) \ + (((x) & MI_PBT_FLAG_SEGMENT_TYPE_MASK) >> \ + MI_PBT_FLAG_SEGMENT_TYPE_SHIFT) + +#define MI_PBT_ACCESS_TYPE_VALUE(x) \ + (((x) & MI_PBT_FLAG_ACCESS_TYPE_MASK) >> \ + MI_PBT_FLAG_ACCESS_TYPE_SHIFT) + +/* GENI_FORCE_DEFAULT_REG fields */ +#define FORCE_DEFAULT BIT(0) + +/* FW_REVISION_RO fields */ +#define FW_REV_PROTOCOL_SHFT 8 +#define FW_REV_VERSION_SHFT 0 + +#define GENI_FW_REVISION_RO 0x68 +#define GENI_S_FW_REVISION_RO 0x6C + +/* SE_GENI_DMA_MODE_EN */ +#define GENI_DMA_MODE_EN BIT(0) + +/* GENI_M_IRQ_EN fields */ +#define M_CMD_DONE_EN BIT(0) +#define M_IO_DATA_DEASSERT_EN BIT(22) +#define M_IO_DATA_ASSERT_EN BIT(23) +#define M_RX_FIFO_RD_ERR_EN BIT(24) +#define M_RX_FIFO_WR_ERR_EN BIT(25) +#define M_RX_FIFO_WATERMARK_EN BIT(26) +#define M_RX_FIFO_LAST_EN BIT(27) +#define M_TX_FIFO_RD_ERR_EN BIT(28) +#define M_TX_FIFO_WR_ERR_EN BIT(29) +#define M_TX_FIFO_WATERMARK_EN BIT(30) +#define M_COMMON_GENI_M_IRQ_EN (GENMASK(6, 1) | \ + M_IO_DATA_DEASSERT_EN | \ + M_IO_DATA_ASSERT_EN | M_RX_FIFO_RD_ERR_EN | \ + M_RX_FIFO_WR_ERR_EN | M_TX_FIFO_RD_ERR_EN | \ + M_TX_FIFO_WR_ERR_EN) + +/* GENI_S_IRQ_EN fields */ +#define S_CMD_OVERRUN_EN BIT(1) +#define S_ILLEGAL_CMD_EN BIT(2) +#define S_CMD_CANCEL_EN BIT(4) +#define S_CMD_ABORT_EN BIT(5) +#define S_GP_IRQ_0_EN BIT(9) +#define S_GP_IRQ_1_EN BIT(10) +#define S_GP_IRQ_2_EN BIT(11) +#define S_GP_IRQ_3_EN BIT(12) +#define S_RX_FIFO_RD_ERR_EN BIT(24) +#define S_RX_FIFO_WR_ERR_EN BIT(25) +#define S_COMMON_GENI_S_IRQ_EN (GENMASK(5, 1) | GENMASK(13, 9) | \ + S_RX_FIFO_RD_ERR_EN | S_RX_FIFO_WR_ERR_EN) + +#define GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK 0x00000200 +#define GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK 0x00000100 + +#define GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK 0x00000001 + +#define DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK 0x00000008 +#define DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK 0x00000004 +#define DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK 0x00000001 + +#define DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK 0x00000010 +#define DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK 0x00000008 +#define DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK 0x00000004 +#define DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK 0x00000001 + +#define DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK 0x00000008 +#define DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK 0x00000004 +#define DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK 0x00000002 +#define DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK 0x00000001 + +#define GENI_CLK_CTRL_SER_CLK_SEL_BMSK 0x00000001 +#define DMA_IF_EN_DMA_IF_EN_BMSK 0x00000001 +#define SE_GSI_EVENT_EN_BMSK 0x0000000f +#define SE_IRQ_EN_RMSK 0x0000000f + +#define QUPV3_COMMON_CFG 0x0120 +#define FAST_SWITCH_TO_HIGH_DISABLE_BMASK 0x00000001 + +#define QUPV3_SE_AHB_M_CFG 0x0118 +#define AHB_M_CLK_CGC_ON_BMASK 0x00000001 + +#define QUPV3_COMMON_CGC_CTRL 0x021C +#define COMMON_CSR_SLV_CLK_CGC_ON_BMASK 0x00000001 + +/* access ports */ +#define geni_setbits32(_addr, _v) writel_relaxed(readl_relaxed(_addr) | (_v), (_addr)) +#define geni_clrbits32(_addr, _v) writel_relaxed(readl_relaxed(_addr) & ~(_v), (_addr)) + +/** + * struct elf_se_hdr - firmware configurations + * + * @magic: set to 'SEFW' + * @version: A 32-bit value indicating the structure’s version number + * @core_version: QUPV3_HW_VERSION + * @serial_protocol: Programmed into GENI_FW_REVISION + * @fw_version: Programmed into GENI_FW_REVISION + * @cfg_version: Programmed into GENI_INIT_CFG_REVISION + * @fw_size_in_items: Number of (uint32_t) GENI_FW_RAM words + * @fw_offset: Byte offset of GENI_FW_RAM array + * @cfg_size_in_items: Number of GENI_FW_CFG index/value pairs + * @cfg_idx_offset: Byte offset of GENI_FW_CFG index array + * @cfg_val_offset: Byte offset of GENI_FW_CFG values array + */ +struct elf_se_hdr { + u32 magic; + u32 version; + u32 core_version; + u16 serial_protocol; + u16 fw_version; + u16 cfg_version; + u16 fw_size_in_items; + u16 fw_offset; + u16 cfg_size_in_items; + u16 cfg_idx_offset; + u16 cfg_val_offset; +}; + +struct udevice; + +int qcom_geni_load_firmware(phys_addr_t qup_base, struct udevice *dev); + +#endif /* _LINUX_QCOM_QUP_FW_LOAD */ -- cgit v1.2.3 From 10f28bc7ae0ca039970f760493fb8719300f0479 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 14 Jul 2025 15:13:15 +0200 Subject: i2c: geni: load firmware if required Load firmware for the peripheral if necessary. Signed-off-by: Casey Connolly Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20250714-geni-load-fw-v5-4-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- drivers/i2c/geni_i2c.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c index 4eb41ba852f..d29e00fdf41 100644 --- a/drivers/i2c/geni_i2c.c +++ b/drivers/i2c/geni_i2c.c @@ -22,6 +22,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN 0x26c #define SE_I2C_RX_TRANS_LEN 0x270 @@ -499,6 +500,13 @@ static int geni_i2c_probe(struct udevice *dev) proto &= FW_REV_PROTOCOL_MSK; proto >>= FW_REV_PROTOCOL_SHFT; + if (proto == GENI_SE_INVALID_PROTO) { + qcom_geni_load_firmware(geni->base, dev); + proto = readl(geni->base + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + } + if (proto != GENI_SE_I2C) { dev_err(dev, "Invalid proto %d\n", proto); geni_i2c_disable_clocks(dev, geni); -- cgit v1.2.3 From 9887944c4fa44cab668626b8e9d07a18f41e4246 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 14 Jul 2025 15:13:16 +0200 Subject: clk/qcom: sc7280: add uart5 and uart7 clocks Allow us to power up UART7 so we can load the QUP firmware, this is used for bluetooth on RB3 Gen 2 and possibly other boards. Additionally add the UART5 clocks so we can adjust baud rate for UART Signed-off-by: Casey Connolly Link: https://patch.msgid.link/20250714-geni-load-fw-v5-5-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- drivers/clk/qcom/clock-sc7280.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 47e0ca5f0e5..55a233df394 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -38,6 +38,22 @@ static const struct freq_tbl ftbl_gcc_usb30_sec_master_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(52174000, CFG_CLK_SRC_GPLL0, 1, 2, 23), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + { } +}; + static ulong sc7280_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -47,6 +63,16 @@ 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_S5_CLK: /* UART5 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x17600, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; + case GCC_QUPV3_WRAP0_S7_CLK: /* UART7 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x17860, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; case GCC_USB30_PRIM_MASTER_CLK: freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, @@ -107,6 +133,8 @@ static const struct gate_clk sc7280_clks[] = { 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_S3_CLK, 0x52008, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x52008, BIT(17)), 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)), -- cgit v1.2.3 From c57419811a90049fda071c0c7c299045b5ef4d11 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 14 Jul 2025 15:13:17 +0200 Subject: serial: msm-geni: Enable SE clk in probe Enable the serial engine clk in probe so that this driver can work on platforms that don't already initialize the clk for this device before this driver runs. This fixes a problem I see on Coreboot platforms like Trogdor where the UART hardware isn't enabled by coreboot unless the serial console build is used. Signed-off-by: Stephen Boyd Link: https://patch.msgid.link/20250714-geni-load-fw-v5-6-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm_geni.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c index 1ab097f1356..9953fe20173 100644 --- a/drivers/serial/serial_msm_geni.c +++ b/drivers/serial/serial_msm_geni.c @@ -131,6 +131,7 @@ struct msm_serial_data { phys_addr_t base; u32 baud; u32 oversampling; + struct clk *se; }; unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, @@ -181,19 +182,6 @@ static int get_clk_div_rate(u32 baud, u64 sampling_rate, u32 *clk_div) return ser_clk; } -static int geni_serial_set_clock_rate(struct udevice *dev, u64 rate) -{ - struct clk *clk; - int ret; - - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - ret = clk_set_rate(clk, rate); - return ret; -} - /** * geni_se_get_tx_fifo_depth() - Get the TX fifo depth of the serial engine * @base: Pointer to the concerned serial engine. @@ -256,7 +244,7 @@ static int msm_serial_setbrg(struct udevice *dev, int baud) pr_err("%s: Couldn't get clock division rate\n", __func__); return -EINVAL; } - ret = geni_serial_set_clock_rate(dev, clk_rate); + ret = clk_set_rate(priv->se, clk_rate); if (ret < 0) { pr_err("%s: Couldn't set clock rate: %d\n", __func__, ret); return ret; @@ -561,6 +549,16 @@ static int msm_serial_probe(struct udevice *dev) { struct msm_serial_data *priv = dev_get_priv(dev); int ret; + struct clk *clk; + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + priv->se = clk; + + ret = clk_enable(clk); + if (ret) + return ret; ret = geni_set_oversampling(dev); if (ret < 0) -- cgit v1.2.3 From 3a65430b5480208d54742dfe7aa73f3c6e1169c1 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 14 Jul 2025 15:13:18 +0200 Subject: serial: msm-geni: implement firmware loading Teach the GENI UART driver to load firmware, similar to i2c. This is primarily intended for non-debug UARTs, but since we don't support using these as the console we abort probe for now. Remove duplicated register macros that are in the common geni-se header. Signed-off-by: Casey Connolly Link: https://patch.msgid.link/20250714-geni-load-fw-v5-7-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- drivers/serial/serial_msm_geni.c | 68 ++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c index 9953fe20173..bb5a2cb4d2c 100644 --- a/drivers/serial/serial_msm_geni.c +++ b/drivers/serial/serial_msm_geni.c @@ -10,11 +10,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #define UART_OVERSAMPLING 32 #define STALE_TIMEOUT 160 @@ -22,8 +25,6 @@ /* Registers*/ #define GENI_FORCE_DEFAULT_REG 0x20 #define GENI_SER_M_CLK_CFG 0x48 -#define GENI_SER_S_CLK_CFG 0x4C -#define SE_HW_PARAM_0 0xE24 #define SE_GENI_STATUS 0x40 #define SE_GENI_S_CMD0 0x630 #define SE_GENI_S_CMD_CTRL_REG 0x634 @@ -39,7 +40,6 @@ #define SE_GENI_RX_FIFOn 0x780 #define SE_GENI_TX_FIFO_STATUS 0x800 #define SE_GENI_RX_FIFO_STATUS 0x804 -#define SE_GENI_TX_WATERMARK_REG 0x80C #define SE_GENI_TX_PACKING_CFG0 0x260 #define SE_GENI_TX_PACKING_CFG1 0x264 #define SE_GENI_RX_PACKING_CFG0 0x284 @@ -54,59 +54,24 @@ #define SE_UART_RX_TRANS_CFG 0x280 #define SE_UART_RX_PARITY_CFG 0x2a8 -#define M_TX_FIFO_WATERMARK_EN (BIT(30)) #define DEF_TX_WM 2 /* GENI_FORCE_DEFAULT_REG fields */ -#define FORCE_DEFAULT (BIT(0)) - -#define S_CMD_ABORT_EN (BIT(5)) #define UART_START_READ 0x1 -/* GENI_M_CMD_CTRL_REG */ -#define M_GENI_CMD_CANCEL (BIT(2)) -#define M_GENI_CMD_ABORT (BIT(1)) -#define M_GENI_DISABLE (BIT(0)) - -#define M_CMD_ABORT_EN (BIT(5)) -#define M_CMD_DONE_EN (BIT(0)) #define M_CMD_DONE_DISABLE_MASK (~M_CMD_DONE_EN) -#define S_GENI_CMD_ABORT (BIT(1)) - -/* GENI_S_CMD0 fields */ -#define S_OPCODE_MSK (GENMASK(31, 27)) -#define S_PARAMS_MSK (GENMASK(26, 0)) - -/* GENI_STATUS fields */ -#define M_GENI_CMD_ACTIVE (BIT(0)) -#define S_GENI_CMD_ACTIVE (BIT(12)) -#define M_CMD_DONE_EN (BIT(0)) -#define S_CMD_DONE_EN (BIT(0)) - #define M_OPCODE_SHIFT 27 #define S_OPCODE_SHIFT 27 -#define M_TX_FIFO_WATERMARK_EN (BIT(30)) #define UART_START_TX 0x1 #define UART_CTS_MASK (BIT(1)) -#define M_SEC_IRQ_EN (BIT(31)) #define TX_FIFO_WC_MSK (GENMASK(27, 0)) -#define RX_FIFO_WC_MSK (GENMASK(24, 0)) - -#define S_RX_FIFO_WATERMARK_EN (BIT(26)) -#define S_RX_FIFO_LAST_EN (BIT(27)) -#define M_RX_FIFO_WATERMARK_EN (BIT(26)) -#define M_RX_FIFO_LAST_EN (BIT(27)) /* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */ -#define SER_CLK_EN (BIT(0)) -#define CLK_DIV_MSK (GENMASK(15, 4)) #define CLK_DIV_SHFT 4 /* SE_HW_PARAM_0 fields */ -#define TX_FIFO_WIDTH_MSK (GENMASK(29, 24)) #define TX_FIFO_WIDTH_SHFT 24 -#define TX_FIFO_DEPTH_MSK (GENMASK(21, 16)) #define TX_FIFO_DEPTH_SHFT 16 /* GENI SE QUP Registers */ @@ -549,6 +514,7 @@ static int msm_serial_probe(struct udevice *dev) { struct msm_serial_data *priv = dev_get_priv(dev); int ret; + u32 proto; struct clk *clk; clk = devm_clk_get(dev, NULL); @@ -556,7 +522,32 @@ static int msm_serial_probe(struct udevice *dev) return PTR_ERR(clk); priv->se = clk; + /* Try enable clock */ ret = clk_enable(clk); + + /* Check if firmware loading is needed (BT UART) */ + proto = readl(priv->base + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + + if (proto == GENI_SE_INVALID_PROTO) { + qcom_geni_load_firmware(priv->base, dev); + proto = readl(priv->base + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + } + + if (proto != GENI_SE_UART) { + dev_err(dev, "Invalid proto %d\n", proto); + clk_disable(clk); + return -ENXIO; + } + + /* Don't actually probe non-debug UARTs */ + if (ofnode_device_is_compatible(dev_ofnode(dev), "qcom,geni-uart")) + return -ENOENT; + + /* Now handle clock enable return value */ if (ret) return ret; @@ -589,6 +580,7 @@ static int msm_serial_ofdata_to_platdata(struct udevice *dev) static const struct udevice_id msm_serial_ids[] = { { .compatible = "qcom,geni-debug-uart" }, + { .compatible = "qcom,geni-uart" }, { } }; -- cgit v1.2.3 From cd44b44e595d16e5dfa90b1f73b9f0fbb3f1c037 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Mon, 14 Jul 2025 15:13:19 +0200 Subject: configs: qcom_*: enable QCOM_GENI where needed Enable the GENI MISC driver which is required for many Qualcomm platforms. Signed-off-by: Casey Connolly Link: https://patch.msgid.link/20250714-geni-load-fw-v5-8-5abbc0d29838@linaro.org Signed-off-by: Casey Connolly --- configs/qcom_defconfig | 1 + configs/qcom_ipq5424_mmc_defconfig | 2 ++ configs/qcom_ipq9574_mmc_defconfig | 2 ++ 3 files changed, 5 insertions(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index bb795fe6608..8bdb3cf7c58 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -91,6 +91,7 @@ CONFIG_IOMMU=y CONFIG_QCOM_HYP_SMMU=y CONFIG_MISC=y CONFIG_NVMEM=y +CONFIG_QCOM_GENI=y CONFIG_I2C_EEPROM=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y diff --git a/configs/qcom_ipq5424_mmc_defconfig b/configs/qcom_ipq5424_mmc_defconfig index 3c03e367b7d..c68c66a28fb 100644 --- a/configs/qcom_ipq5424_mmc_defconfig +++ b/configs/qcom_ipq5424_mmc_defconfig @@ -33,6 +33,8 @@ CONFIG_CLK_QCOM_IPQ5424=y CONFIG_MSM_GPIO=y # CONFIG_I2C is not set # CONFIG_INPUT is not set +CONFIG_MISC=y +CONFIG_QCOM_GENI=y CONFIG_MMC_HS200_SUPPORT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y diff --git a/configs/qcom_ipq9574_mmc_defconfig b/configs/qcom_ipq9574_mmc_defconfig index b45ef504155..6592d9de39d 100644 --- a/configs/qcom_ipq9574_mmc_defconfig +++ b/configs/qcom_ipq9574_mmc_defconfig @@ -33,6 +33,8 @@ CONFIG_CLK_QCOM_IPQ9574=y CONFIG_MSM_GPIO=y # CONFIG_I2C is not set # CONFIG_INPUT is not set +CONFIG_MISC=y +CONFIG_QCOM_GENI=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y CONFIG_MMC_SDHCI_MSM=y -- cgit v1.2.3 From fef8c84b57fd305205a13984530e81af6bf81ac3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 7 Apr 2025 11:54:21 +0200 Subject: usb: host: ehci-msm: Fix pointer check dev_read_addr_ptr() returns a null pointer on error, not FDT_ADDR_T_NONE. Fixes: 2be1130a9305 ("usb: ehci-msm: Use dev interface to get device address") Signed-off-by: Stephan Gerhold Acked-by: Caleb Connolly Tested-by: Sam Day Link: https://patch.msgid.link/20250407-ehci-msm-fixes-v1-1-f8b30eb05d07@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/host/ehci-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index a759aea9db3..dd1d527a3a2 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -141,7 +141,7 @@ static int ehci_usb_of_to_plat(struct udevice *dev) priv->ulpi_vp.port_num = 0; priv->ehci = dev_read_addr_ptr(dev); - if (priv->ehci == (void *)FDT_ADDR_T_NONE) + if (!priv->ehci) return -EINVAL; /* Warning: this will not work if viewport address is > 64 bit due to -- cgit v1.2.3 From e4e47da7e876d9f184e0060e6e59ac1f57d0290d Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 7 Apr 2025 11:54:22 +0200 Subject: usb: host: echi-msm: Drop ulpi definitions These are unused. Signed-off-by: Stephan Gerhold Acked-by: Caleb Connolly Tested-by: Sam Day Link: https://patch.msgid.link/20250407-ehci-msm-fixes-v1-2-f8b30eb05d07@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/host/ehci-msm.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index dd1d527a3a2..60b2dc44d3d 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -24,7 +24,6 @@ struct msm_ehci_priv { struct ehci_ctrl ctrl; /* Needed by EHCI */ struct usb_ehci *ehci; /* Start of IP core*/ - struct ulpi_viewport ulpi_vp; /* ULPI Viewport */ struct phy phy; struct clk iface_clk; struct clk core_clk; @@ -138,17 +137,11 @@ static int ehci_usb_of_to_plat(struct udevice *dev) { struct msm_ehci_priv *priv = dev_get_priv(dev); - priv->ulpi_vp.port_num = 0; priv->ehci = dev_read_addr_ptr(dev); if (!priv->ehci) return -EINVAL; - /* Warning: this will not work if viewport address is > 64 bit due to - * ULPI design. - */ - priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint; - return 0; } -- cgit v1.2.3 From 2faabff35899a2106dc0480bd482783e906c8b7d Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 7 Apr 2025 11:54:23 +0200 Subject: usb: host: ehci-msm: Disable clocks after all register accesses We need the USB clocks to do accesses like wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, ...) so we should disable them only after all of them are done. At the moment this works only because the clock driver doesn't actually disabling these clocks in U-Boot. Fixes: 9b3a9f896e66 ("ehci: msm: bring up iface + core clocks") Signed-off-by: Stephan Gerhold Acked-by: Caleb Connolly Tested-by: Sam Day Link: https://patch.msgid.link/20250407-ehci-msm-fixes-v1-3-f8b30eb05d07@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/host/ehci-msm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 60b2dc44d3d..bf46e89104e 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -110,9 +110,6 @@ static int ehci_usb_remove(struct udevice *dev) /* Stop controller. */ clrbits_le32(&ehci->usbcmd, CMD_RUN); - clk_disable_unprepare(&p->iface_clk); - clk_disable_unprepare(&p->core_clk); - ret = generic_shutdown_phy(&p->phy); if (ret) return ret; @@ -130,6 +127,8 @@ static int ehci_usb_remove(struct udevice *dev) return -ETIMEDOUT; } + clk_disable_unprepare(&p->iface_clk); + clk_disable_unprepare(&p->core_clk); return 0; } -- cgit v1.2.3 From c45a043d8a0e1589b09ce4d630b9d6bf41cb6755 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 7 Apr 2025 11:54:24 +0200 Subject: usb: host: ehci-msm: Use clk bulk helpers The enable order for the clocks does not matter much, we just need to enable all the USB clocks. Use the clk bulk helpers to simplify the code. Signed-off-by: Stephan Gerhold Acked-by: Caleb Connolly Tested-by: Sam Day Link: https://patch.msgid.link/20250407-ehci-msm-fixes-v1-4-f8b30eb05d07@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/host/ehci-msm.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index bf46e89104e..17cfff8380c 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -25,8 +25,7 @@ struct msm_ehci_priv { struct ehci_ctrl ctrl; /* Needed by EHCI */ struct usb_ehci *ehci; /* Start of IP core*/ struct phy phy; - struct clk iface_clk; - struct clk core_clk; + struct clk_bulk clks; }; static int msm_init_after_reset(struct ehci_ctrl *dev) @@ -55,25 +54,15 @@ static int ehci_usb_probe(struct udevice *dev) struct ehci_hcor *hcor; int ret; - ret = clk_get_by_name(dev, "core", &p->core_clk); - if (ret) { - dev_err(dev, "Failed to get core clock: %d\n", ret); + ret = clk_get_bulk(dev, &p->clks); + if (ret && (ret != -ENOSYS && ret != -ENOENT)) { + dev_err(dev, "Failed to get clocks: %d\n", ret); return ret; } - ret = clk_get_by_name(dev, "iface", &p->iface_clk); - if (ret) { - dev_err(dev, "Failed to get iface clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(&p->core_clk); - if (ret) - return ret; - - ret = clk_prepare_enable(&p->iface_clk); + ret = clk_enable_bulk(&p->clks); if (ret) - goto cleanup_core; + goto cleanup_clocks; hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength); hcor = (struct ehci_hcor *)((phys_addr_t)hccr + @@ -81,19 +70,17 @@ static int ehci_usb_probe(struct udevice *dev) ret = generic_setup_phy(dev, &p->phy, 0, PHY_MODE_USB_HOST, 0); if (ret) - goto cleanup_iface; + goto cleanup_clocks; ret = board_usb_init(0, plat->init_type); if (ret < 0) - goto cleanup_iface; + goto cleanup_clocks; return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, plat->init_type); -cleanup_iface: - clk_disable_unprepare(&p->iface_clk); -cleanup_core: - clk_disable_unprepare(&p->core_clk); +cleanup_clocks: + clk_release_bulk(&p->clks); return ret; } @@ -127,8 +114,7 @@ static int ehci_usb_remove(struct udevice *dev) return -ETIMEDOUT; } - clk_disable_unprepare(&p->iface_clk); - clk_disable_unprepare(&p->core_clk); + clk_release_bulk(&p->clks); return 0; } -- cgit v1.2.3 From f5ff016b44902591520f020c77fd08e8de6fc412 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 7 Apr 2025 11:54:25 +0200 Subject: usb: host: ehci-msm: Drop redundant EHCI register writes ehci_unregister() already clears the CMD_RUN bit with more careful checks. It also ensures that we only do this in case we were actually in USB host (rather than USB device) mode. It's not clear what the extra register writes in the Qualcomm-specific ehci-msm driver are supposed to do, so just drop them. Signed-off-by: Stephan Gerhold Acked-by: Caleb Connolly Tested-by: Sam Day Link: https://patch.msgid.link/20250407-ehci-msm-fixes-v1-5-f8b30eb05d07@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/host/ehci-msm.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 17cfff8380c..659a917ad27 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -87,16 +87,12 @@ cleanup_clocks: static int ehci_usb_remove(struct udevice *dev) { struct msm_ehci_priv *p = dev_get_priv(dev); - struct usb_ehci *ehci = p->ehci; int ret; ret = ehci_deregister(dev); if (ret) return ret; - /* Stop controller. */ - clrbits_le32(&ehci->usbcmd, CMD_RUN); - ret = generic_shutdown_phy(&p->phy); if (ret) return ret; @@ -105,15 +101,6 @@ static int ehci_usb_remove(struct udevice *dev) if (ret < 0) return ret; - /* Reset controller */ - setbits_le32(&ehci->usbcmd, CMD_RESET); - - /* Wait for reset */ - if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) { - printf("Stuck on USB reset.\n"); - return -ETIMEDOUT; - } - clk_release_bulk(&p->clks); return 0; } -- cgit v1.2.3 From ed733d40ec3279fe8425becbe0552a2974051193 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 7 Apr 2025 11:54:26 +0200 Subject: usb: host: ehci-msm: Register ULPI PHY through NOP wrapper The UCLASS_USB device is removed and rebound each time you run "usb stop" followed by "usb start", or when you switch between USB device and USB host mode. Unfortunately, this causes issues with the current ehci-msm driver: In ehci_usb_remove() we call generic_shutdown_phy(), but at that point the ULPI PHY we registered in ehci_usb_of_bind() was already removed again by the DM core. Fix this by adding a UCLASS_NOP driver that keeps the PHY driver bound permanently, and then just re-probe the actual USB part. Reported-by: Jianfeng Zhu Closes: https://lore.kernel.org/u-boot/OSQPR04MB774067EBEEADD714EFE18C2A90882@OSQPR04MB7740.apcprd04.prod.outlook.com/ Signed-off-by: Stephan Gerhold Acked-by: Caleb Connolly Tested-by: Sam Day Link: https://patch.msgid.link/20250407-ehci-msm-fixes-v1-6-f8b30eb05d07@linaro.org Signed-off-by: Casey Connolly --- drivers/usb/host/ehci-msm.c | 107 +++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 42 deletions(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 659a917ad27..8aeb6a91556 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -25,6 +25,9 @@ struct msm_ehci_priv { struct ehci_ctrl ctrl; /* Needed by EHCI */ struct usb_ehci *ehci; /* Start of IP core*/ struct phy phy; +}; + +struct qcom_ci_hdrc_priv { struct clk_bulk clks; }; @@ -54,34 +57,20 @@ static int ehci_usb_probe(struct udevice *dev) struct ehci_hcor *hcor; int ret; - ret = clk_get_bulk(dev, &p->clks); - if (ret && (ret != -ENOSYS && ret != -ENOENT)) { - dev_err(dev, "Failed to get clocks: %d\n", ret); - return ret; - } - - ret = clk_enable_bulk(&p->clks); - if (ret) - goto cleanup_clocks; - hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength); hcor = (struct ehci_hcor *)((phys_addr_t)hccr + HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); ret = generic_setup_phy(dev, &p->phy, 0, PHY_MODE_USB_HOST, 0); if (ret) - goto cleanup_clocks; + return ret; ret = board_usb_init(0, plat->init_type); if (ret < 0) - goto cleanup_clocks; + return ret; return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, plat->init_type); - -cleanup_clocks: - clk_release_bulk(&p->clks); - return ret; } static int ehci_usb_remove(struct udevice *dev) @@ -101,7 +90,6 @@ static int ehci_usb_remove(struct udevice *dev) if (ret < 0) return ret; - clk_release_bulk(&p->clks); return 0; } @@ -117,24 +105,6 @@ static int ehci_usb_of_to_plat(struct udevice *dev) return 0; } -static int ehci_usb_of_bind(struct udevice *dev) -{ - ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev)); - ofnode phy_node; - - if (!ofnode_valid(ulpi_node)) - return 0; - - phy_node = ofnode_first_subnode(ulpi_node); - if (!ofnode_valid(phy_node)) { - printf("%s: ulpi subnode with no phy\n", __func__); - return -ENOENT; - } - - return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy", - phy_node, NULL); -} - #if defined(CONFIG_CI_UDC) /* Little quirk that MSM needs with Chipidea controller * Must reinit phy after reset @@ -147,17 +117,10 @@ void ci_init_after_reset(struct ehci_ctrl *ctrl) } #endif -static const struct udevice_id ehci_usb_ids[] = { - { .compatible = "qcom,ci-hdrc", }, - { } -}; - U_BOOT_DRIVER(usb_ehci) = { .name = "ehci_msm", .id = UCLASS_USB, - .of_match = ehci_usb_ids, .of_to_plat = ehci_usb_of_to_plat, - .bind = ehci_usb_of_bind, .probe = ehci_usb_probe, .remove = ehci_usb_remove, .ops = &ehci_usb_ops, @@ -165,3 +128,63 @@ U_BOOT_DRIVER(usb_ehci) = { .plat_auto = sizeof(struct usb_plat), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; + +static int qcom_ci_hdrc_probe(struct udevice *dev) +{ + struct qcom_ci_hdrc_priv *p = dev_get_priv(dev); + int ret; + + ret = clk_get_bulk(dev, &p->clks); + if (ret && (ret != -ENOSYS && ret != -ENOENT)) { + dev_err(dev, "Failed to get clocks: %d\n", ret); + return ret; + } + + return clk_enable_bulk(&p->clks); +} + +static int qcom_ci_hdrc_remove(struct udevice *dev) +{ + struct qcom_ci_hdrc_priv *p = dev_get_priv(dev); + + return clk_release_bulk(&p->clks); +} + +static int qcom_ci_hdrc_bind(struct udevice *dev) +{ + ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev)); + ofnode phy_node; + int ret; + + ret = device_bind_driver_to_node(dev, "ehci_msm", "ehci_msm", + dev_ofnode(dev), NULL); + if (ret) + return ret; + + if (!ofnode_valid(ulpi_node)) + return 0; + + phy_node = ofnode_first_subnode(ulpi_node); + if (!ofnode_valid(phy_node)) { + printf("%s: ulpi subnode with no phy\n", __func__); + return -ENOENT; + } + + return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy", + phy_node, NULL); +} + +static const struct udevice_id qcom_ci_hdrc_ids[] = { + { .compatible = "qcom,ci-hdrc", }, + { } +}; + +U_BOOT_DRIVER(qcom_ci_hdrc) = { + .name = "qcom_ci_hdrc", + .id = UCLASS_NOP, + .of_match = qcom_ci_hdrc_ids, + .bind = qcom_ci_hdrc_bind, + .probe = qcom_ci_hdrc_probe, + .remove = qcom_ci_hdrc_remove, + .priv_auto = sizeof(struct qcom_ci_hdrc_priv), +}; -- cgit v1.2.3 From 5d6042ce3fdacefb075ef22ca9e14a7d13f43eca Mon Sep 17 00:00:00 2001 From: George Chan Date: Tue, 21 Oct 2025 00:23:58 +0800 Subject: iommu: qcom-smmu: Introduce sc7180 compatible string Add basic compatible string for sc7180 family soc. Signed-off-by: Vitalii Skorkin Co-developed-by: George Chan Signed-off-by: George Chan Reviewed-by: Casey Connolly Link: https://patch.msgid.link/20251021-sc7180-minor-v1-1-9fe33c73365e@gmail.com Signed-off-by: Casey Connolly --- drivers/iommu/qcom-hyp-smmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c index 161e0b60091..5b37c21f66c 100644 --- a/drivers/iommu/qcom-hyp-smmu.c +++ b/drivers/iommu/qcom-hyp-smmu.c @@ -388,6 +388,7 @@ static struct iommu_ops qcom_smmu_ops = { }; static const struct udevice_id qcom_smmu500_ids[] = { + { .compatible = "qcom,sc7180-smmu-500" }, { .compatible = "qcom,sc7280-smmu-500" }, { .compatible = "qcom,sdm845-smmu-500" }, { .compatible = "qcom,sm6350-smmu-500" }, -- cgit v1.2.3 From 934647d49c61f9405767bd36da3bba06a40cf346 Mon Sep 17 00:00:00 2001 From: George Chan Date: Tue, 21 Oct 2025 00:23:59 +0800 Subject: usb: gadget: Introduce usb gadget vendor/product default id for ARCH_QCOM Currently vendor/product id are both 0, and that might not as we want. Set to some arbitrary known value that we can make it work more smoothly. Reviewed-by: Mattijs Korpershoek Acked-by: Mattijs Korpershoek Reviewed-by: Neil Armstrong Signed-off-by: George Chan Link: https://patch.msgid.link/20251021-sc7180-minor-v1-2-9fe33c73365e@gmail.com Signed-off-by: Casey Connolly --- drivers/usb/gadget/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e845e46e0b7..008f8c99a58 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -60,6 +60,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 0x0 help Vendor ID of the USB device emulated, reported to the host device. @@ -87,6 +88,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 0x0 help Product ID of the USB device emulated, reported to the host device. -- cgit v1.2.3