aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-07-05 10:22:53 -0600
committerTom Rini <trini@konsulko.com>2024-07-05 10:24:27 -0600
commit18908395edcee8450d742c670610557751866393 (patch)
tree7bb7fc29e834cddc01f101e80ca95f5bd1e7810f /drivers
parentd12e1029133aed42c5086c04a22ece0fe597e704 (diff)
parent69b37f1625ac0c9d0c867d591564af91c0b52d18 (diff)
downloadu-boot-18908395edcee8450d742c670610557751866393.zip
u-boot-18908395edcee8450d742c670610557751866393.tar.gz
u-boot-18908395edcee8450d742c670610557751866393.tar.bz2
Merge branch 'qcom-main' of https://source.denx.de/u-boot/custodians/u-boot-snapdragon
Various minor fixes and improvements: * Fix Qualcomm SPMI v5 support * Move default environment to a file * Add support for special pins (e.g ufs/mmc reset/data pins) * IPQ moves to OF_UPSTREAM and receives some cleanup and MAINTAINERS changes * Add a reset driver for devices without PSCI * msm8916 USB clock improvements for mobile devices
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/qcom/clock-apq8016.c32
-rw-r--r--drivers/clk/qcom/clock-ipq4019.c21
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.c38
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8550.c42
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8650.c42
-rw-r--r--drivers/spmi/spmi-msm.c6
-rw-r--r--drivers/sysreset/Kconfig6
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset_qcom-pshold.c55
-rw-r--r--drivers/usb/host/ehci-msm.c37
10 files changed, 257 insertions, 23 deletions
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
index 41fe4d8..b5def55 100644
--- a/drivers/clk/qcom/clock-apq8016.c
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -16,6 +16,8 @@
#include "clock-qcom.h"
+#define USB_HS_SYSTEM_CLK_CMD_RCGR 0x41010
+
/* Clocks: (from CLK_CTL_BASE) */
#define GPLL0_STATUS (0x2101C)
#define APCS_GPLL_ENA_VOTE (0x45000)
@@ -51,6 +53,11 @@ static struct vote_clk gcc_blsp1_ahb_clk = {
.vote_bit = BIT(10),
};
+static const struct gate_clk apq8016_clks[] = {
+ GATE_CLK(GCC_USB_HS_AHB_CLK, 0x41008, 0x00000001),
+ GATE_CLK(GCC_USB_HS_SYSTEM_CLK, 0x41004, 0x00000001),
+};
+
/* SDHCI */
static int apq8016_clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate)
{
@@ -116,13 +123,38 @@ static ulong apq8016_clk_set_rate(struct clk *clk, ulong rate)
case GCC_BLSP1_UART2_APPS_CLK: /* UART2 */
apq8016_clk_init_uart(priv->base, clk->id);
return 7372800;
+ case GCC_USB_HS_SYSTEM_CLK:
+ if (rate != 80000000)
+ log_warning("Unexpected rate %ld requested for USB_HS_SYSTEM_CLK\n",
+ rate);
+ clk_rcg_set_rate_mnd(priv->base, USB_HS_SYSTEM_CLK_CMD_RCGR,
+ 10, 0, 0, CFG_CLK_SRC_GPLL0, 0);
+ return rate;
default:
return 0;
}
}
+static int apq8016_clk_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (priv->data->num_clks < clk->id) {
+ log_warning("%s: unknown clk id %lu\n", __func__, clk->id);
+ return 0;
+ }
+
+ debug("%s: clk %s\n", __func__, apq8016_clks[clk->id].name);
+ qcom_gate_clk_en(priv, clk->id);
+
+ return 0;
+}
+
static struct msm_clk_data apq8016_clk_data = {
.set_rate = apq8016_clk_set_rate,
+ .clks = apq8016_clks,
+ .num_clks = ARRAY_SIZE(apq8016_clks),
+ .enable = apq8016_clk_enable,
};
static const struct udevice_id gcc_apq8016_of_match[] = {
diff --git a/drivers/clk/qcom/clock-ipq4019.c b/drivers/clk/qcom/clock-ipq4019.c
index 0e6d93b..9352ff4 100644
--- a/drivers/clk/qcom/clock-ipq4019.c
+++ b/drivers/clk/qcom/clock-ipq4019.c
@@ -15,6 +15,12 @@
#include "clock-qcom.h"
+/* I2C controller clock control registerss */
+#define BLSP1_QUP1_I2C_APPS_CBCR (0x2008)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR (0x200C)
+#define BLSP1_QUP2_I2C_APPS_CBCR (0x3010)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR (0x3000)
+
static ulong ipq4019_clk_set_rate(struct clk *clk, ulong rate)
{
switch (clk->id) {
@@ -28,7 +34,22 @@ static ulong ipq4019_clk_set_rate(struct clk *clk, ulong rate)
static int ipq4019_clk_enable(struct clk *clk)
{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
switch (clk->id) {
+ case GCC_BLSP1_AHB_CLK:
+ /* This clock is already initialized by SBL1 */
+ return 0;
+ 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_CMD_RCGR, 0,
+ CFG_CLK_SRC_CXO);
+ return 0;
+ 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_CMD_RCGR, 0,
+ CFG_CLK_SRC_CXO);
+ return 0;
case GCC_BLSP1_QUP1_SPI_APPS_CLK: /*SPI1*/
/* This clock is already initialized by SBL1 */
return 0;
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index 3c3336e..26a3fba 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -44,6 +44,7 @@ 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 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "output-high", PIN_CONFIG_OUTPUT, 1, },
{ "output-low", PIN_CONFIG_OUTPUT, 0, },
};
@@ -102,14 +103,47 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
return 0;
}
+static int msm_pinconf_set_special(struct msm_pinctrl_priv *priv, unsigned int pin_selector,
+ unsigned int param, unsigned int argument)
+{
+ unsigned int offset = pin_selector - priv->data->pin_data.special_pins_start;
+ const struct msm_special_pin_data *data;
+
+ if (!priv->data->pin_data.special_pins_data)
+ return 0;
+
+ data = &priv->data->pin_data.special_pins_data[offset];
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ argument = (argument / 2) - 1;
+ clrsetbits_le32(priv->base + data->ctl_reg,
+ GENMASK(2, 0) << data->drv_bit,
+ argument << data->drv_bit);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ clrbits_le32(priv->base + data->ctl_reg,
+ TLMM_GPIO_PULL_MASK << data->pull_bit);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ clrsetbits_le32(priv->base + data->ctl_reg,
+ TLMM_GPIO_PULL_MASK << data->pull_bit,
+ argument << data->pull_bit);
+ break;
+ default:
+ return 0;
+ }
+
+ 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);
- /* Always NOP for special pins */
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
- return 0;
+ return msm_pinconf_set_special(priv, pin_selector, param, argument);
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c
index 7265cb7..c65dfe0 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8550.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c
@@ -18,6 +18,37 @@ static const struct pinctrl_function msm_pinctrl_functions[] = {
{"gpio", 0},
};
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+#define UFS_RESET(pg_name, ctl, io) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = io, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", 0xde000, 0xde004),
+ [1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xd6000, 14, 6),
+ [2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xd6000, 11, 3),
+ [3] = SDC_QDSD_PINGROUP("sdc2_data", 0xd6000, 9, 0),
+};
+
static const char *sm8550_get_function_name(struct udevice *dev,
unsigned int selector)
{
@@ -27,15 +58,9 @@ static const char *sm8550_get_function_name(struct udevice *dev,
static const char *sm8550_get_pin_name(struct udevice *dev,
unsigned int selector)
{
- static const char *special_pins_names[] = {
- "ufs_reset",
- "sdc2_clk",
- "sdc2_cmd",
- "sdc2_data",
- };
-
if (selector >= 210 && selector <= 213)
- snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 210]);
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ msm_special_pins_data[selector - 210].name);
else
snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
@@ -52,6 +77,7 @@ static struct msm_pinctrl_data sm8550_data = {
.pin_data = {
.pin_count = 214,
.special_pins_start = 210,
+ .special_pins_data = msm_special_pins_data,
},
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = sm8550_get_function_name,
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650.c b/drivers/pinctrl/qcom/pinctrl-sm8650.c
index d6cc1bb..58fc94e 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8650.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8650.c
@@ -18,6 +18,37 @@ static const struct pinctrl_function msm_pinctrl_functions[] = {
{"gpio", 0},
};
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+#define UFS_RESET(pg_name, ctl, io) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = io, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", 0xde004, 0xdf000),
+ [1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xd6000, 14, 6),
+ [2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xd6000, 11, 3),
+ [3] = SDC_QDSD_PINGROUP("sdc2_data", 0xd6000, 9, 0),
+};
+
static const char *sm8650_get_function_name(struct udevice *dev,
unsigned int selector)
{
@@ -27,15 +58,9 @@ static const char *sm8650_get_function_name(struct udevice *dev,
static const char *sm8650_get_pin_name(struct udevice *dev,
unsigned int selector)
{
- static const char *special_pins_names[] = {
- "ufs_reset",
- "sdc2_clk",
- "sdc2_cmd",
- "sdc2_data",
- };
-
if (selector >= 210 && selector <= 213)
- snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 210]);
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ msm_special_pins_data[selector - 210].name);
else
snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
@@ -52,6 +77,7 @@ static struct msm_pinctrl_data sm8650_data = {
.pin_data = {
.pin_count = 214,
.special_pins_start = 210,
+ .special_pins_data = msm_special_pins_data,
},
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = sm8650_get_function_name,
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index b0d6226..5cc5a9e 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -119,7 +119,7 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
channel = priv->channel_map[usid][pid] & SPMI_CHANNEL_MASK;
- dev_dbg(dev, "[%d:%d] %s: channel %d\n", usid, pid, __func__, channel);
+ debug("%s: [%d:%d] %s: channel %d\n", dev->name, usid, pid, __func__, channel);
switch (priv->arb_ver) {
case V1:
@@ -186,7 +186,7 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
channel = priv->channel_map[usid][pid] & SPMI_CHANNEL_MASK;
- dev_dbg(dev, "[%d:%d] %s: channel %d\n", usid, pid, __func__, channel);
+ debug("%s: [%d:%d] %s: channel %d\n", dev->name, usid, pid, __func__, channel);
switch (priv->arb_ver) {
case V1:
@@ -271,7 +271,7 @@ static int msm_spmi_probe(struct udevice *dev)
} else if (hw_ver < PMIC_ARB_VERSION_V7_MIN) {
priv->arb_ver = V5;
priv->arb_chnl = core_addr + APID_MAP_OFFSET_V5;
- priv->max_channels = SPMI_MAX_CHANNELS;
+ priv->max_channels = SPMI_MAX_CHANNELS_V5;
priv->spmi_cnfg = dev_read_addr_name(dev, "cnfg");
} else {
/* TOFIX: handle second bus */
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index b64bfad..121194e 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -240,6 +240,12 @@ config SYSRESET_RAA215300
help
Add support for the system reboot via the Renesas RAA215300 PMIC.
+config SYSRESET_QCOM_PSHOLD
+ bool "Support sysreset for Qualcomm SoCs via PSHOLD"
+ depends on ARCH_IPQ40XX
+ help
+ Add support for the system reboot on Qualcomm SoCs via PSHOLD.
+
endif
endmenu
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index d59299a..a6a0584 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -29,4 +29,5 @@ obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o
obj-$(CONFIG_$(SPL_TPL_)SYSRESET_AT91) += sysreset_at91.o
obj-$(CONFIG_$(SPL_TPL_)SYSRESET_X86) += sysreset_x86.o
obj-$(CONFIG_SYSRESET_RAA215300) += sysreset_raa215300.o
+obj-$(CONFIG_SYSRESET_QCOM_PSHOLD) += sysreset_qcom-pshold.o
obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
diff --git a/drivers/sysreset/sysreset_qcom-pshold.c b/drivers/sysreset/sysreset_qcom-pshold.c
new file mode 100644
index 0000000..4529047
--- /dev/null
+++ b/drivers/sysreset/sysreset_qcom-pshold.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm PSHOLD reset driver
+ *
+ * Copyright (c) 2024 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ * Based on the Linux msm-poweroff driver.
+ *
+ */
+
+#include <dm.h>
+#include <sysreset.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+struct qcom_pshold_priv {
+ phys_addr_t base;
+};
+
+static int qcom_pshold_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct qcom_pshold_priv *priv = dev_get_priv(dev);
+
+ writel(0, priv->base);
+ mdelay(10000);
+
+ return 0;
+}
+
+static struct sysreset_ops qcom_pshold_ops = {
+ .request = qcom_pshold_request,
+};
+
+static int qcom_pshold_probe(struct udevice *dev)
+{
+ struct qcom_pshold_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
+}
+
+static const struct udevice_id qcom_pshold_ids[] = {
+ { .compatible = "qcom,pshold", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(qcom_pshold) = {
+ .name = "qcom_pshold",
+ .id = UCLASS_SYSRESET,
+ .of_match = qcom_pshold_ids,
+ .probe = qcom_pshold_probe,
+ .priv_auto = sizeof(struct qcom_pshold_priv),
+ .ops = &qcom_pshold_ops,
+};
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index a081f71..ff33608 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -7,7 +7,9 @@
* Based on Linux driver
*/
+#include <clk.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <dm/lists.h>
#include <errno.h>
#include <usb.h>
@@ -24,6 +26,8 @@ struct msm_ehci_priv {
struct usb_ehci *ehci; /* Start of IP core*/
struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
struct phy phy;
+ struct clk iface_clk;
+ struct clk core_clk;
};
static int msm_init_after_reset(struct ehci_ctrl *dev)
@@ -52,20 +56,46 @@ static int ehci_usb_probe(struct udevice *dev)
struct ehci_hcor *hcor;
int ret;
+ ret = clk_get_by_name(dev, "core", &p->core_clk);
+ if (ret) {
+ dev_err(dev, "Failed to get core clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "iface", &p->iface_clk);
+ if (ret) {
+ dev_err(dev, "Failed to get iface clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(&p->core_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(&p->iface_clk);
+ if (ret)
+ goto cleanup_core;
+
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
ret = generic_setup_phy(dev, &p->phy, 0);
if (ret)
- return ret;
+ goto cleanup_iface;
ret = board_usb_init(0, plat->init_type);
if (ret < 0)
- return ret;
+ goto cleanup_iface;
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
plat->init_type);
+
+cleanup_iface:
+ clk_disable_unprepare(&p->iface_clk);
+cleanup_core:
+ clk_disable_unprepare(&p->core_clk);
+ return ret;
}
static int ehci_usb_remove(struct udevice *dev)
@@ -81,6 +111,9 @@ static int ehci_usb_remove(struct udevice *dev)
/* Stop controller. */
clrbits_le32(&ehci->usbcmd, CMD_RUN);
+ clk_disable_unprepare(&p->iface_clk);
+ clk_disable_unprepare(&p->core_clk);
+
ret = generic_shutdown_phy(&p->phy);
if (ret)
return ret;