summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2024-01-16 09:51:16 -0500
committerTom Rini <[email protected]>2024-01-16 09:51:16 -0500
commit043ca8c8a9b181cf6f17441e9b89b5ee33206309 (patch)
tree7971baea0d859a44a15339ffc505e07dddc44956 /drivers
parent6ca9349b6723dbb00385ca9c04e6478d4a03b109 (diff)
parent4c3dfa1b8babf9fc0575ce08eed99f950d3bab84 (diff)
Merge tag 'qcom-2024.04-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-snapdragon
Qualcomm architecture changes: * Move clock and pinctrl drivers out of mach-snapdragon * Various clock driver improvements * Convert PMIC power/reset key driver to use the button API * Preparetory work for migrating to upstream DT
Diffstat (limited to 'drivers')
-rw-r--r--drivers/button/Kconfig9
-rw-r--r--drivers/button/Makefile1
-rw-r--r--drivers/button/button-qcom-pmic.c165
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/qcom/Kconfig52
-rw-r--r--drivers/clk/qcom/Makefile10
-rw-r--r--drivers/clk/qcom/clock-apq8016.c160
-rw-r--r--drivers/clk/qcom/clock-apq8096.c138
-rw-r--r--drivers/clk/qcom/clock-ipq4019.c (renamed from drivers/reset/reset-qcom.c)160
-rw-r--r--drivers/clk/qcom/clock-qcom.c307
-rw-r--r--drivers/clk/qcom/clock-qcom.h100
-rw-r--r--drivers/clk/qcom/clock-qcs404.c362
-rw-r--r--drivers/clk/qcom/clock-sdm845.c187
-rw-r--r--drivers/gpio/Kconfig5
-rw-r--r--drivers/gpio/msm_gpio.c42
-rw-r--r--drivers/gpio/qcom_pmic_gpio.c138
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/qcom-geni-se.c41
-rw-r--r--drivers/pinctrl/Kconfig1
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/qcom/Kconfig46
-rw-r--r--drivers/pinctrl/qcom/Makefile10
-rw-r--r--drivers/pinctrl/qcom/pinctrl-apq8016.c76
-rw-r--r--drivers/pinctrl/qcom/pinctrl-apq8096.c71
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ipq4019.c67
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.c180
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.h35
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcs404.c83
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm845.c100
-rw-r--r--drivers/power/pmic/pmic_qcom.c15
-rw-r--r--drivers/reset/Kconfig7
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/serial_msm_geni.c38
-rw-r--r--drivers/spmi/spmi-msm.c46
37 files changed, 2330 insertions, 336 deletions
diff --git a/drivers/button/Kconfig b/drivers/button/Kconfig
index 8ce2de37d62..097b05f822e 100644
--- a/drivers/button/Kconfig
+++ b/drivers/button/Kconfig
@@ -27,4 +27,13 @@ config BUTTON_GPIO
The GPIO driver must used driver model. Buttons are configured using
the device tree.
+config BUTTON_QCOM_PMIC
+ bool "Qualcomm power button"
+ depends on BUTTON
+ depends on PMIC_QCOM
+ help
+ Enable support for the power and "resin" (usually volume down) buttons
+ on Qualcomm SoCs. These will be configured as the Enter and Down keys
+ respectively, allowing navigation of bootmenu with buttons on device.
+
endmenu
diff --git a/drivers/button/Makefile b/drivers/button/Makefile
index bbd18af1494..68555081a47 100644
--- a/drivers/button/Makefile
+++ b/drivers/button/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_BUTTON) += button-uclass.o
obj-$(CONFIG_BUTTON_ADC) += button-adc.o
obj-$(CONFIG_BUTTON_GPIO) += button-gpio.o
+obj-$(CONFIG_BUTTON_QCOM_PMIC) += button-qcom-pmic.o \ No newline at end of file
diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c
new file mode 100644
index 00000000000..34a976d1e6c
--- /dev/null
+++ b/drivers/button/button-qcom-pmic.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm generic pmic gpio driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ * (C) Copyright 2023 Linaro Ltd.
+ */
+
+#include <button.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+#include <linux/bitops.h>
+
+#define REG_TYPE 0x4
+#define REG_SUBTYPE 0x5
+
+struct qcom_pmic_btn_priv {
+ u32 base;
+ u32 status_bit;
+ int code;
+ struct udevice *pmic;
+};
+
+#define PON_INT_RT_STS 0x10
+#define KPDPWR_ON_INT_BIT 0
+#define RESIN_ON_INT_BIT 1
+
+#define NODE_IS_PWRKEY(node) (!strncmp(ofnode_get_name(node), "pwrkey", strlen("pwrkey")))
+#define NODE_IS_RESIN(node) (!strncmp(ofnode_get_name(node), "resin", strlen("resin")))
+
+static enum button_state_t qcom_pwrkey_get_state(struct udevice *dev)
+{
+ struct qcom_pmic_btn_priv *priv = dev_get_priv(dev);
+
+ int reg = pmic_reg_read(priv->pmic, priv->base + PON_INT_RT_STS);
+
+ if (reg < 0)
+ return 0;
+
+ return (reg & BIT(priv->status_bit)) != 0;
+}
+
+static int qcom_pwrkey_get_code(struct udevice *dev)
+{
+ struct qcom_pmic_btn_priv *priv = dev_get_priv(dev);
+
+ return priv->code;
+}
+
+static int qcom_pwrkey_probe(struct udevice *dev)
+{
+ struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+ struct qcom_pmic_btn_priv *priv = dev_get_priv(dev);
+ ofnode node = dev_ofnode(dev);
+ int ret;
+ u64 base;
+
+ /* Ignore the top-level pon node */
+ if (!uc_plat->label)
+ return 0;
+
+ /* the pwrkey and resin nodes are children of the "pon" node, get the
+ * PMIC device to use in pmic_reg_* calls.
+ */
+ priv->pmic = dev->parent->parent;
+
+ /* Get the address of the parent pon node */
+ base = dev_read_addr(dev->parent);
+ if (base == FDT_ADDR_T_NONE) {
+ printf("%s: Can't find address\n", dev->name);
+ return -EINVAL;
+ }
+
+ priv->base = base;
+
+ /* Do a sanity check */
+ ret = pmic_reg_read(priv->pmic, priv->base + REG_TYPE);
+ if (ret != 0x1 && ret != 0xb) {
+ printf("%s: unexpected PMIC function type %d\n", dev->name, ret);
+ return -ENXIO;
+ }
+
+ ret = pmic_reg_read(priv->pmic, priv->base + REG_SUBTYPE);
+ if ((ret & 0x7) == 0) {
+ printf("%s: unexpected PMCI function subtype %d\n", dev->name, ret);
+ return -ENXIO;
+ }
+
+ if (NODE_IS_PWRKEY(node)) {
+ priv->status_bit = 0;
+ priv->code = KEY_ENTER;
+ } else if (NODE_IS_RESIN(node)) {
+ priv->status_bit = 1;
+ priv->code = KEY_DOWN;
+ } else {
+ /* Should not get here! */
+ printf("Invalid pon node '%s' should be 'pwrkey' or 'resin'\n",
+ ofnode_get_name(node));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int button_qcom_pmic_bind(struct udevice *parent)
+{
+ struct udevice *dev;
+ ofnode node;
+ int ret;
+
+ dev_for_each_subnode(node, parent) {
+ struct button_uc_plat *uc_plat;
+ const char *label;
+
+ if (!ofnode_is_enabled(node))
+ continue;
+
+ ret = device_bind_driver_to_node(parent, "qcom_pwrkey",
+ ofnode_get_name(node),
+ node, &dev);
+ if (ret) {
+ printf("Failed to bind %s! %d\n", label, ret);
+ return ret;
+ }
+ uc_plat = dev_get_uclass_plat(dev);
+ if (NODE_IS_PWRKEY(node)) {
+ uc_plat->label = "pwrkey";
+ } else if (NODE_IS_RESIN(node)) {
+ uc_plat->label = "vol_down";
+ } else {
+ printf("Unknown button node '%s' should be 'pwrkey' or 'resin'\n",
+ ofnode_get_name(node));
+ device_unbind(dev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct button_ops button_qcom_pmic_ops = {
+ .get_state = qcom_pwrkey_get_state,
+ .get_code = qcom_pwrkey_get_code,
+};
+
+static const struct udevice_id qcom_pwrkey_ids[] = {
+ { .compatible = "qcom,pm8916-pon" },
+ { .compatible = "qcom,pm8941-pon" },
+ { .compatible = "qcom,pm8998-pon" },
+ { }
+};
+
+U_BOOT_DRIVER(qcom_pwrkey) = {
+ .name = "qcom_pwrkey",
+ .id = UCLASS_BUTTON,
+ .of_match = qcom_pwrkey_ids,
+ .bind = button_qcom_pmic_bind,
+ .probe = qcom_pwrkey_probe,
+ .ops = &button_qcom_pmic_ops,
+ .priv_auto = sizeof(struct qcom_pmic_btn_priv),
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index bfd23a99046..017dd260a54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -254,6 +254,7 @@ source "drivers/clk/meson/Kconfig"
source "drivers/clk/microchip/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/owl/Kconfig"
+source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/sunxi/Kconfig"
source "drivers/clk/sifive/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index af27ceb27da..638ad04baeb 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_CLK_MPFS) += microchip/
obj-$(CONFIG_CLK_MVEBU) += mvebu/
obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
obj-$(CONFIG_CLK_OWL) += owl/
+obj-$(CONFIG_CLK_QCOM) += qcom/
obj-$(CONFIG_CLK_RENESAS) += renesas/
obj-$(CONFIG_$(SPL_TPL_)CLK_SCMI) += clk_scmi.o
obj-$(CONFIG_CLK_SIFIVE) += sifive/
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
new file mode 100644
index 00000000000..0df0d1881a4
--- /dev/null
+++ b/drivers/clk/qcom/Kconfig
@@ -0,0 +1,52 @@
+if ARCH_SNAPDRAGON || ARCH_IPQ40XX
+
+config CLK_QCOM
+ bool
+ depends on CLK && DM_RESET
+ def_bool n
+
+menu "Qualcomm clock drivers"
+
+config CLK_QCOM_APQ8016
+ bool "Qualcomm APQ8016 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon APQ8016 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
+config CLK_QCOM_APQ8096
+ bool "Qualcomm APQ8096 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon APQ8096 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
+config CLK_QCOM_IPQ4019
+ bool "Qualcomm IPQ4019 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon IPQ4019 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
+config CLK_QCOM_QCS404
+ bool "Qualcomm QCS404 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon QCS404 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
+config CLK_QCOM_SDM845
+ bool "Qualcomm SDM845 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon 845 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
+endmenu
+
+endif
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
new file mode 100644
index 00000000000..cb179fdac58
--- /dev/null
+++ b/drivers/clk/qcom/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2023 Linaro
+
+obj-y += clock-qcom.o
+obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o
+obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o
+obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o
+obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o
+obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
new file mode 100644
index 00000000000..c0ce570edc7
--- /dev/null
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm APQ8016
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * Based on Little Kernel driver, simplified
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#include "clock-qcom.h"
+
+/* Clocks: (from CLK_CTL_BASE) */
+#define GPLL0_STATUS (0x2101C)
+#define APCS_GPLL_ENA_VOTE (0x45000)
+#define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004)
+
+#define SDCC_BCR(n) ((n * 0x1000) + 0x41000)
+#define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004)
+#define SDCC_CFG_RCGR(n) ((n * 0x1000) + 0x41008)
+#define SDCC_M(n) ((n * 0x1000) + 0x4100C)
+#define SDCC_N(n) ((n * 0x1000) + 0x41010)
+#define SDCC_D(n) ((n * 0x1000) + 0x41014)
+#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018)
+#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C)
+
+/* BLSP1 AHB clock (root clock for BLSP) */
+#define BLSP1_AHB_CBCR 0x1008
+
+/* Uart clock control registers */
+#define BLSP1_UART2_BCR (0x3028)
+#define BLSP1_UART2_APPS_CBCR (0x302C)
+#define BLSP1_UART2_APPS_CMD_RCGR (0x3034)
+#define BLSP1_UART2_APPS_CFG_RCGR (0x3038)
+#define BLSP1_UART2_APPS_M (0x303C)
+#define BLSP1_UART2_APPS_N (0x3040)
+#define BLSP1_UART2_APPS_D (0x3044)
+
+/* GPLL0 clock control registers */
+#define GPLL0_STATUS_ACTIVE BIT(17)
+
+static const struct bcr_regs sdc_regs[] = {
+ {
+ .cfg_rcgr = SDCC_CFG_RCGR(1),
+ .cmd_rcgr = SDCC_CMD_RCGR(1),
+ .M = SDCC_M(1),
+ .N = SDCC_N(1),
+ .D = SDCC_D(1),
+ },
+ {
+ .cfg_rcgr = SDCC_CFG_RCGR(2),
+ .cmd_rcgr = SDCC_CMD_RCGR(2),
+ .M = SDCC_M(2),
+ .N = SDCC_N(2),
+ .D = SDCC_D(2),
+ }
+};
+
+static struct pll_vote_clk gpll0_vote_clk = {
+ .status = GPLL0_STATUS,
+ .status_bit = GPLL0_STATUS_ACTIVE,
+ .ena_vote = APCS_GPLL_ENA_VOTE,
+ .vote_bit = BIT(0),
+};
+
+static struct vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .vote_bit = BIT(10),
+};
+
+/* SDHCI */
+static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate)
+{
+ int div = 15; /* 100MHz default */
+
+ if (rate == 200000000)
+ div = 4;
+
+ clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot));
+ /* 800Mhz/div, gpll0 */
+ clk_rcg_set_rate_mnd(priv->base, &sdc_regs[slot], div, 0, 0,
+ CFG_CLK_SRC_GPLL0, 8);
+ clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+ clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot));
+
+ return rate;
+}
+
+static const struct bcr_regs uart2_regs = {
+ .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR,
+ .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR,
+ .M = BLSP1_UART2_APPS_M,
+ .N = BLSP1_UART2_APPS_N,
+ .D = BLSP1_UART2_APPS_D,
+};
+
+/* UART: 115200 */
+static int clk_init_uart(struct msm_clk_priv *priv)
+{
+ /* Enable AHB clock */
+ clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
+
+ /* 7372800 uart block clock @ GPLL0 */
+ clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625,
+ CFG_CLK_SRC_GPLL0, 16);
+
+ /* Vote for gpll0 clock */
+ clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+
+ /* Enable core clk */
+ clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
+
+ return 0;
+}
+
+static ulong apq8016_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case 0: /* SDC1 */
+ return clk_init_sdc(priv, 0, rate);
+ break;
+ case 1: /* SDC2 */
+ return clk_init_sdc(priv, 1, rate);
+ break;
+ case 4: /* UART2 */
+ return clk_init_uart(priv);
+ break;
+ default:
+ return 0;
+ }
+}
+
+static struct msm_clk_data apq8016_clk_data = {
+ .set_rate = apq8016_clk_set_rate,
+};
+
+static const struct udevice_id gcc_apq8016_of_match[] = {
+ {
+ .compatible = "qcom,gcc-apq8016",
+ .data = (ulong)&apq8016_clk_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_apq8016) = {
+ .name = "gcc_apq8016",
+ .id = UCLASS_NOP,
+ .of_match = gcc_apq8016_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/qcom/clock-apq8096.c b/drivers/clk/qcom/clock-apq8096.c
new file mode 100644
index 00000000000..cf1a347309a
--- /dev/null
+++ b/drivers/clk/qcom/clock-apq8096.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm APQ8096
+ *
+ * (C) Copyright 2017 Jorge Ramirez Ortiz <[email protected]>
+ *
+ * Based on Little Kernel driver, simplified
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#include "clock-qcom.h"
+
+/* Clocks: (from CLK_CTL_BASE) */
+#define GPLL0_STATUS (0x0000)
+#define APCS_GPLL_ENA_VOTE (0x52000)
+#define APCS_CLOCK_BRANCH_ENA_VOTE (0x52004)
+
+#define SDCC2_BCR (0x14000) /* block reset */
+#define SDCC2_APPS_CBCR (0x14004) /* branch control */
+#define SDCC2_AHB_CBCR (0x14008)
+#define SDCC2_CMD_RCGR (0x14010)
+#define SDCC2_CFG_RCGR (0x14014)
+#define SDCC2_M (0x14018)
+#define SDCC2_N (0x1401C)
+#define SDCC2_D (0x14020)
+
+#define BLSP2_AHB_CBCR (0x25004)
+#define BLSP2_UART2_APPS_CBCR (0x29004)
+#define BLSP2_UART2_APPS_CMD_RCGR (0x2900C)
+#define BLSP2_UART2_APPS_CFG_RCGR (0x29010)
+#define BLSP2_UART2_APPS_M (0x29014)
+#define BLSP2_UART2_APPS_N (0x29018)
+#define BLSP2_UART2_APPS_D (0x2901C)
+
+/* GPLL0 clock control registers */
+#define GPLL0_STATUS_ACTIVE BIT(30)
+#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0)
+
+static const struct bcr_regs sdc_regs = {
+ .cfg_rcgr = SDCC2_CFG_RCGR,
+ .cmd_rcgr = SDCC2_CMD_RCGR,
+ .M = SDCC2_M,
+ .N = SDCC2_N,
+ .D = SDCC2_D,
+};
+
+static const struct pll_vote_clk gpll0_vote_clk = {
+ .status = GPLL0_STATUS,
+ .status_bit = GPLL0_STATUS_ACTIVE,
+ .ena_vote = APCS_GPLL_ENA_VOTE,
+ .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0,
+};
+
+static struct vote_clk gcc_blsp2_ahb_clk = {
+ .cbcr_reg = BLSP2_AHB_CBCR,
+ .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .vote_bit = BIT(15),
+};
+
+static int clk_init_sdc(struct msm_clk_priv *priv, uint rate)
+{
+ int div = 5;
+
+ clk_enable_cbc(priv->base + SDCC2_AHB_CBCR);
+ clk_rcg_set_rate_mnd(priv->base, &sdc_regs, div, 0, 0,
+ CFG_CLK_SRC_GPLL0, 8);
+ clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+ clk_enable_cbc(priv->base + SDCC2_APPS_CBCR);
+
+ return rate;
+}
+
+static const struct bcr_regs uart2_regs = {
+ .cfg_rcgr = BLSP2_UART2_APPS_CFG_RCGR,
+ .cmd_rcgr = BLSP2_UART2_APPS_CMD_RCGR,
+ .M = BLSP2_UART2_APPS_M,
+ .N = BLSP2_UART2_APPS_N,
+ .D = BLSP2_UART2_APPS_D,
+};
+
+static int clk_init_uart(struct msm_clk_priv *priv)
+{
+ /* Enable AHB clock */
+ clk_enable_vote_clk(priv->base, &gcc_blsp2_ahb_clk);
+
+ /* 7372800 uart block clock @ GPLL0 */
+ clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 192, 15625,
+ CFG_CLK_SRC_GPLL0, 16);
+
+ /* Vote for gpll0 clock */
+ clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+
+ /* Enable core clk */
+ clk_enable_cbc(priv->base + BLSP2_UART2_APPS_CBCR);
+
+ return 0;
+}
+
+static ulong apq8096_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case 0: /* SDC1 */
+ return clk_init_sdc(priv, rate);
+ break;
+ case 4: /*UART2*/
+ return clk_init_uart(priv);
+ default:
+ return 0;
+ }
+}
+
+static struct msm_clk_data apq8096_clk_data = {
+ .set_rate = apq8096_clk_set_rate,
+};
+
+static const struct udevice_id gcc_apq8096_of_match[] = {
+ {
+ .compatible = "qcom,gcc-apq8096",
+ .data = (ulong)&apq8096_clk_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_apq8096) = {
+ .name = "gcc_apq8096",
+ .id = UCLASS_NOP,
+ .of_match = gcc_apq8096_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/reset/reset-qcom.c b/drivers/clk/qcom/clock-ipq4019.c
index 94315e76d54..d693776d339 100644
--- a/drivers/reset/reset-qcom.c
+++ b/drivers/clk/qcom/clock-ipq4019.c
@@ -1,33 +1,55 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0+
/*
+ * Clock drivers for Qualcomm IPQ40xx
+ *
* Copyright (c) 2020 Sartura Ltd.
- * Copyright (c) 2022 Linaro Ltd.
*
* Author: Robert Marko <[email protected]>
- * Sumit Garg <[email protected]>
*
- * Based on Linux driver
*/
-#include <asm/io.h>
+#include <clk-uclass.h>
#include <common.h>
#include <dm.h>
-#include <reset-uclass.h>
-#include <linux/bitops.h>
-#include <malloc.h>
+#include <errno.h>
+#include <dt-bindings/clock/qcom,gcc-ipq4019.h>
-struct qcom_reset_priv {
- phys_addr_t base;
-};
+#include "clock-qcom.h"
-struct qcom_reset_map {
- unsigned int reg;
- u8 bit;
-};
+static ulong ipq4019_clk_set_rate(struct clk *clk, ulong rate)
+{
+ switch (clk->id) {
+ case GCC_BLSP1_UART1_APPS_CLK: /*UART1*/
+ /* This clock is already initialized by SBL1 */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
-#ifdef CONFIG_ARCH_IPQ40XX
-#include <dt-bindings/reset/qcom,ipq4019-reset.h>
-static const struct qcom_reset_map gcc_qcom_resets[] = {
+static int ipq4019_clk_enable(struct clk *clk)
+{
+ switch (clk->id) {
+ case GCC_BLSP1_QUP1_SPI_APPS_CLK: /*SPI1*/
+ /* This clock is already initialized by SBL1 */
+ return 0;
+ case GCC_PRNG_AHB_CLK: /*PRNG*/
+ /* This clock is already initialized by SBL1 */
+ return 0;
+ case GCC_USB3_MASTER_CLK:
+ case GCC_USB3_SLEEP_CLK:
+ case GCC_USB3_MOCK_UTMI_CLK:
+ case GCC_USB2_MASTER_CLK:
+ case GCC_USB2_SLEEP_CLK:
+ case GCC_USB2_MOCK_UTMI_CLK:
+ /* These clocks is already initialized by SBL1 */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct qcom_reset_map gcc_ipq4019_resets[] = {
[WIFI0_CPU_INIT_RESET] = { 0x1f008, 5 },
[WIFI0_RADIO_SRIF_RESET] = { 0x1f008, 4 },
[WIFI0_RADIO_WARM_RESET] = { 0x1f008, 3 },
@@ -100,96 +122,26 @@ static const struct qcom_reset_map gcc_qcom_resets[] = {
[GCC_MPM_BCR] = {0x24000, 0},
[GCC_SPDM_BCR] = {0x25000, 0},
};
-#endif
-
-#ifdef CONFIG_TARGET_QCS404EVB
-#include <dt-bindings/clock/qcom,gcc-qcs404.h>
-static const struct qcom_reset_map gcc_qcom_resets[] = {
- [GCC_GENI_IR_BCR] = { 0x0F000 },
- [GCC_CDSP_RESTART] = { 0x18000 },
- [GCC_USB_HS_BCR] = { 0x41000 },
- [GCC_USB2_HS_PHY_ONLY_BCR] = { 0x41034 },
- [GCC_QUSB2_PHY_BCR] = { 0x4103c },
- [GCC_USB_HS_PHY_CFG_AHB_BCR] = { 0x0000c, 1 },
- [GCC_USB2A_PHY_BCR] = { 0x0000c, 0 },
- [GCC_USB3_PHY_BCR] = { 0x39004 },
- [GCC_USB_30_BCR] = { 0x39000 },
- [GCC_USB3PHY_PHY_BCR] = { 0x39008 },
- [GCC_PCIE_0_BCR] = { 0x3e000 },
- [GCC_PCIE_0_PHY_BCR] = { 0x3e004 },
- [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x3e038 },
- [GCC_PCIEPHY_0_PHY_BCR] = { 0x3e03c },
- [GCC_PCIE_0_AXI_MASTER_STICKY_ARES] = { 0x3e040, 6},
- [GCC_PCIE_0_AHB_ARES] = { 0x3e040, 5 },
- [GCC_PCIE_0_AXI_SLAVE_ARES] = { 0x3e040, 4 },
- [GCC_PCIE_0_AXI_MASTER_ARES] = { 0x3e040, 3 },
- [GCC_PCIE_0_CORE_STICKY_ARES] = { 0x3e040, 2 },
- [GCC_PCIE_0_SLEEP_ARES] = { 0x3e040, 1 },
- [GCC_PCIE_0_PIPE_ARES] = { 0x3e040, 0 },
- [GCC_EMAC_BCR] = { 0x4e000 },
- [GCC_WDSP_RESTART] = {0x19000},
-};
-#endif
-
-static int qcom_reset_assert(struct reset_ctl *rst)
-{
- struct qcom_reset_priv *priv = dev_get_priv(rst->dev);
- const struct qcom_reset_map *reset_map = gcc_qcom_resets;
- const struct qcom_reset_map *map;
- u32 value;
-
- map = &reset_map[rst->id];
- value = readl(priv->base + map->reg);
- value |= BIT(map->bit);
- writel(value, priv->base + map->reg);
-
- return 0;
-}
-
-static int qcom_reset_deassert(struct reset_ctl *rst)
-{
- struct qcom_reset_priv *priv = dev_get_priv(rst->dev);
- const struct qcom_reset_map *reset_map = gcc_qcom_resets;
- const struct qcom_reset_map *map;
- u32 value;
-
- map = &reset_map[rst->id];
-
- value = readl(priv->base + map->reg);
- value &= ~BIT(map->bit);
- writel(value, priv->base + map->reg);
-
- return 0;
-}
-
-static const struct reset_ops qcom_reset_ops = {
- .rst_assert = qcom_reset_assert,
- .rst_deassert = qcom_reset_deassert,
+static struct msm_clk_data ipq4019_clk_data = {
+ .enable = ipq4019_clk_enable,
+ .set_rate = ipq4019_clk_set_rate,
+ .resets = gcc_ipq4019_resets,
+ .num_resets = ARRAY_SIZE(gcc_ipq4019_resets),
};
-static const struct udevice_id qcom_reset_ids[] = {
- { .compatible = "qcom,gcc-reset-ipq4019" },
- { .compatible = "qcom,gcc-reset-qcs404" },
+static const struct udevice_id gcc_ipq4019_of_match[] = {
+ {
+ .compatible = "qcom,gcc-ipq4019",
+ .data = (ulong)&ipq4019_clk_data,
+ },
{ }
};
-static int qcom_reset_probe(struct udevice *dev)
-{
- struct qcom_reset_priv *priv = dev_get_priv(dev);
-
- priv->base = dev_read_addr(dev);
- if (priv->base == FDT_ADDR_T_NONE)
- return -EINVAL;
-
- return 0;
-}
-
-U_BOOT_DRIVER(qcom_reset) = {
- .name = "qcom_reset",
- .id = UCLASS_RESET,
- .of_match = qcom_reset_ids,
- .ops = &qcom_reset_ops,
- .probe = qcom_reset_probe,
- .priv_auto = sizeof(struct qcom_reset_priv),
+U_BOOT_DRIVER(gcc_ipq4019) = {
+ .name = "gcc_ipq4019",
+ .id = UCLASS_NOP,
+ .of_match = gcc_ipq4019_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
new file mode 100644
index 00000000000..7c683e51922
--- /dev/null
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: BSD-3-Clause AND GPL-2.0
+/*
+ * Clock and reset drivers for Qualcomm platforms Global Clock
+ * Controller (GCC).
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ * (C) Copyright 2020 Sartura Ltd. (reset driver)
+ * Author: Robert Marko <[email protected]>
+ * (C) Copyright 2022 Linaro Ltd. (reset driver)
+ * Author: Sumit Garg <[email protected]>
+ *
+ * Based on Little Kernel driver, simplified
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <reset-uclass.h>
+
+#include "clock-qcom.h"
+
+/* CBCR register fields */
+#define CBCR_BRANCH_ENABLE_BIT BIT(0)
+#define CBCR_BRANCH_OFF_BIT BIT(31)
+
+/* Enable clock controlled by CBC soft macro */
+void clk_enable_cbc(phys_addr_t cbcr)
+{
+ setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT);
+
+ while (readl(cbcr) & CBCR_BRANCH_OFF_BIT)
+ ;
+}
+
+void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0)
+{
+ if (readl(base + gpll0->status) & gpll0->status_bit)
+ return; /* clock already enabled */
+
+ setbits_le32(base + gpll0->ena_vote, gpll0->vote_bit);
+
+ while ((readl(base + gpll0->status) & gpll0->status_bit) == 0)
+ ;
+}
+
+#define BRANCH_ON_VAL (0)
+#define BRANCH_NOC_FSM_ON_VAL BIT(29)
+#define BRANCH_CHECK_MASK GENMASK(31, 28)
+
+void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk)
+{
+ u32 val;
+
+ setbits_le32(base + vclk->ena_vote, vclk->vote_bit);
+ do {
+ val = readl(base + vclk->cbcr_reg);
+ val &= BRANCH_CHECK_MASK;
+ } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL));
+}
+
+#define APPS_CMD_RCGR_UPDATE BIT(0)
+
+/* Update clock command via CMD_RCGR */
+void clk_bcr_update(phys_addr_t apps_cmd_rcgr)
+{
+ u32 count;
+ setbits_le32(apps_cmd_rcgr, APPS_CMD_RCGR_UPDATE);
+
+ /* Wait for frequency to be updated. */
+ for (count = 0; count < 50000; count++) {
+ if (!(readl(apps_cmd_rcgr) & APPS_CMD_RCGR_UPDATE))
+ break;
+ udelay(1);
+ }
+ WARN(count == 50000, "WARNING: RCG @ %#llx [%#010x] stuck at off\n",
+ apps_cmd_rcgr, readl(apps_cmd_rcgr));
+}
+
+#define CFG_SRC_DIV_MASK 0b11111
+#define CFG_SRC_SEL_SHIFT 8
+#define CFG_SRC_SEL_MASK (0x7 << CFG_SRC_SEL_SHIFT)
+#define CFG_MODE_SHIFT 12
+#define CFG_MODE_MASK (0x3 << CFG_MODE_SHIFT)
+#define CFG_MODE_DUAL_EDGE (0x2 << CFG_MODE_SHIFT)
+#define CFG_HW_CLK_CTRL_MASK BIT(20)
+
+/*
+ * root set rate for clocks with half integer and MND divider
+ * div should be pre-calculated ((div * 2) - 1)
+ */
+void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
+ int div, int m, int n, int source, u8 mnd_width)
+{
+ u32 cfg;
+ /* M value for MND divider. */
+ u32 m_val = m;
+ u32 n_minus_m = n - m;
+ /* NOT(N-M) value for MND divider. */
+ u32 n_val = ~n_minus_m * !!(n);
+ /* NOT 2D value for MND divider. */
+ u32 d_val = ~(clamp_t(u32, n, m, n_minus_m));
+ u32 mask = BIT(mnd_width) - 1;
+
+ debug("m %#x n %#x d %#x div %#x mask %#x\n", m_val, n_val, d_val, div, mask);
+
+ /* Program MND values */
+ writel(m_val & mask, base + regs->M);
+ writel(n_val & mask, base + regs->N);
+ writel(d_val & mask, base + regs->D);
+
+ /* setup src select and divider */
+ cfg = readl(base + regs->cfg_rcgr);
+ cfg &= ~(CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK);
+ cfg |= source & CFG_SRC_SEL_MASK; /* Select clock source */
+
+ if (div)
+ cfg |= div & CFG_SRC_DIV_MASK;
+
+ if (n && n != m)
+ cfg |= CFG_MODE_DUAL_EDGE;
+
+ writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */
+
+ /* Inform h/w to start using the new config. */
+ clk_bcr_update(base + regs->cmd_rcgr);
+}
+
+/* root set rate for clocks with half integer and mnd_width=0 */
+void clk_rcg_set_rate(phys_addr_t base, const struct bcr_regs *regs, int div,
+ int source)
+{
+ u32 cfg;
+
+ /* setup src select and divider */
+ cfg = readl(base + regs->cfg_rcgr);
+ cfg &= ~(CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK);
+ cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */
+
+ /*
+ * Set the divider; HW permits fraction dividers (+0.5), but
+ * for simplicity, we will support integers only
+ */
+ if (div)
+ cfg |= (2 * div - 1) & CFG_SRC_DIV_MASK;
+
+ writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */
+
+ /* Inform h/w to start using the new config. */
+ clk_bcr_update(base + regs->cmd_rcgr);
+}
+
+const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, uint rate)
+{
+ if (!f)
+ return NULL;
+
+ if (!f->freq)
+ return f;
+
+ for (; f->freq; f++)
+ if (rate <= f->freq)
+ return f;
+
+ /* Default to our fastest rate */
+ return f - 1;
+}
+
+static int msm_clk_probe(struct udevice *dev)
+{
+ struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev);
+ struct msm_clk_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->data = data;
+
+ return 0;
+}
+
+static ulong msm_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(clk->dev);
+
+ if (data->set_rate)
+ return data->set_rate(clk, rate);
+
+ return 0;
+}
+
+static int msm_clk_enable(struct clk *clk)
+{
+ struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(clk->dev);
+
+ if (data->enable)
+ return data->enable(clk);
+
+ return 0;
+}
+
+static struct clk_ops msm_clk_ops = {
+ .set_rate = msm_clk_set_rate,
+ .enable = msm_clk_enable,
+};
+
+U_BOOT_DRIVER(qcom_clk) = {
+ .name = "qcom_clk",
+ .id = UCLASS_CLK,
+ .ops = &msm_clk_ops,
+ .priv_auto = sizeof(struct msm_clk_priv),
+ .probe = msm_clk_probe,
+};
+
+int qcom_cc_bind(struct udevice *parent)
+{
+ struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
+ struct udevice *clkdev, *rstdev;
+ struct driver *drv;
+ int ret;
+
+ /* Get a handle to the common clk handler */
+ drv = lists_driver_lookup_name("qcom_clk");
+ if (!drv)
+ return -ENOENT;
+
+ /* Register the clock controller */
+ ret = device_bind_with_driver_data(parent, drv, "qcom_clk", (ulong)data,
+ dev_ofnode(parent), &clkdev);
+ if (ret)
+ return ret;
+
+ /* Bail out early if resets are not specified for this platform */
+ if (!data->resets)
+ return ret;
+
+ /* Get a handle to the common reset handler */
+ drv = lists_driver_lookup_name("qcom_reset");
+ if (!drv)
+ return -ENOENT;
+
+ /* Register the reset controller */
+ ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
+ dev_ofnode(parent), &rstdev);
+ if (ret)
+ device_unbind(clkdev);
+
+ return ret;
+}
+
+static int qcom_reset_set(struct reset_ctl *rst, bool assert)
+{
+ struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(rst->dev);
+ void __iomem *base = dev_get_priv(rst->dev);
+ const struct qcom_reset_map *map;
+ u32 value;
+
+ map = &data->resets[rst->id];
+
+ value = readl(base + map->reg);
+
+ if (assert)
+ value |= BIT(map->bit);
+ else
+ value &= ~BIT(map->bit);
+
+ writel(value, base + map->reg);
+
+ return 0;
+}
+
+static int qcom_reset_assert(struct reset_ctl *rst)
+{
+ return qcom_reset_set(rst, true);
+}
+
+static int qcom_reset_deassert(struct reset_ctl *rst)
+{
+ return qcom_reset_set(rst, false);
+}
+
+static const struct reset_ops qcom_reset_ops = {
+ .rst_assert = qcom_reset_assert,
+ .rst_deassert = qcom_reset_deassert,
+};
+
+static int qcom_reset_probe(struct udevice *dev)
+{
+ /* Set our priv pointer to the base address */
+ dev_set_priv(dev, (void *)dev_read_addr(dev));
+
+ return 0;
+}
+
+U_BOOT_DRIVER(qcom_reset) = {
+ .name = "qcom_reset",
+ .id = UCLASS_RESET,
+ .ops = &qcom_reset_ops,
+ .probe = qcom_reset_probe,
+};
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
new file mode 100644
index 00000000000..01088c19015
--- /dev/null
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <[email protected]>
+ */
+#ifndef _CLOCK_QCOM_H
+#define _CLOCK_QCOM_H
+
+#include <asm/io.h>
+
+#define CFG_CLK_SRC_CXO (0 << 8)
+#define CFG_CLK_SRC_GPLL0 (1 << 8)
+#define CFG_CLK_SRC_GPLL0_EVEN (6 << 8)
+#define CFG_CLK_SRC_MASK (7 << 8)
+
+struct pll_vote_clk {
+ uintptr_t status;
+ int status_bit;
+ uintptr_t ena_vote;
+ int vote_bit;
+};
+
+struct vote_clk {
+ uintptr_t cbcr_reg;
+ uintptr_t ena_vote;
+ int vote_bit;
+};
+struct bcr_regs {
+ uintptr_t cfg_rcgr;
+ uintptr_t cmd_rcgr;
+ uintptr_t M;
+ uintptr_t N;
+ uintptr_t D;
+};
+
+struct freq_tbl {
+ uint freq;
+ uint src;
+ u8 pre_div;
+ u16 m;
+ u16 n;
+};
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+struct gate_clk {
+ uintptr_t reg;
+ u32 en_val;
+ const char *name;
+};
+
+#ifdef DEBUG
+#define GATE_CLK(clk, reg, val) [clk] = { reg, val, #clk }
+#else
+#define GATE_CLK(clk, reg, val) [clk] = { reg, val, NULL }
+#endif
+
+struct qcom_reset_map {
+ unsigned int reg;
+ u8 bit;
+};
+
+struct clk;
+
+struct msm_clk_data {
+ const struct qcom_reset_map *resets;
+ unsigned long num_resets;
+ const struct gate_clk *clks;
+ unsigned long num_clks;
+
+ int (*enable)(struct clk *clk);
+ unsigned long (*set_rate)(struct clk *clk, unsigned long rate);
+};
+
+struct msm_clk_priv {
+ phys_addr_t base;
+ struct msm_clk_data *data;
+};
+
+int qcom_cc_bind(struct udevice *parent);
+void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0);
+void clk_bcr_update(phys_addr_t apps_cmd_rgcr);
+void clk_enable_cbc(phys_addr_t cbcr);
+void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk);
+const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, uint rate);
+void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
+ int div, int m, int n, int source, u8 mnd_width);
+void clk_rcg_set_rate(phys_addr_t base, const struct bcr_regs *regs, int div,
+ int source);
+
+static inline void qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id)
+{
+ u32 val;
+ if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0)
+ return;
+
+ val = readl(priv->base + priv->data->clks[id].reg);
+ writel(val | priv->data->clks[id].en_val, priv->base + priv->data->clks[id].reg);
+}
+
+#endif
diff --git a/drivers/clk/qcom/clock-qcs404.c b/drivers/clk/qcom/clock-qcs404.c
new file mode 100644
index 00000000000..f5b35280392
--- /dev/null
+++ b/drivers/clk/qcom/clock-qcs404.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm QCS404
+ *
+ * (C) Copyright 2022 Sumit Garg <[email protected]>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-qcs404.h>
+
+#include "clock-qcom.h"
+
+/* Clocks: (from CLK_CTL_BASE) */
+#define GPLL0_STATUS (0x21000)
+#define GPLL1_STATUS (0x20000)
+#define APCS_GPLL_ENA_VOTE (0x45000)
+#define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004)
+
+/* BLSP1 AHB clock (root clock for BLSP) */
+#define BLSP1_AHB_CBCR 0x1008
+
+/* Uart clock control registers */
+#define BLSP1_UART2_BCR (0x3028)
+#define BLSP1_UART2_APPS_CBCR (0x302C)
+#define BLSP1_UART2_APPS_CMD_RCGR (0x3034)
+#define BLSP1_UART2_APPS_CFG_RCGR (0x3038)
+#define BLSP1_UART2_APPS_M (0x303C)
+#define BLSP1_UART2_APPS_N (0x3040)
+#define BLSP1_UART2_APPS_D (0x3044)
+
+/* I2C controller clock control registerss */
+#define BLSP1_QUP0_I2C_APPS_CBCR (0x6028)
+#define BLSP1_QUP0_I2C_APPS_CMD_RCGR (0x602C)
+#define BLSP1_QUP0_I2C_APPS_CFG_RCGR (0x6030)
+#define BLSP1_QUP1_I2C_APPS_CBCR (0x2008)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR (0x200C)
+#define BLSP1_QUP1_I2C_APPS_CFG_RCGR (0x2010)
+#define BLSP1_QUP2_I2C_APPS_CBCR (0x3010)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR (0x3000)
+#define BLSP1_QUP2_I2C_APPS_CFG_RCGR (0x3004)
+#define BLSP1_QUP3_I2C_APPS_CBCR (0x4020)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR (0x4000)
+#define BLSP1_QUP3_I2C_APPS_CFG_RCGR (0x4004)
+#define BLSP1_QUP4_I2C_APPS_CBCR (0x5020)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR (0x5000)
+#define BLSP1_QUP4_I2C_APPS_CFG_RCGR (0x5004)
+
+/* SD controller clock control registers */
+#define SDCC_BCR(n) (((n) * 0x1000) + 0x41000)
+#define SDCC_CMD_RCGR(n) (((n) * 0x1000) + 0x41004)
+#define SDCC_CFG_RCGR(n) (((n) * 0x1000) + 0x41008)
+#define SDCC_M(n) (((n) * 0x1000) + 0x4100C)
+#define SDCC_N(n) (((n) * 0x1000) + 0x41010)
+#define SDCC_D(n) (((n) * 0x1000) + 0x41014)
+#define SDCC_APPS_CBCR(n) (((n) * 0x1000) + 0x41018)
+#define SDCC_AHB_CBCR(n) (((n) * 0x1000) + 0x4101C)
+
+/* USB-3.0 controller clock control registers */
+#define SYS_NOC_USB3_CBCR (0x26014)
+#define USB30_BCR (0x39000)
+#define USB3PHY_BCR (0x39008)
+#define USB30_MASTER_CBCR (0x3900C)
+#define USB30_SLEEP_CBCR (0x39010)
+#define USB30_MOCK_UTMI_CBCR (0x39014)
+#define USB30_MOCK_UTMI_CMD_RCGR (0x3901C)
+#define USB30_MOCK_UTMI_CFG_RCGR (0x39020)
+#define USB30_MASTER_CMD_RCGR (0x39028)
+#define USB30_MASTER_CFG_RCGR (0x3902C)
+#define USB30_MASTER_M (0x39030)
+#define USB30_MASTER_N (0x39034)
+#define USB30_MASTER_D (0x39038)
+#define USB2A_PHY_SLEEP_CBCR (0x4102C)
+#define USB_HS_PHY_CFG_AHB_CBCR (0x41030)
+
+/* ETH controller clock control registers */
+#define ETH_PTP_CBCR (0x4e004)
+#define ETH_RGMII_CBCR (0x4e008)
+#define ETH_SLAVE_AHB_CBCR (0x4e00c)
+#define ETH_AXI_CBCR (0x4e010)
+#define EMAC_PTP_CMD_RCGR (0x4e014)
+#define EMAC_PTP_CFG_RCGR (0x4e018)
+#define EMAC_CMD_RCGR (0x4e01c)
+#define EMAC_CFG_RCGR (0x4e020)
+#define EMAC_M (0x4e024)
+#define EMAC_N (0x4e028)
+#define EMAC_D (0x4e02c)
+
+
+/* GPLL0 clock control registers */
+#define GPLL0_STATUS_ACTIVE BIT(31)
+
+#define CFG_CLK_SRC_GPLL1 BIT(8)
+#define GPLL1_STATUS_ACTIVE BIT(31)
+
+static struct vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .vote_bit = BIT(10) | BIT(5) | BIT(4),
+};
+
+static const struct bcr_regs uart2_regs = {
+ .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR,
+ .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR,
+ .M = BLSP1_UART2_APPS_M,
+ .N = BLSP1_UART2_APPS_N,
+ .D = BLSP1_UART2_APPS_D,
+};
+
+static const struct bcr_regs sdc_regs = {
+ .cfg_rcgr = SDCC_CFG_RCGR(1),
+ .cmd_rcgr = SDCC_CMD_RCGR(1),
+ .M = SDCC_M(1),
+ .N = SDCC_N(1),
+ .D = SDCC_D(1),
+};
+
+static struct pll_vote_clk gpll0_vote_clk = {
+ .status = GPLL0_STATUS,
+ .status_bit = GPLL0_STATUS_ACTIVE,
+ .ena_vote = APCS_GPLL_ENA_VOTE,
+ .vote_bit = BIT(0),
+};
+
+static struct pll_vote_clk gpll1_vote_clk = {
+ .status = GPLL1_STATUS,
+ .status_bit = GPLL1_STATUS_ACTIVE,
+ .ena_vote = APCS_GPLL_ENA_VOTE,
+ .vote_bit = BIT(1),
+};
+
+static const struct bcr_regs usb30_master_regs = {
+ .cfg_rcgr = USB30_MASTER_CFG_RCGR,
+ .cmd_rcgr = USB30_MASTER_CMD_RCGR,
+ .M = USB30_MASTER_M,
+ .N = USB30_MASTER_N,
+ .D = USB30_MASTER_D,
+};
+
+static const struct bcr_regs emac_regs = {
+ .cfg_rcgr = EMAC_CFG_RCGR,
+ .cmd_rcgr = EMAC_CMD_RCGR,
+ .M = EMAC_M,
+ .N = EMAC_N,
+ .D = EMAC_D,
+};
+
+static const struct bcr_regs emac_ptp_regs = {
+ .cfg_rcgr = EMAC_PTP_CFG_RCGR,
+ .cmd_rcgr = EMAC_PTP_CMD_RCGR,
+ .M = EMAC_M,
+ .N = EMAC_N,
+ .D = EMAC_D,
+};
+
+static const struct bcr_regs blsp1_qup0_i2c_apps_regs = {
+ .cmd_rcgr = BLSP1_QUP0_I2C_APPS_CMD_RCGR,
+ .cfg_rcgr = BLSP1_QUP0_I2C_APPS_CFG_RCGR,
+ /* mnd_width = 0 */
+};
+
+static const struct bcr_regs blsp1_qup1_i2c_apps_regs = {
+ .cmd_rcgr = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+ .cfg_rcgr = BLSP1_QUP1_I2C_APPS_CFG_RCGR,
+ /* mnd_width = 0 */
+};
+
+static const struct bcr_regs blsp1_qup2_i2c_apps_regs = {
+ .cmd_rcgr = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+ .cfg_rcgr = BLSP1_QUP2_I2C_APPS_CFG_RCGR,
+ /* mnd_width = 0 */
+};
+
+static const struct bcr_regs blsp1_qup3_i2c_apps_regs = {
+ .cmd_rcgr = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+ .cfg_rcgr = BLSP1_QUP3_I2C_APPS_CFG_RCGR,
+ /* mnd_width = 0 */
+};
+
+static const struct bcr_regs blsp1_qup4_i2c_apps_regs = {
+ .cmd_rcgr = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+ .cfg_rcgr = BLSP1_QUP4_I2C_APPS_CFG_RCGR,
+ /* mnd_width = 0 */
+};
+
+static ulong qcs404_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case GCC_BLSP1_UART2_APPS_CLK:
+ /* UART: 115200 */
+ clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 0, 12, 125,
+ CFG_CLK_SRC_CXO, 16);
+ clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
+ break;
+ case GCC_BLSP1_AHB_CLK:
+ clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
+ break;
+ case GCC_SDCC1_APPS_CLK:
+ /* SDCC1: 200MHz */
+ clk_rcg_set_rate_mnd(priv->base, &sdc_regs, 7, 0, 0,
+ CFG_CLK_SRC_GPLL0, 8);
+ clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+ clk_enable_cbc(priv->base + SDCC_APPS_CBCR(1));
+ break;
+ case GCC_SDCC1_AHB_CLK:
+ clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1));
+ break;
+ case GCC_ETH_RGMII_CLK:
+ if (rate == 250000000)
+ clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 0, 0,
+ CFG_CLK_SRC_GPLL1, 8);
+ else if (rate == 125000000)
+ clk_rcg_set_rate_mnd(priv->base, &emac_regs, 7, 0, 0,
+ CFG_CLK_SRC_GPLL1, 8);
+ else if (rate == 50000000)
+ clk_rcg_set_rate_mnd(priv->base, &emac_regs, 19, 0, 0,
+ CFG_CLK_SRC_GPLL1, 8);
+ else if (rate == 5000000)
+ clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 1, 50,
+ CFG_CLK_SRC_GPLL1, 8);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int qcs404_clk_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case GCC_USB30_MASTER_CLK:
+ clk_enable_cbc(priv->base + USB30_MASTER_CBCR);
+ clk_rcg_set_rate_mnd(priv->base, &usb30_master_regs, 7, 0, 0,
+ CFG_CLK_SRC_GPLL0, 8);
+ break;
+ case GCC_SYS_NOC_USB3_CLK:
+ clk_enable_cbc(priv->base + SYS_NOC_USB3_CBCR);
+ break;
+ case GCC_USB30_SLEEP_CLK:
+ clk_enable_cbc(priv->base + USB30_SLEEP_CBCR);
+ break;
+ case GCC_USB30_MOCK_UTMI_CLK:
+ clk_enable_cbc(priv->base + USB30_MOCK_UTMI_CBCR);
+ break;
+ case GCC_USB_HS_PHY_CFG_AHB_CLK:
+ clk_enable_cbc(priv->base + USB_HS_PHY_CFG_AHB_CBCR);
+ break;
+ case GCC_USB2A_PHY_SLEEP_CLK:
+ clk_enable_cbc(priv->base + USB_HS_PHY_CFG_AHB_CBCR);
+ break;
+ case GCC_ETH_PTP_CLK:
+ /* SPEED_1000: freq -> 250MHz */
+ clk_enable_cbc(priv->base + ETH_PTP_CBCR);
+ clk_enable_gpll0(priv->base, &gpll1_vote_clk);
+ clk_rcg_set_rate_mnd(priv->base, &emac_ptp_regs, 3, 0, 0,
+ CFG_CLK_SRC_GPLL1, 8);
+ break;
+ case GCC_ETH_RGMII_CLK:
+ /* SPEED_1000: freq -> 250MHz */
+ clk_enable_cbc(priv->base + ETH_RGMII_CBCR);
+ clk_enable_gpll0(priv->base, &gpll1_vote_clk);
+ clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 0, 0,
+ CFG_CLK_SRC_GPLL1, 8);
+ break;
+ case GCC_ETH_SLAVE_AHB_CLK:
+ clk_enable_cbc(priv->base + ETH_SLAVE_AHB_CBCR);
+ break;
+ case GCC_ETH_AXI_CLK:
+ clk_enable_cbc(priv->base + ETH_AXI_CBCR);
+ break;
+ case GCC_BLSP1_AHB_CLK:
+ clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
+ break;
+ case GCC_BLSP1_QUP0_I2C_APPS_CLK:
+ clk_enable_cbc(priv->base + BLSP1_QUP0_I2C_APPS_CBCR);
+ clk_rcg_set_rate(priv->base, &blsp1_qup0_i2c_apps_regs, 0,
+ CFG_CLK_SRC_CXO);
+ break;
+ case GCC_BLSP1_QUP1_I2C_APPS_CLK:
+ clk_enable_cbc(priv->base + BLSP1_QUP1_I2C_APPS_CBCR);
+ clk_rcg_set_rate(priv->base, &blsp1_qup1_i2c_apps_regs, 0,
+ CFG_CLK_SRC_CXO);
+ break;
+ case GCC_BLSP1_QUP2_I2C_APPS_CLK:
+ clk_enable_cbc(priv->base + BLSP1_QUP2_I2C_APPS_CBCR);
+ clk_rcg_set_rate(priv->base, &blsp1_qup2_i2c_apps_regs, 0,
+ CFG_CLK_SRC_CXO);
+ break;
+ case GCC_BLSP1_QUP3_I2C_APPS_CLK:
+ clk_enable_cbc(priv->base + BLSP1_QUP3_I2C_APPS_CBCR);
+ clk_rcg_set_rate(priv->base, &blsp1_qup3_i2c_apps_regs, 0,
+ CFG_CLK_SRC_CXO);
+ break;
+ case GCC_BLSP1_QUP4_I2C_APPS_CLK:
+ clk_enable_cbc(priv->base + BLSP1_QUP4_I2C_APPS_CBCR);
+ clk_rcg_set_rate(priv->base, &blsp1_qup4_i2c_apps_regs, 0,
+ CFG_CLK_SRC_CXO);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct qcom_reset_map qcs404_gcc_resets[] = {
+ [GCC_GENI_IR_BCR] = { 0x0F000 },
+ [GCC_CDSP_RESTART] = { 0x18000 },
+ [GCC_USB_HS_BCR] = { 0x41000 },
+ [GCC_USB2_HS_PHY_ONLY_BCR] = { 0x41034 },
+ [GCC_QUSB2_PHY_BCR] = { 0x4103c },
+ [GCC_USB_HS_PHY_CFG_AHB_BCR] = { 0x0000c, 1 },
+ [GCC_USB2A_PHY_BCR] = { 0x0000c, 0 },
+ [GCC_USB3_PHY_BCR] = { 0x39004 },
+ [GCC_USB_30_BCR] = { 0x39000 },
+ [GCC_USB3PHY_PHY_BCR] = { 0x39008 },
+ [GCC_PCIE_0_BCR] = { 0x3e000 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x3e004 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x3e038 },
+ [GCC_PCIEPHY_0_PHY_BCR] = { 0x3e03c },
+ [GCC_PCIE_0_AXI_MASTER_STICKY_ARES] = { 0x3e040, 6},
+ [GCC_PCIE_0_AHB_ARES] = { 0x3e040, 5 },
+ [GCC_PCIE_0_AXI_SLAVE_ARES] = { 0x3e040, 4 },
+ [GCC_PCIE_0_AXI_MASTER_ARES] = { 0x3e040, 3 },
+ [GCC_PCIE_0_CORE_STICKY_ARES] = { 0x3e040, 2 },
+ [GCC_PCIE_0_SLEEP_ARES] = { 0x3e040, 1 },
+ [GCC_PCIE_0_PIPE_ARES] = { 0x3e040, 0 },
+ [GCC_EMAC_BCR] = { 0x4e000 },
+ [GCC_WDSP_RESTART] = {0x19000},
+};
+
+static const struct msm_clk_data qcs404_clk_gcc_data = {
+ .resets = qcs404_gcc_resets,
+ .num_resets = ARRAY_SIZE(qcs404_gcc_resets),
+ .enable = qcs404_clk_enable,
+ .set_rate = qcs404_clk_set_rate,
+};
+
+static const struct udevice_id gcc_qcs404_of_match[] = {
+ {
+ .compatible = "qcom,gcc-qcs404",
+ .data = (ulong)&qcs404_clk_gcc_data
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_qcs404) = {
+ .name = "gcc_qcs404",
+ .id = UCLASS_NOP,
+ .of_match = gcc_qcs404_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c
new file mode 100644
index 00000000000..36ffee79d96
--- /dev/null
+++ b/drivers/clk/qcom/clock-sdm845.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm SDM845
+ *
+ * (C) Copyright 2017 Jorge Ramirez Ortiz <[email protected]>
+ * (C) Copyright 2021 Dzmitry Sankouski <[email protected]>
+ *
+ * Based on Little Kernel driver, simplified
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+
+#include "clock-qcom.h"
+
+#define SE9_AHB_CBCR 0x25004
+#define SE9_UART_APPS_CBCR 0x29004
+#define SE9_UART_APPS_CMD_RCGR 0x18148
+#define SE9_UART_APPS_CFG_RCGR 0x1814C
+#define SE9_UART_APPS_M 0x18150
+#define SE9_UART_APPS_N 0x18154
+#define SE9_UART_APPS_D 0x18158
+
+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 bcr_regs uart2_regs = {
+ .cfg_rcgr = SE9_UART_APPS_CFG_RCGR,
+ .cmd_rcgr = SE9_UART_APPS_CMD_RCGR,
+ .M = SE9_UART_APPS_M,
+ .N = SE9_UART_APPS_N,
+ .D = SE9_UART_APPS_D,
+};
+
+static ulong sdm845_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_QUPV3_WRAP1_S1_CLK: /* UART9 */
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, &uart2_regs,
+ freq->pre_div, freq->m, freq->n, freq->src, 16);
+ return freq->freq;
+ default:
+ return 0;
+ }
+}
+
+static const struct gate_clk sdm845_clks[] = {
+ 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_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_CARD_AHB_CLK, 0x75010, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_AXI_CLK, 0x7500c, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_CLKREF_CLK, 0x8c004, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_ICE_CORE_CLK, 0x75058, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_PHY_AUX_CLK, 0x7508c, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_RX_SYMBOL_0_CLK, 0x75018, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_RX_SYMBOL_1_CLK, 0x750a8, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_TX_SYMBOL_0_CLK, 0x75014, 0x00000001),
+ GATE_CLK(GCC_UFS_CARD_UNIPRO_CORE_CLK, 0x75054, 0x00000001),
+ GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 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_RX_SYMBOL_1_CLK, 0x770a8, 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_USB30_SEC_MASTER_CLK, 0x1000c, 0x00000001),
+ GATE_CLK(GCC_USB30_SEC_MOCK_UTMI_CLK, 0x10014, 0x00000001),
+ GATE_CLK(GCC_USB30_SEC_SLEEP_CLK, 0x10010, 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_USB3_SEC_CLKREF_CLK, 0x8c028, 0x00000001),
+ GATE_CLK(GCC_USB3_SEC_PHY_AUX_CLK, 0x1004c, 0x00000001),
+ GATE_CLK(GCC_USB3_SEC_PHY_PIPE_CLK, 0x10054, 0x00000001),
+ GATE_CLK(GCC_USB3_SEC_PHY_COM_AUX_CLK, 0x10050, 0x00000001),
+ GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001),
+};
+
+static int sdm845_clk_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ debug("%s: clk %s\n", __func__, sdm845_clks[clk->id].name);
+
+ qcom_gate_clk_en(priv, clk->id);
+
+ return 0;
+}
+
+static const struct qcom_reset_map sdm845_gcc_resets[] = {
+ [GCC_QUPV3_WRAPPER_0_BCR] = { 0x17000 },
+ [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+ [GCC_SDCC2_BCR] = { 0x14000 },
+ [GCC_SDCC4_BCR] = { 0x16000 },
+ [GCC_UFS_CARD_BCR] = { 0x75000 },
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB30_PRIM_BCR] = { 0xf000 },
+ [GCC_USB30_SEC_BCR] = { 0x10000 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x5000c },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+};
+
+static struct msm_clk_data sdm845_clk_data = {
+ .resets = sdm845_gcc_resets,
+ .num_resets = ARRAY_SIZE(sdm845_gcc_resets),
+ .clks = sdm845_clks,
+ .num_clks = ARRAY_SIZE(sdm845_clks),
+
+ .enable = sdm845_clk_enable,
+ .set_rate = sdm845_clk_set_rate,
+};
+
+static const struct udevice_id gcc_sdm845_of_match[] = {
+ {
+ .compatible = "qcom,gcc-sdm845",
+ .data = (ulong)&sdm845_clk_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_sdm845) = {
+ .name = "gcc_sdm845",
+ .id = UCLASS_NOP,
+ .of_match = gcc_sdm845_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 63e62e1acd2..27df5d88d40 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -318,12 +318,11 @@ config CMD_PCA953X
config QCOM_PMIC_GPIO
bool "Qualcomm generic PMIC GPIO/keypad driver"
depends on DM_GPIO && PMIC_QCOM
+ select BUTTON
help
Support for GPIO pins and power/reset buttons found on
Qualcomm SoCs PMIC.
- Default name for GPIO bank is "pm8916".
- Power and reset buttons are placed in "pwkey_qcom" bank and
- have gpio numbers 0 and 1 respectively.
+ The GPIO bank is called "pmic"
config PCF8575_GPIO
bool "PCF8575 I2C GPIO Expander driver"
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index 51670f26371..80cd28bb231 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -11,13 +11,10 @@
#include <asm/global_data.h>
#include <asm/gpio.h>
#include <asm/io.h>
+#include <mach/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
-/* Register offsets */
-#define GPIO_CONFIG_OFF(no) ((no) * 0x1000)
-#define GPIO_IN_OUT_OFF(no) ((no) * 0x1000 + 0x4)
-
/* OE */
#define GPIO_OE_DISABLE (0x0 << 9)
#define GPIO_OE_ENABLE (0x1 << 9)
@@ -29,57 +26,64 @@ DECLARE_GLOBAL_DATA_PTR;
struct msm_gpio_bank {
phys_addr_t base;
+ const struct msm_pin_data *pin_data;
};
+#define GPIO_CONFIG_REG(dev, x) \
+ (qcom_pin_offset(((struct msm_gpio_bank *)dev_get_priv(dev))->pin_data->pin_offsets, x))
+
+#define GPIO_IN_OUT_REG(dev, x) \
+ (GPIO_CONFIG_REG(dev, x) + 0x4)
+
static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio);
/* Disable OE bit */
- clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_DISABLE);
+ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
+ GPIO_OE_MASK, GPIO_OE_DISABLE);
return 0;
}
-static int msm_gpio_set_value(struct udevice *dev, unsigned gpio, int value)
+static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
value = !!value;
/* set value */
- writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio));
+ writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
return 0;
}
-static int msm_gpio_direction_output(struct udevice *dev, unsigned gpio,
+static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
int value)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio);
value = !!value;
/* set value */
- writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio));
+ writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
/* switch direction */
- clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_ENABLE);
+ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
+ GPIO_OE_MASK, GPIO_OE_ENABLE);
return 0;
}
-static int msm_gpio_get_value(struct udevice *dev, unsigned gpio)
+static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- return !!(readl(priv->base + GPIO_IN_OUT_OFF(gpio)) >> GPIO_IN);
+ return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
}
-static int msm_gpio_get_function(struct udevice *dev, unsigned offset)
+static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- if (readl(priv->base + GPIO_CONFIG_OFF(offset)) & GPIO_OE_ENABLE)
+ if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
return GPIOF_OUTPUT;
return GPIOF_INPUT;
@@ -98,6 +102,7 @@ static int msm_gpio_probe(struct udevice *dev)
struct msm_gpio_bank *priv = dev_get_priv(dev);
priv->base = dev_read_addr(dev);
+ priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
}
@@ -105,9 +110,10 @@ static int msm_gpio_probe(struct udevice *dev)
static int msm_gpio_of_to_plat(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
- uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "gpio-count", 0);
+ /* Get the pin count from the pinctrl driver */
+ uc_priv->gpio_count = pin_data->pin_count;
uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
"gpio-bank-name", NULL);
if (uc_priv->bank_name == NULL)
diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c
index 65feb453ebc..6167c841167 100644
--- a/drivers/gpio/qcom_pmic_gpio.c
+++ b/drivers/gpio/qcom_pmic_gpio.c
@@ -221,11 +221,14 @@ static int qcom_gpio_probe(struct udevice *dev)
{
struct qcom_gpio_bank *priv = dev_get_priv(dev);
int reg;
+ u64 pid;
- priv->pid = dev_read_addr(dev);
- if (priv->pid == FDT_ADDR_T_NONE)
+ pid = dev_read_addr(dev);
+ if (pid == FDT_ADDR_T_NONE)
return log_msg_ret("bad address", -EINVAL);
+ priv->pid = pid;
+
/* Do a sanity check */
reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
if (reg != REG_TYPE_VAL)
@@ -242,14 +245,36 @@ static int qcom_gpio_probe(struct udevice *dev)
return 0;
}
+/*
+ * Parse basic GPIO count specified via the gpio-ranges property
+ * as specified in Linux devicetrees
+ * Returns < 0 on error, otherwise gpio count
+ */
+static int qcom_gpio_of_parse_ranges(struct udevice *dev)
+{
+ int ret;
+ struct ofnode_phandle_args args;
+
+ ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
+ NULL, 3, 0, &args);
+ if (ret)
+ return log_msg_ret("gpio-ranges", ret);
+
+ return args.args[2];
+}
+
static int qcom_gpio_of_to_plat(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ ret = qcom_gpio_of_parse_ranges(dev);
+ if (ret > 0)
+ uc_priv->gpio_count = ret;
+ else
+ return ret;
- uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
- uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
- if (uc_priv->bank_name == NULL)
- uc_priv->bank_name = "qcom_pmic";
+ uc_priv->bank_name = "pmic";
return 0;
}
@@ -272,104 +297,3 @@ U_BOOT_DRIVER(qcom_pmic_gpio) = {
.priv_auto = sizeof(struct qcom_gpio_bank),
};
-
-/* Add pmic buttons as GPIO as well - there is no generic way for now */
-#define PON_INT_RT_STS 0x10
-#define KPDPWR_ON_INT_BIT 0
-#define RESIN_ON_INT_BIT 1
-
-static int qcom_pwrkey_get_function(struct udevice *dev, unsigned offset)
-{
- return GPIOF_INPUT;
-}
-
-static int qcom_pwrkey_get_value(struct udevice *dev, unsigned offset)
-{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
-
- int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
-
- if (reg < 0)
- return 0;
-
- switch (offset) {
- case 0: /* Power button */
- return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
- break;
- case 1: /* Reset button */
- default:
- return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
- break;
- }
-}
-
-/*
- * Since pmic buttons modelled as GPIO, we need empty direction functions
- * to trick u-boot button driver
- */
-static int qcom_pwrkey_direction_input(struct udevice *dev, unsigned int offset)
-{
- return 0;
-}
-
-static int qcom_pwrkey_direction_output(struct udevice *dev, unsigned int offset, int value)
-{
- return -EOPNOTSUPP;
-}
-
-static const struct dm_gpio_ops qcom_pwrkey_ops = {
- .get_value = qcom_pwrkey_get_value,
- .get_function = qcom_pwrkey_get_function,
- .direction_input = qcom_pwrkey_direction_input,
- .direction_output = qcom_pwrkey_direction_output,
-};
-
-static int qcom_pwrkey_probe(struct udevice *dev)
-{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
- int reg;
-
- priv->pid = dev_read_addr(dev);
- if (priv->pid == FDT_ADDR_T_NONE)
- return log_msg_ret("bad address", -EINVAL);
-
- /* Do a sanity check */
- reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
- if (reg != 0x1)
- return log_msg_ret("bad type", -ENXIO);
-
- reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
- if ((reg & 0x5) == 0)
- return log_msg_ret("bad subtype", -ENXIO);
-
- return 0;
-}
-
-static int qcom_pwrkey_of_to_plat(struct udevice *dev)
-{
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-
- uc_priv->gpio_count = 2;
- uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
- if (uc_priv->bank_name == NULL)
- uc_priv->bank_name = "pwkey_qcom";
-
- return 0;
-}
-
-static const struct udevice_id qcom_pwrkey_ids[] = {
- { .compatible = "qcom,pm8916-pwrkey" },
- { .compatible = "qcom,pm8994-pwrkey" },
- { .compatible = "qcom,pm8998-pwrkey" },
- { }
-};
-
-U_BOOT_DRIVER(pwrkey_qcom) = {
- .name = "pwrkey_qcom",
- .id = UCLASS_GPIO,
- .of_match = qcom_pwrkey_ids,
- .of_to_plat = qcom_pwrkey_of_to_plat,
- .probe = qcom_pwrkey_probe,
- .ops = &qcom_pwrkey_ops,
- .priv_auto = sizeof(struct qcom_gpio_bank),
-};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e8e4400516f..e85a0dd51ca 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -527,13 +527,6 @@ config WINBOND_W83627
legacy UART or other devices in the Winbond Super IO chips
on X86 platforms.
-config QCOM_GENI_SE
- bool "Qualcomm GENI Serial Engine Driver"
- depends on ARCH_SNAPDRAGON
- help
- The driver manages Generic Interface (GENI) firmware based
- Qualcomm Technologies, Inc. Universal Peripheral (QUP) Wrapper.
-
config QFW
bool
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index cda701d38ec..6bf1e79f7e2 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -60,7 +60,6 @@ obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
-obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
ifdef CONFIG_QFW
obj-y += qfw.o
obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o
diff --git a/drivers/misc/qcom-geni-se.c b/drivers/misc/qcom-geni-se.c
deleted file mode 100644
index 281a5ec819a..00000000000
--- a/drivers/misc/qcom-geni-se.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Qualcomm Generic Interface (GENI) Serial Engine (SE) Wrapper
- *
- * Copyright (C) 2023 Linaro Ltd. <[email protected]>
- */
-
-#include <common.h>
-#include <dm.h>
-#include <misc.h>
-#include <asm/io.h>
-
-static int geni_se_qup_read(struct udevice *dev, int offset,
- void *buf, int size)
-{
- fdt_addr_t base = dev_read_addr(dev);
-
- if (size != sizeof(u32))
- return -EINVAL;
-
- *(u32 *)buf = readl(base + offset);
-
- return size;
-}
-
-static struct misc_ops geni_se_qup_ops = {
- .read = geni_se_qup_read,
-};
-
-static const struct udevice_id geni_se_qup_ids[] = {
- { .compatible = "qcom,geni-se-qup" },
- {}
-};
-
-U_BOOT_DRIVER(geni_se_qup) = {
- .name = "geni_se_qup",
- .id = UCLASS_MISC,
- .of_match = geni_se_qup_ids,
- .ops = &geni_se_qup_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index fceafea24c2..a1d53cfbdbe 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -355,6 +355,7 @@ source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/nexell/Kconfig"
source "drivers/pinctrl/nuvoton/Kconfig"
source "drivers/pinctrl/nxp/Kconfig"
+source "drivers/pinctrl/qcom/Kconfig"
source "drivers/pinctrl/renesas/Kconfig"
source "drivers/pinctrl/rockchip/Kconfig"
source "drivers/pinctrl/sunxi/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 96a0516fe08..0e929d8ca04 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_ARCH_ATH79) += ath79/
obj-$(CONFIG_PINCTRL_INTEL) += intel/
obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
obj-$(CONFIG_ARCH_NPCM) += nuvoton/
+obj-$(CONFIG_PINCTRL_QCOM) += qcom/
obj-$(CONFIG_ARCH_RMOBILE) += renesas/
obj-$(CONFIG_ARCH_RZN1) += renesas/
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
new file mode 100644
index 00000000000..2fe63981478
--- /dev/null
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -0,0 +1,46 @@
+if ARCH_SNAPDRAGON
+
+config PINCTRL_QCOM
+ depends on PINCTRL_GENERIC
+ def_bool n
+
+menu "Qualcomm pinctrl drivers"
+
+config PINCTRL_QCOM_APQ8016
+ bool "Qualcomm APQ8016 GCC"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the MSM8916 / APQ8016
+ Snapdragon 410 SoC, as well as the associated GPIO driver.
+
+config PINCTRL_QCOM_APQ8096
+ bool "Qualcomm APQ8096 GCC"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the MSM8996 / APQ8096
+ Snapdragon 820 SoC, as well as the associated GPIO driver.
+
+config PINCTRL_QCOM_IPQ4019
+ bool "Qualcomm IPQ4019 GCC"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the IPQ4019 SoC,
+ as well as the associated GPIO driver.
+
+config PINCTRL_QCOM_QCS404
+ bool "Qualcomm QCS404 GCC"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon QCS404 SoC,
+ as well as the associated GPIO driver.
+
+config PINCTRL_QCOM_SDM845
+ bool "Qualcomm SDM845 GCC"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon 845 SoC,
+ as well as the associated GPIO driver.
+
+endmenu
+
+endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
new file mode 100644
index 00000000000..6d9aca6d7b7
--- /dev/null
+++ b/drivers/pinctrl/qcom/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2023 Linaro Ltd.
+
+obj-$(CONFIG_PINCTRL_QCOM) += pinctrl-qcom.o
+obj-$(CONFIG_PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o
+obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o
+obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o
+obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o
+obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8016.c b/drivers/pinctrl/qcom/pinctrl-apq8016.c
new file mode 100644
index 00000000000..8149ffd83cc
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-apq8016.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm APQ8016 pinctrl
+ *
+ * (C) Copyright 2018 Ramon Fried <[email protected]>
+ *
+ */
+
+#include <common.h>
+#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 char * const msm_pinctrl_pins[] = {
+ "SDC1_CLK",
+ "SDC1_CMD",
+ "SDC1_DATA",
+ "SDC2_CLK",
+ "SDC2_CMD",
+ "SDC2_DATA",
+ "QDSD_CLK",
+ "QDSD_CMD",
+ "QDSD_DATA0",
+ "QDSD_DATA1",
+ "QDSD_DATA2",
+ "QDSD_DATA3",
+};
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ {"blsp1_uart", 2},
+};
+
+static const char *apq8016_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *apq8016_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector < 122) {
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ return pin_name;
+ } else {
+ return msm_pinctrl_pins[selector - 122];
+ }
+}
+
+static unsigned int apq8016_get_function_mux(unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static const struct msm_pinctrl_data apq8016_data = {
+ .pin_data = { .pin_count = 133, },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = apq8016_get_function_name,
+ .get_function_mux = apq8016_get_function_mux,
+ .get_pin_name = apq8016_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,msm8916-pinctrl", .data = (ulong)&apq8016_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_apq8016) = {
+ .name = "pinctrl_apq8016",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8096.c b/drivers/pinctrl/qcom/pinctrl-apq8096.c
new file mode 100644
index 00000000000..d64ab1ff7be
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-apq8096.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm APQ8096 pinctrl
+ *
+ * (C) Copyright 2019 Ramon Fried <[email protected]>
+ *
+ */
+
+#include <common.h>
+#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 char * const msm_pinctrl_pins[] = {
+ "SDC1_CLK",
+ "SDC1_CMD",
+ "SDC1_DATA",
+ "SDC2_CLK",
+ "SDC2_CMD",
+ "SDC2_DATA",
+ "SDC1_RCLK",
+};
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ {"blsp_uart8", 2},
+};
+
+static const char *apq8096_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *apq8096_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector < 150) {
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ return pin_name;
+ } else {
+ return msm_pinctrl_pins[selector - 150];
+ }
+}
+
+static unsigned int apq8096_get_function_mux(unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static const struct msm_pinctrl_data apq8096_data = {
+ .pin_data = { .pin_count = 157, },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = apq8096_get_function_name,
+ .get_function_mux = apq8096_get_function_mux,
+ .get_pin_name = apq8096_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,msm8996-pinctrl", .data = (ulong)&apq8096_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_apq8096) = {
+ .name = "pinctrl_apq8096",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
new file mode 100644
index 00000000000..2d99f99e1e4
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm IPQ40xx pinctrl
+ *
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <[email protected]>
+ */
+
+#include <common.h>
+#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[] = {
+ {"gpio", 0},
+ {"blsp_uart0_0", 1}, /* Only for GPIO:16,17 */
+ {"blsp_uart0_1", 2}, /* Only for GPIO:60,61 */
+ {"blsp_uart1", 1},
+ {"blsp_spi0_0", 1}, /* Only for GPIO:12,13,14,15 */
+ {"blsp_spi0_1", 2}, /* Only for GPIO:54,55,56,57 */
+ {"blsp_spi1", 2},
+ {"mdio_0", 1}, /* Only for GPIO6 */
+ {"mdio_1", 2}, /* Only for GPIO53 */
+ {"mdc_0", 1}, /* Only for GPIO7 */
+ {"mdc_1", 2}, /* Only for GPIO52 */
+};
+static const char *ipq4019_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *ipq4019_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ return pin_name;
+}
+
+static unsigned int ipq4019_get_function_mux(unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static const struct msm_pinctrl_data ipq4019_data = {
+ .pin_data = { .pin_count = 100, },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = ipq4019_get_function_name,
+ .get_function_mux = ipq4019_get_function_mux,
+ .get_pin_name = ipq4019_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,ipq4019-pinctrl", .data = (ulong)&ipq4019_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_ipq4019) = {
+ .name = "pinctrl_ipq4019",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
new file mode 100644
index 00000000000..dc3d8c4d903
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TLMM driver for Qualcomm APQ8016, APQ8096
+ *
+ * (C) Copyright 2018 Ramon Fried <[email protected]>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <asm/gpio.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <mach/gpio.h>
+
+#include "pinctrl-qcom.h"
+
+struct msm_pinctrl_priv {
+ phys_addr_t base;
+ struct msm_pinctrl_data *data;
+};
+
+#define GPIO_CONFIG_REG(priv, x) \
+ (qcom_pin_offset((priv)->data->pin_data.pin_offsets, x))
+
+#define TLMM_GPIO_PULL_MASK GENMASK(1, 0)
+#define TLMM_FUNC_SEL_MASK GENMASK(5, 2)
+#define TLMM_DRV_STRENGTH_MASK GENMASK(8, 6)
+#define TLMM_GPIO_DISABLE BIT(9)
+
+static const struct pinconf_param msm_conf_params[] = {
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 2 },
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 3 },
+};
+
+static int msm_get_functions_count(struct udevice *dev)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->data->functions_count;
+}
+
+static int msm_get_pins_count(struct udevice *dev)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->data->pin_data.pin_count;
+}
+
+static const char *msm_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->data->get_function_name(dev, selector);
+}
+
+static int msm_pinctrl_probe(struct udevice *dev)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
+
+ return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
+}
+
+static const char *msm_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->data->get_pin_name(dev, selector);
+}
+
+static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
+ unsigned int func_selector)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
+ TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
+ priv->data->get_function_mux(func_selector) << 2);
+ return 0;
+}
+
+static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
+ unsigned int param, unsigned int argument)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ argument = (argument / 2) - 1;
+ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
+ TLMM_DRV_STRENGTH_MASK, argument << 6);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ clrbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
+ TLMM_GPIO_PULL_MASK);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
+ TLMM_GPIO_PULL_MASK, argument);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+struct pinctrl_ops msm_pinctrl_ops = {
+ .get_pins_count = msm_get_pins_count,
+ .get_pin_name = msm_get_pin_name,
+ .set_state = pinctrl_generic_set_state,
+ .pinmux_set = msm_pinmux_set,
+ .pinconf_num_params = ARRAY_SIZE(msm_conf_params),
+ .pinconf_params = msm_conf_params,
+ .pinconf_set = msm_pinconf_set,
+ .get_functions_count = msm_get_functions_count,
+ .get_function_name = msm_get_function_name,
+};
+
+int msm_pinctrl_bind(struct udevice *dev)
+{
+ ofnode node = dev_ofnode(dev);
+ struct msm_pinctrl_data *data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
+ struct driver *drv;
+ struct udevice *pinctrl_dev;
+ const char *name;
+ int ret;
+
+ drv = lists_driver_lookup_name("pinctrl_qcom");
+ if (!drv)
+ return -ENOENT;
+
+ ret = device_bind_with_driver_data(dev_get_parent(dev), drv, ofnode_get_name(node), (ulong)data,
+ dev_ofnode(dev), &pinctrl_dev);
+ if (ret)
+ return ret;
+
+ ofnode_get_property(node, "gpio-controller", &ret);
+ if (ret < 0)
+ return 0;
+
+ /* Get the name of gpio node */
+ name = ofnode_get_name(node);
+ if (!name)
+ return -EINVAL;
+
+ drv = lists_driver_lookup_name("gpio_msm");
+ if (!drv) {
+ printf("Can't find gpio_msm driver\n");
+ return -ENODEV;
+ }
+
+ /* Bind gpio device as a child of the pinctrl device */
+ ret = device_bind_with_driver_data(pinctrl_dev, drv,
+ name, (ulong)&data->pin_data, node, NULL);
+ if (ret) {
+ device_unbind(pinctrl_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(pinctrl_qcom) = {
+ .name = "pinctrl_qcom",
+ .id = UCLASS_PINCTRL,
+ .priv_auto = sizeof(struct msm_pinctrl_priv),
+ .ops = &msm_pinctrl_ops,
+ .probe = msm_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.h b/drivers/pinctrl/qcom/pinctrl-qcom.h
new file mode 100644
index 00000000000..07f2eae9bae
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Qualcomm Pin control
+ *
+ * (C) Copyright 2018 Ramon Fried <[email protected]>
+ *
+ */
+#ifndef _PINCTRL_QCOM_H
+#define _PINCTRL_QCOM_H
+
+#include <asm/types.h>
+#include <mach/gpio.h>
+
+struct udevice;
+
+struct msm_pinctrl_data {
+ struct msm_pin_data pin_data;
+ int functions_count;
+ const char *(*get_function_name)(struct udevice *dev,
+ unsigned int selector);
+ unsigned int (*get_function_mux)(unsigned int selector);
+ const char *(*get_pin_name)(struct udevice *dev,
+ unsigned int selector);
+};
+
+struct pinctrl_function {
+ const char *name;
+ int val;
+};
+
+extern struct pinctrl_ops msm_pinctrl_ops;
+
+int msm_pinctrl_bind(struct udevice *dev);
+
+#endif
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
new file mode 100644
index 00000000000..ac00afa2a1f
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm QCS404 pinctrl
+ *
+ * (C) Copyright 2022 Sumit Garg <[email protected]>
+ */
+
+#include <common.h>
+#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 char * const msm_pinctrl_pins[] = {
+ "SDC1_RCLK",
+ "SDC1_CLK",
+ "SDC1_CMD",
+ "SDC1_DATA",
+ "SDC2_CLK",
+ "SDC2_CMD",
+ "SDC2_DATA",
+};
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ {"blsp_uart2", 1},
+ {"rgmii_int", 1},
+ {"rgmii_ck", 1},
+ {"rgmii_tx", 1},
+ {"rgmii_ctl", 1},
+ {"rgmii_rx", 1},
+ {"rgmii_mdio", 1},
+ {"rgmii_mdc", 1},
+ {"blsp_i2c0", 3},
+ {"blsp_i2c1", 2},
+ {"blsp_i2c_sda_a2", 3},
+ {"blsp_i2c_scl_a2", 3},
+ {"blsp_i2c3", 2},
+ {"blsp_i2c4", 1},
+};
+
+static const char *qcs404_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *qcs404_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector < 120) {
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ return pin_name;
+ } else {
+ return msm_pinctrl_pins[selector - 120];
+ }
+}
+
+static unsigned int qcs404_get_function_mux(unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static struct msm_pinctrl_data qcs404_data = {
+ .pin_data = { .pin_count = 126, },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = qcs404_get_function_name,
+ .get_function_mux = qcs404_get_function_mux,
+ .get_pin_name = qcs404_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,qcs404-pinctrl", .data = (ulong)&qcs404_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_qcs404) = {
+ .name = "pinctrl_qcs404",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
new file mode 100644
index 00000000000..9f0f4085ce2
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm SDM845 pinctrl
+ *
+ * (C) Copyright 2021 Dzmitry Sankouski <[email protected]>
+ * (C) Copyright 2023 Linaro Ltd.
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define NORTH 0x00500000
+#define SOUTH 0x00900000
+#define EAST 0x00100000
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ {"qup9", 1},
+ {"gpio", 0},
+};
+
+static const unsigned int sdm845_pin_offsets[] = {
+ [0] = EAST, [1] = EAST, [2] = EAST, [3] = EAST, [4] = NORTH,
+ [5] = NORTH, [6] = NORTH, [7] = NORTH, [8] = EAST, [9] = EAST,
+ [10] = EAST, [11] = EAST, [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] = EAST, [28] = EAST, [29] = EAST,
+ [30] = EAST, [31] = NORTH, [32] = NORTH, [33] = NORTH, [34] = NORTH,
+ [35] = SOUTH, [36] = SOUTH, [37] = SOUTH, [38] = NORTH, [39] = EAST,
+ [40] = SOUTH, [41] = EAST, [42] = EAST, [43] = EAST, [44] = EAST,
+ [45] = EAST, [46] = EAST, [47] = EAST, [48] = EAST, [49] = NORTH,
+ [50] = NORTH, [51] = NORTH, [52] = NORTH, [53] = NORTH, [54] = NORTH,
+ [55] = NORTH, [56] = NORTH, [57] = NORTH, [58] = NORTH, [59] = NORTH,
+ [60] = NORTH, [61] = NORTH, [62] = NORTH, [63] = NORTH, [64] = NORTH,
+ [65] = NORTH, [66] = NORTH, [67] = NORTH, [68] = NORTH, [69] = EAST,
+ [70] = EAST, [71] = EAST, [72] = EAST, [73] = EAST, [74] = EAST,
+ [75] = EAST, [76] = EAST, [77] = EAST, [78] = EAST, [79] = NORTH,
+ [80] = NORTH, [81] = NORTH, [82] = NORTH, [83] = NORTH, [84] = NORTH,
+ [85] = EAST, [86] = EAST, [87] = EAST, [88] = EAST, [89] = SOUTH,
+ [90] = SOUTH, [91] = SOUTH, [92] = SOUTH, [93] = SOUTH, [94] = SOUTH,
+ [95] = SOUTH, [96] = SOUTH, [97] = NORTH, [98] = NORTH, [99] = NORTH,
+ [100] = NORTH, [101] = NORTH, [102] = NORTH, [103] = NORTH, [104] = NORTH,
+ [105] = NORTH, [106] = NORTH, [107] = NORTH, [108] = NORTH, [109] = NORTH,
+ [110] = NORTH, [111] = NORTH, [112] = NORTH, [113] = NORTH, [114] = NORTH,
+ [115] = NORTH, [116] = NORTH, [117] = NORTH, [118] = NORTH, [119] = NORTH,
+ [120] = NORTH, [121] = NORTH, [122] = EAST, [123] = EAST, [124] = EAST,
+ [125] = EAST, [126] = EAST, [127] = NORTH, [128] = NORTH, [129] = NORTH,
+ [130] = NORTH, [131] = NORTH, [132] = NORTH, [133] = NORTH, [134] = NORTH,
+ [135] = NORTH, [136] = NORTH, [137] = NORTH, [138] = NORTH, [139] = NORTH,
+ [140] = NORTH, [141] = NORTH, [142] = NORTH, [143] = NORTH, [144] = NORTH,
+ [145] = NORTH, [146] = NORTH, [147] = NORTH, [148] = NORTH, [149] = NORTH,
+};
+
+static const char *sdm845_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *sdm845_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+ return pin_name;
+}
+
+static unsigned int sdm845_get_function_mux(unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static struct msm_pinctrl_data sdm845_data = {
+ .pin_data = {
+ .pin_offsets = sdm845_pin_offsets,
+ .pin_count = ARRAY_SIZE(sdm845_pin_offsets),
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = sdm845_get_function_name,
+ .get_function_mux = sdm845_get_function_mux,
+ .get_pin_name = sdm845_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,sdm845-pinctrl", .data = (ulong)&sdm845_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_sdm845) = {
+ .name = "pinctrl_sdm845",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/power/pmic/pmic_qcom.c b/drivers/power/pmic/pmic_qcom.c
index ad8daf43f06..f2ac6494811 100644
--- a/drivers/power/pmic/pmic_qcom.c
+++ b/drivers/power/pmic/pmic_qcom.c
@@ -66,12 +66,19 @@ static const struct udevice_id pmic_qcom_ids[] = {
static int pmic_qcom_probe(struct udevice *dev)
{
struct pmic_qcom_priv *priv = dev_get_priv(dev);
-
- priv->usid = dev_read_addr(dev);
-
- if (priv->usid == FDT_ADDR_T_NONE)
+ int ret;
+
+ /*
+ * dev_read_addr() can't be used here because the reg property actually
+ * contains two discrete values, not a single 64-bit address.
+ * The address is the first value.
+ */
+ ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, &priv->usid);
+ if (ret < 0)
return -EINVAL;
+ debug("usid: %d\n", priv->usid);
+
return 0;
}
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 73bbd306925..88e04d93f2a 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -156,13 +156,6 @@ config RESET_IMX7
help
Support for reset controller on i.MX7/8 SoCs.
-config RESET_QCOM
- bool "Reset driver for Qualcomm SoCs"
- depends on DM_RESET && (ARCH_SNAPDRAGON || ARCH_IPQ40XX)
- default y
- help
- Support for reset controller on Qualcomm SoCs.
-
config RESET_SIFIVE
bool "Reset Driver for SiFive SoC's"
depends on DM_RESET && CLK_SIFIVE_PRCI && (TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED)
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index e2239a250a3..7b0066f8018 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -24,7 +24,6 @@ obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
-obj-$(CONFIG_RESET_QCOM) += reset-qcom.o
obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o
obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o
obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6628a887de7..26460c4e0ca 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -972,8 +972,6 @@ config MSM_SERIAL
config MSM_GENI_SERIAL
bool "Qualcomm on-chip GENI UART"
- select MISC
- imply QCOM_GENI_SE
help
Support UART based on Generic Interface (GENI) Serial Engine (SE),
used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index b8bc61451a0..e5c3dcffc1c 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -188,8 +188,8 @@ static int geni_serial_set_clock_rate(struct udevice *dev, u64 rate)
int ret;
clk = devm_clk_get(dev, NULL);
- if (!clk)
- return -EINVAL;
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
ret = clk_set_rate(clk, rate);
return ret;
@@ -248,11 +248,16 @@ static int msm_serial_setbrg(struct udevice *dev, int baud)
struct msm_serial_data *priv = dev_get_priv(dev);
u64 clk_rate;
u32 clk_div;
+ int ret;
priv->baud = baud;
clk_rate = get_clk_div_rate(baud, priv->oversampling, &clk_div);
- geni_serial_set_clock_rate(dev, clk_rate);
+ ret = geni_serial_set_clock_rate(dev, clk_rate);
+ if (ret < 0) {
+ pr_err("%s: Couldn't set clock rate: %d\n", __func__, ret);
+ return ret;
+ }
geni_serial_baud(priv->base, clk_div, baud);
return 0;
@@ -485,12 +490,12 @@ static const struct dm_serial_ops msm_serial_ops = {
.setbrg = msm_serial_setbrg,
};
-static void geni_set_oversampling(struct udevice *dev)
+static int geni_set_oversampling(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
- struct udevice *parent_dev = dev_get_parent(dev);
+ ofnode parent_node = ofnode_get_parent(dev_ofnode(dev));
u32 geni_se_version;
- int ret;
+ fdt_addr_t addr;
priv->oversampling = UART_OVERSAMPLING;
@@ -498,16 +503,20 @@ static void geni_set_oversampling(struct udevice *dev)
* It could happen that GENI SE IP is missing in the board's device
* tree or GENI UART node is a direct child of SoC device tree node.
*/
- if (device_get_uclass_id(parent_dev) != UCLASS_MISC)
- return;
+ if (!ofnode_device_is_compatible(parent_node, "qcom,geni-se-qup")) {
+ pr_err("%s: UART node must be a child of geniqup node\n",
+ __func__);
+ return -ENODEV;
+ }
- ret = misc_read(parent_dev, QUP_HW_VER_REG,
- &geni_se_version, sizeof(geni_se_version));
- if (ret != sizeof(geni_se_version))
- return;
+ /* Read the HW_VER register relative to the parents address space */
+ addr = ofnode_get_addr(parent_node);
+ geni_se_version = readl(addr + QUP_HW_VER_REG);
if (geni_se_version >= QUP_SE_VERSION_2_5)
priv->oversampling /= 2;
+
+ return 0;
}
static inline void geni_serial_init(struct udevice *dev)
@@ -552,8 +561,11 @@ static inline void geni_serial_init(struct udevice *dev)
static int msm_serial_probe(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
+ int ret;
- geni_set_oversampling(dev);
+ ret = geni_set_oversampling(dev);
+ if (ret < 0)
+ return ret;
/* No need to reinitialize the UART after relocation */
if (gd->flags & GD_FLG_RELOC)
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index 27a035c0a59..5fe8a70abca 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -70,7 +70,7 @@ enum pmic_arb_channel {
struct msm_spmi_priv {
phys_addr_t arb_chnl; /* ARB channel mapping base */
- phys_addr_t spmi_core; /* SPMI core */
+ phys_addr_t spmi_chnls; /* SPMI channels */
phys_addr_t spmi_obs; /* SPMI observer */
/* SPMI channel map */
uint8_t channel_map[SPMI_MAX_SLAVES][SPMI_MAX_PERIPH];
@@ -95,10 +95,10 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
/* Disable IRQ mode for the current channel*/
writel(0x0,
- priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG);
+ priv->spmi_chnls + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG);
/* Write single byte */
- writel(val, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_WDATA);
+ writel(val, priv->spmi_chnls + SPMI_CH_OFFSET(channel) + SPMI_REG_WDATA);
/* Prepare write command */
reg |= SPMI_CMD_EXT_REG_WRITE_LONG << SPMI_CMD_OPCODE_SHIFT;
@@ -113,12 +113,12 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
ch_offset = SPMI_CH_OFFSET(channel);
/* Send write command */
- writel(reg, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0);
+ writel(reg, priv->spmi_chnls + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0);
/* Wait till CMD DONE status */
reg = 0;
while (!reg) {
- reg = readl(priv->spmi_core + SPMI_CH_OFFSET(channel) +
+ reg = readl(priv->spmi_chnls + SPMI_CH_OFFSET(channel) +
SPMI_REG_STATUS);
}
@@ -186,47 +186,37 @@ static struct dm_spmi_ops msm_spmi_ops = {
static int msm_spmi_probe(struct udevice *dev)
{
struct msm_spmi_priv *priv = dev_get_priv(dev);
- phys_addr_t config_addr;
+ phys_addr_t core_addr;
u32 hw_ver;
- u32 version;
int i;
- int err;
- config_addr = dev_read_addr_index(dev, 0);
- priv->spmi_core = dev_read_addr_index(dev, 1);
- priv->spmi_obs = dev_read_addr_index(dev, 2);
+ core_addr = dev_read_addr_name(dev, "core");
+ priv->spmi_chnls = dev_read_addr_name(dev, "chnls");
+ priv->spmi_obs = dev_read_addr_name(dev, "obsrvr");
- hw_ver = readl(config_addr + PMIC_ARB_VERSION);
+ hw_ver = readl(core_addr + PMIC_ARB_VERSION);
if (hw_ver < PMIC_ARB_VERSION_V3_MIN) {
priv->arb_ver = V2;
- version = 2;
- priv->arb_chnl = config_addr + APID_MAP_OFFSET_V1_V2_V3;
+ priv->arb_chnl = core_addr + APID_MAP_OFFSET_V1_V2_V3;
} else if (hw_ver < PMIC_ARB_VERSION_V5_MIN) {
priv->arb_ver = V3;
- version = 3;
- priv->arb_chnl = config_addr + APID_MAP_OFFSET_V1_V2_V3;
+ priv->arb_chnl = core_addr + APID_MAP_OFFSET_V1_V2_V3;
} else {
priv->arb_ver = V5;
- version = 5;
- priv->arb_chnl = config_addr + APID_MAP_OFFSET_V5;
-
- if (err) {
- dev_err(dev, "could not read APID->PPID mapping table, rc= %d\n", err);
- return -1;
- }
+ priv->arb_chnl = core_addr + APID_MAP_OFFSET_V5;
}
- dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", version, hw_ver);
+ dev_dbg(dev, "PMIC Arb Version-%d (%#x)\n", hw_ver >> 28, hw_ver);
if (priv->arb_chnl == FDT_ADDR_T_NONE ||
- priv->spmi_core == FDT_ADDR_T_NONE ||
+ priv->spmi_chnls == FDT_ADDR_T_NONE ||
priv->spmi_obs == FDT_ADDR_T_NONE)
return -EINVAL;
- dev_dbg(dev, "priv->arb_chnl address (%llu)\n", priv->arb_chnl);
- dev_dbg(dev, "priv->spmi_core address (%llu)\n", priv->spmi_core);
- dev_dbg(dev, "priv->spmi_obs address (%llu)\n", priv->spmi_obs);
+ dev_dbg(dev, "priv->arb_chnl address (%#08llx)\n", priv->arb_chnl);
+ dev_dbg(dev, "priv->spmi_chnls address (%#08llx)\n", priv->spmi_chnls);
+ dev_dbg(dev, "priv->spmi_obs address (%#08llx)\n", priv->spmi_obs);
/* Scan peripherals connected to each SPMI channel */
for (i = 0; i < SPMI_MAX_PERIPH; i++) {
uint32_t periph = readl(priv->arb_chnl + ARB_CHANNEL_OFFSET(i));