summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/dts/apq8016-sbc-u-boot.dtsi9
-rw-r--r--board/qualcomm/debug-msm8953.config5
-rw-r--r--board/qualcomm/debug-qcm6490.config5
-rw-r--r--board/qualcomm/debug-qcs9100.config5
-rw-r--r--board/qualcomm/debug-sm6350.config5
-rw-r--r--configs/qcm6490_defconfig6
-rw-r--r--configs/qcom_defconfig10
-rw-r--r--configs/qcom_ipq5424_mmc_defconfig2
-rw-r--r--configs/qcom_ipq9574_mmc_defconfig2
-rw-r--r--configs/qcs9100_defconfig6
-rw-r--r--doc/board/qualcomm/debugging.rst2
-rw-r--r--drivers/clk/clk-stub.c3
-rw-r--r--drivers/clk/qcom/Kconfig15
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/clock-sc7280.c28
-rw-r--r--drivers/clk/qcom/clock-sdm845.c127
-rw-r--r--drivers/clk/qcom/clock-sm6350.c193
-rw-r--r--drivers/clk/qcom/clock-sm7150.c250
-rw-r--r--drivers/clk/qcom/clock-sm8250.c5
-rw-r--r--drivers/gpio/qcom_spmi_gpio.c4
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/geni_i2c.c14
-rw-r--r--drivers/iommu/qcom-hyp-smmu.c4
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/qcom_geni.c580
-rw-r--r--drivers/phy/qcom/Kconfig6
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-ufs.c62
-rw-r--r--drivers/pinctrl/qcom/Kconfig20
-rw-r--r--drivers/pinctrl/qcom/Makefile3
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc7280.c6
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm670.c247
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm6350.c104
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm7150.c142
-rw-r--r--drivers/power/regulator/qcom-rpmh-regulator.c31
-rw-r--r--drivers/serial/Kconfig3
-rw-r--r--drivers/serial/serial_msm.c127
-rw-r--r--drivers/serial/serial_msm_geni.c107
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/host/ehci-msm.c146
-rw-r--r--include/soc/qcom/geni-se.h36
-rw-r--r--include/soc/qcom/qup-fw-load.h178
42 files changed, 2229 insertions, 285 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;
-};
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
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/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
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/qcom_defconfig b/configs/qcom_defconfig
index 8d1269b4634..8bdb3cf7c58 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
@@ -44,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
@@ -60,6 +63,8 @@ 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_SM7150=y
CONFIG_CLK_QCOM_SM8150=y
CONFIG_CLK_QCOM_SM8250=y
CONFIG_CLK_QCOM_SM8550=y
@@ -86,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
@@ -110,8 +116,12 @@ 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
+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
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
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
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<BOARD>_defconfig``
- CONFIG_BAUDRATE=115200
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ANNOUNCE=y
# db410c - 0x78b0000
@@ -50,7 +49,6 @@ Open ``configs/dragonboard<BOARD>_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
diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c
index 5f5aca41d5b..117266ac778 100644
--- a/drivers/clk/clk-stub.c
+++ b/drivers/clk/clk-stub.c
@@ -50,8 +50,11 @@ 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,sc7180-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" },
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 34e41461e72..8504ed5d656 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -103,6 +103,21 @@ 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
+
+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
bool "Qualcomm SM8150 GCC"
select CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index b3d95b0faa3..82a5b166196 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -16,6 +16,8 @@ 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_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-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)),
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),
@@ -311,6 +434,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,
},
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 <[email protected]>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-sm6350.h>
+
+#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,
+};
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 <[email protected]>
+ * (C) Copyright 2025 Jens Reidel <[email protected]>
+ *
+ * Based on Linux Kernel driver
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,sm7150-gcc.h>
+
+#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,
+};
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),
diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c
index 22c8072534e..1a7c7c48dfc 100644
--- a/drivers/gpio/qcom_spmi_gpio.c
+++ b/drivers/gpio/qcom_spmi_gpio.c
@@ -743,6 +743,10 @@ 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,pm7325-gpio" },
{ .compatible = "qcom,pm8550-gpio" },
{ .compatible = "qcom,pm8550b-gpio" },
{ .compatible = "qcom,pm8550ve-gpio" },
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index bdd3c60118c..55465dc1d46 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -668,7 +668,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/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c
index eabf5c76c21..d29e00fdf41 100644
--- a/drivers/i2c/geni_i2c.c
+++ b/drivers/i2c/geni_i2c.c
@@ -22,6 +22,7 @@
#include <reset.h>
#include <time.h>
#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
#define SE_I2C_TX_TRANS_LEN 0x26c
#define SE_I2C_RX_TRANS_LEN 0x270
@@ -331,15 +332,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;
@@ -501,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);
diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c
index 2e51ce4f242..5b37c21f66c 100644
--- a/drivers/iommu/qcom-hyp-smmu.c
+++ b/drivers/iommu/qcom-hyp-smmu.c
@@ -388,8 +388,10 @@ static struct iommu_ops qcom_smmu_ops = {
};
static const struct udevice_id qcom_smmu500_ids[] = {
- { .compatible = "qcom,sdm845-smmu-500" },
+ { .compatible = "qcom,sc7180-smmu-500" },
{ .compatible = "qcom,sc7280-smmu-500" },
+ { .compatible = "qcom,sdm845-smmu-500" },
+ { .compatible = "qcom,sm6350-smmu-500" },
{ .compatible = "qcom,smmu-500", },
{ /* sentinel */ }
};
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 <blk.h>
+#include <part.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <elf.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <misc.h>
+#include <linux/printk.h>
+#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
+#include <dm/device_compat.h>
+
+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/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.
diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c
index f3c606847fb..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,
@@ -1593,6 +1653,8 @@ 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,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 },
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 21f81b66099..320aba33347 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
@@ -89,6 +96,19 @@ 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,
+
+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
bool "Qualcomm SM8150 Pinctrl"
select PINCTRL_QCOM
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 6cb53838e71..06582ac2068 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -13,8 +13,11 @@ 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_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-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),
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 <[email protected]>
+ */
+
+#include <dm.h>
+#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,
+};
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 <[email protected]>
+ *
+ */
+
+#include <dm.h>
+
+#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,
+};
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 <[email protected]>
+ * (C) Copyright 2025 Jens Reidel <[email protected]>
+ *
+ * Based on Linux Kernel driver
+ */
+
+#include <dm.h>
+
+#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,
+};
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"),
{}
@@ -706,6 +733,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,
},
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index bc05d2f1508..e33f61b024a 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
@@ -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.c b/drivers/serial/serial_msm.c
index 757e5eaf974..18d15b7b15b 100644
--- a/drivers/serial/serial_msm.c
+++ b/drivers/serial/serial_msm.c
@@ -17,20 +17,17 @@
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/compiler.h>
-#include <linux/delay.h>
#include <dm/pinctrl.h>
/* 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
+#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
@@ -44,119 +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_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_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_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)
+#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 = {
@@ -207,8 +141,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");
@@ -221,13 +153,16 @@ 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);
- /* 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);
+ 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)
{
@@ -319,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);
}
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index 0eb90f82a34..bb5a2cb4d2c 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -10,11 +10,14 @@
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <errno.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <misc.h>
#include <serial.h>
+#include <soc/qcom/qup-fw-load.h>
+#include <soc/qcom/geni-se.h>
#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 */
@@ -131,6 +96,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 +147,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 +209,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 +514,42 @@ 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);
+ if (IS_ERR(clk))
+ 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;
ret = geni_set_oversampling(dev);
if (ret < 0)
@@ -591,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" },
{ }
};
@@ -605,19 +595,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/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.
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index a759aea9db3..8aeb6a91556 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -24,10 +24,11 @@
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;
+};
+
+struct qcom_ci_hdrc_priv {
+ struct clk_bulk clks;
};
static int msm_init_after_reset(struct ehci_ctrl *dev)
@@ -56,64 +57,31 @@ 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);
- 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);
- if (ret)
- goto cleanup_core;
-
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_iface;
+ return ret;
ret = board_usb_init(0, plat->init_type);
if (ret < 0)
- goto cleanup_iface;
+ return ret;
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);
- return ret;
}
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);
-
- clk_disable_unprepare(&p->iface_clk);
- clk_disable_unprepare(&p->core_clk);
-
ret = generic_shutdown_phy(&p->phy);
if (ret)
return ret;
@@ -122,15 +90,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;
- }
-
return 0;
}
@@ -138,38 +97,14 @@ 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 == (void *)FDT_ADDR_T_NONE)
+ 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;
}
-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
@@ -182,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,
@@ -200,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),
+};
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 <linux/kernel.h>
+
+/*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 */