diff options
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 */ |
