summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-04-27 08:05:40 -0600
committerTom Rini <[email protected]>2026-04-27 08:05:40 -0600
commite0991f42aa7f973e09f38bbe60cd12b28a46e491 (patch)
tree66619177875432ae895a1e068532bfaa036b686e
parent1a4cb8dc03810f2fb0b1499e26bae32e5116df4c (diff)
parentfabf5878bb86b3e1e2b19301afc2a9180bf79cf6 (diff)
Merge branch 'casey/qcom-main-13Apr2026' of https://source.denx.de/u-boot/custodians/u-boot-snapdragon
Various Qualcomm additions this cycle: * USB superspeed support for 1 platform * Initial support for the Milos platform and the Fairphone Gen 6 (chainloaded from ABL) * Improved support for booting with OP-TEE on supported platforms * Initial basic power domain support Notably there is a generic change to the device core, missing power domains will no longer cause a device to fail probe and instead will just print a warning. This shouldn't affect any existing platforms.
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/arm/cpu/armv8/fwcall.c15
-rw-r--r--arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi4
-rw-r--r--arch/arm/include/asm/system.h1
-rw-r--r--arch/arm/mach-snapdragon/board.c5
-rw-r--r--arch/arm/mach-snapdragon/of_fixup.c172
-rw-r--r--board/qualcomm/debug-milos.config5
-rw-r--r--board/qualcomm/tfa-optee.config4
-rw-r--r--cmd/boot.c3
-rw-r--r--configs/qcm6490_defconfig1
-rw-r--r--configs/qcom_defconfig5
-rw-r--r--doc/usage/cmd/reset.rst2
-rw-r--r--drivers/clk/qcom/Kconfig8
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clock-milos.c196
-rw-r--r--drivers/clk/qcom/clock-sc7280.c3
-rw-r--r--drivers/firmware/psci.c4
-rw-r--r--drivers/gpio/qcom_spmi_gpio.c1
-rw-r--r--drivers/phy/qcom/Kconfig8
-rw-r--r--drivers/phy/qcom/Makefile1
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-combo.c643
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-common.h62
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h18
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h34
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-ufs.c88
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp.h17
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-milos.c103
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc7280.c522
-rw-r--r--drivers/power/domain/Kconfig8
-rw-r--r--drivers/power/domain/Makefile1
-rw-r--r--drivers/power/domain/power-domain-uclass.c7
-rw-r--r--drivers/power/domain/qcom-rpmhpd.c278
-rw-r--r--drivers/power/regulator/qcom-rpmh-regulator.c33
-rw-r--r--drivers/sysreset/Kconfig15
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset-uclass.c37
-rw-r--r--drivers/sysreset/sysreset_qcom-psci.c45
-rw-r--r--drivers/tee/optee/core.c5
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--include/sysreset.h18
-rw-r--r--include/tee/optee.h9
-rw-r--r--lib/efi_loader/Kconfig3
44 files changed, 2349 insertions, 49 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 1ad65bf2f4c..0dcc7243124 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -685,6 +685,7 @@ F: drivers/*/*/pm8???-*
F: drivers/gpio/msm_gpio.c
F: drivers/mmc/msm_sdhci.c
F: drivers/phy/msm8916-usbh-phy.c
+F: drivers/phy/qcom/
F: drivers/serial/serial_msm.c
F: drivers/serial/serial_msm_geni.c
F: drivers/smem/msm_smem.c
diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c
index 87de09979b1..f834d770dd6 100644
--- a/arch/arm/cpu/armv8/fwcall.c
+++ b/arch/arm/cpu/armv8/fwcall.c
@@ -129,3 +129,18 @@ void __noreturn psci_system_off(void)
while (1)
;
}
+
+int psci_features(u32 psci_func_id)
+{
+ struct pt_regs regs;
+
+ regs.regs[0] = ARM_PSCI_1_0_FN_PSCI_FEATURES;
+ regs.regs[1] = psci_func_id;
+
+ if (use_smc_for_psci)
+ smc_call(&regs);
+ else
+ hvc_call(&regs);
+
+ return regs.regs[0];
+}
diff --git a/arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi b/arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi
index 8d4871135fa..c3ec4a317f7 100644
--- a/arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi
+++ b/arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi
@@ -17,10 +17,6 @@
};
};
-&usb_1 {
- dr_mode = "host";
-};
-
// RAM Entry 0 : Base 0x0080000000 Size 0x003A800000
// RAM Entry 1 : Base 0x00C0000000 Size 0x0001800000
// RAM Entry 2 : Base 0x00C3400000 Size 0x003CC00000
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 9e3ad57073d..5ed6833c155 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -342,6 +342,7 @@ void smc_call(struct pt_regs *args);
void __noreturn psci_system_reset(void);
void __noreturn psci_system_reset2(u32 reset_level, u32 cookie);
void __noreturn psci_system_off(void);
+int psci_features(u32 psci_func_id);
#ifdef CONFIG_ARMV8_PSCI
extern char __secure_start[];
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 5fb3240acc5..829a0109ac7 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -555,6 +555,11 @@ int board_late_init(void)
fdt_status |= !lmb_alloc(SZ_2M, &addr) ?
env_set_hex("fdt_addr_r", addr) : 1;
+ if (IS_ENABLED(CONFIG_OF_LIBFDT_OVERLAY)) {
+ status |= !lmb_alloc(SZ_1M, &addr) ?
+ env_set_hex("fdtoverlay_addr_r", addr) : 1;
+ }
+
if (status || fdt_status)
log_warning("%s: Failed to set run time variables\n", __func__);
diff --git a/arch/arm/mach-snapdragon/of_fixup.c b/arch/arm/mach-snapdragon/of_fixup.c
index 5b6076ea8e5..374e6262db4 100644
--- a/arch/arm/mach-snapdragon/of_fixup.c
+++ b/arch/arm/mach-snapdragon/of_fixup.c
@@ -4,7 +4,7 @@
*
* This file implements runtime fixups for Qualcomm DT to improve
* compatibility with U-Boot. This includes adjusting the USB nodes
- * to only use USB high-speed.
+ * to only use USB high-speed if SSPHY driver is not available.
*
* We use OF_LIVE for this rather than early FDT fixup for a couple
* of reasons: it has a much nicer API, is most likely more efficient,
@@ -21,26 +21,108 @@
#include <dt-bindings/input/linux-event-codes.h>
#include <dm/of_access.h>
#include <dm/of.h>
+#include <dm/device.h>
+#include <dm/lists.h>
#include <event.h>
#include <fdt_support.h>
#include <linux/errno.h>
+#include <linker_lists.h>
#include <stdlib.h>
+#include <tee/optee.h>
#include <time.h>
-/* U-Boot only supports USB high-speed mode on Qualcomm platforms with DWC3
- * USB controllers. Rather than requiring source level DT changes, we fix up
- * DT here. This improves compatibility with upstream DT and simplifies the
- * porting process for new devices.
+/**
+ * find_ssphy_node() - Find the super-speed PHY node referenced by DWC3
+ * @dwc3: DWC3 device node
+ *
+ * Returns: Pointer to SS-PHY node if found, NULL otherwise
*/
+static struct device_node *find_ssphy_node(struct device_node *dwc3)
+{
+ const __be32 *phandles;
+ const char *phy_name;
+ int len, i, ret;
+
+ phandles = of_get_property(dwc3, "phys", &len);
+ if (!phandles)
+ return NULL;
+
+ len /= sizeof(*phandles);
+
+ /* Iterate through PHY phandles to find the SS-PHY */
+ for (i = 0; i < len; i++) {
+ ret = of_property_read_string_index(dwc3, "phy-names", i, &phy_name);
+ if (ret)
+ continue;
+
+ /* Check if this is the super-speed PHY */
+ if (!strncmp("usb3-phy", phy_name, strlen("usb3-phy")) ||
+ !strncmp("usb3_phy", phy_name, strlen("usb3_phy"))) {
+ return of_find_node_by_phandle(NULL, be32_to_cpu(phandles[i]));
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * has_driver_for_node() - Check if any PHY driver can bind to this node
+ * @np: Device node to check
+ *
+ * Returns: true if a PHY driver with matching compatible string exists, false otherwise
+ */
+static bool has_driver_for_node(struct device_node *np)
+{
+ struct driver *driver = ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ const char *compat_list, *compat;
+ int compat_length, i;
+ struct driver *entry;
+
+ if (!np)
+ return false;
+
+ /* Get compatible strings from the node */
+ compat_list = of_get_property(np, "compatible", &compat_length);
+ if (!compat_list)
+ return false;
+
+ /* Check each compatible string against PHY drivers only */
+ for (i = 0; i < compat_length; i += strlen(compat) + 1) {
+ compat = compat_list + i;
+
+ /* Iterate through all registered drivers */
+ for (entry = driver; entry != driver + n_ents; entry++) {
+ const struct udevice_id *of_match = entry->of_match;
+
+ /* Skip non-PHY drivers to improve performance */
+ if (entry->id != UCLASS_PHY)
+ continue;
+
+ if (!of_match)
+ continue;
+
+ while (of_match->compatible) {
+ if (!strcmp(of_match->compatible, compat)) {
+ debug("Found PHY driver '%s' for SS-PHY compatible '%s'\n",
+ entry->name, compat);
+ return true;
+ }
+ of_match++;
+ }
+ }
+ }
+
+ return false;
+}
+
static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np, bool flat)
{
- struct device_node *dwc3;
+ struct device_node *dwc3, *ssphy_np;
int ret, len, hsphy_idx = 1;
const __be32 *phandles;
const char *second_phy_name;
- debug("Fixing up %s\n", glue_np->name);
-
/* New DT flattens the glue and controller into a single node. */
if (flat) {
dwc3 = glue_np;
@@ -54,30 +136,43 @@ static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np
}
}
- /* Tell the glue driver to configure the wrapper for high-speed only operation */
- ret = of_write_prop(glue_np, "qcom,select-utmi-as-pipe-clk", 0, NULL);
- if (ret) {
- log_err("Failed to add property 'qcom,select-utmi-as-pipe-clk': %d\n", ret);
- return ret;
- }
+ debug("Checking USB configuration for %s\n", dwc3->name);
phandles = of_get_property(dwc3, "phys", &len);
len /= sizeof(*phandles);
if (len == 1) {
- log_debug("Only one phy, not a superspeed controller\n");
+ debug("Only one phy, not a superspeed controller\n");
return 0;
}
- /* Figure out if the superspeed phy is present and if so then which phy is it? */
+ /* Figure out if the superspeed phy is present */
ret = of_property_read_string_index(dwc3, "phy-names", 1, &second_phy_name);
if (ret == -ENODATA) {
- log_debug("Only one phy, not a super-speed controller\n");
+ debug("Only one phy, not a super-speed controller\n");
return 0;
} else if (ret) {
log_err("Failed to read second phy name: %d\n", ret);
return ret;
}
+ /* Find the super-speed PHY node and check if a driver is available */
+ ssphy_np = find_ssphy_node(dwc3);
+ if (ssphy_np && has_driver_for_node(ssphy_np)) {
+ debug("Skipping USB fixup for %s (SS-PHY driver available)\n",
+ dwc3->name);
+ return 0;
+ }
+
+ /* No driver available - apply the fixup */
+ debug("Applying USB high-speed fixup to %s\n", dwc3->name);
+
+ /* Tell the glue driver to configure the wrapper for high-speed only operation */
+ ret = of_write_prop(dwc3, "qcom,select-utmi-as-pipe-clk", 0, NULL);
+ if (ret) {
+ log_err("Failed to add property 'qcom,select-utmi-as-pipe-clk': %d\n", ret);
+ return ret;
+ }
+
/*
* Determine which phy is the superspeed phy by checking the name of the second phy
* since it is typically the superspeed one.
@@ -134,33 +229,34 @@ static void fixup_usb_nodes(struct device_node *root)
}
}
-/* Remove all references to the rpmhpd device */
-static void fixup_power_domains(struct device_node *root)
+static void add_optee_node(struct device_node *root)
{
- struct device_node *pd = NULL, *np = NULL;
- struct property *prop;
- const __be32 *val;
+ struct device_node *fw = NULL, *optee = NULL;
+ int ret;
- /* All Qualcomm platforms name the rpm(h)pd "power-controller" */
- for_each_of_allnodes_from(root, pd) {
- if (pd->name && !strcmp("power-controller", pd->name))
- break;
+ fw = of_find_node_by_path("/firmware");
+ if (!fw) {
+ log_err("Failed to find /firmware node\n");
+ return;
}
- /* Sanity check that this is indeed a power domain controller */
- if (!of_find_property(pd, "#power-domain-cells", NULL)) {
- log_err("Found power-controller but it doesn't have #power-domain-cells\n");
+ ret = of_add_subnode(fw, "optee", strlen("optee") + 1, &optee);
+ if (ret) {
+ log_err("Failed to add 'optee' subnode: %d\n", ret);
return;
}
- /* Remove all references to the power domain controller */
- for_each_of_allnodes_from(root, np) {
- if (!(prop = of_find_property(np, "power-domains", NULL)))
- continue;
+ ret = of_write_prop(optee, "compatible", strlen("linaro,optee-tz") + 1,
+ "linaro,optee-tz");
+ if (ret) {
+ log_err("Failed to add optee 'compatible' property: %d\n", ret);
+ return;
+ }
- val = prop->value;
- if (val[0] == cpu_to_fdt32(pd->phandle))
- of_remove_property(np, prop);
+ ret = of_write_prop(optee, "method", strlen("smc") + 1, "smc");
+ if (ret) {
+ log_err("Failed to add optee 'method' property: %d\n", ret);
+ return;
}
}
@@ -176,7 +272,9 @@ static int qcom_of_fixup_nodes(void * __maybe_unused ctx, struct event *event)
struct device_node *root = event->data.of_live_built.root;
time_call(fixup_usb_nodes, root);
- time_call(fixup_power_domains, root);
+
+ if (IS_ENABLED(CONFIG_OPTEE) && is_optee_smc_api())
+ time_call(add_optee_node, root);
return 0;
}
diff --git a/board/qualcomm/debug-milos.config b/board/qualcomm/debug-milos.config
new file mode 100644
index 00000000000..a4cdd13f226
--- /dev/null
+++ b/board/qualcomm/debug-milos.config
@@ -0,0 +1,5 @@
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_ANNOUNCE=y
+CONFIG_DEBUG_UART_BASE=0xa94000
+CONFIG_DEBUG_UART_MSM_GENI=y
+CONFIG_DEBUG_UART_CLOCK=14745600
diff --git a/board/qualcomm/tfa-optee.config b/board/qualcomm/tfa-optee.config
new file mode 100644
index 00000000000..1e8364c114f
--- /dev/null
+++ b/board/qualcomm/tfa-optee.config
@@ -0,0 +1,4 @@
+# Enables support for TF-A based OP-TEE as the open
+# source TrustZone stack on Qcom platforms
+CONFIG_TEE=y
+CONFIG_OPTEE=y
diff --git a/cmd/boot.c b/cmd/boot.c
index 23496cafdf5..d80f9d8c05d 100644
--- a/cmd/boot.c
+++ b/cmd/boot.c
@@ -60,6 +60,9 @@ U_BOOT_CMD(
reset, 2, 0, do_reset,
"Perform RESET of the CPU",
"- cold boot without level specifier\n"
+#ifdef CONFIG_SYSRESET_QCOM_PSCI
+ "reset -edl - Boot to Emergency DownLoad mode\n"
+#endif
"reset -w - warm reset if implemented"
);
diff --git a/configs/qcm6490_defconfig b/configs/qcm6490_defconfig
index 618098c8860..b088367f86c 100644
--- a/configs/qcm6490_defconfig
+++ b/configs/qcm6490_defconfig
@@ -15,3 +15,4 @@ CONFIG_REMAKE_ELF=y
CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs6490-rb3gen2"
CONFIG_FASTBOOT_BUF_ADDR=0xd8800000
+CONFIG_PHY_QCOM_QMP_COMBO=y
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
index baad5f09455..3c8982dafd9 100644
--- a/configs/qcom_defconfig
+++ b/configs/qcom_defconfig
@@ -6,6 +6,7 @@ CONFIG_ARCH_SNAPDRAGON=y
CONFIG_NR_DRAM_BANKS=24
CONFIG_DEFAULT_DEVICE_TREE="qcom/sdm845-db845c"
CONFIG_SYS_LOAD_ADDR=0xA0000000
+# CONFIG_EFI_HAVE_RUNTIME_RESET is not set
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
@@ -56,6 +57,7 @@ CONFIG_CLK=y
CONFIG_CLK_STUB=y
CONFIG_CLK_QCOM_APQ8016=y
CONFIG_CLK_QCOM_APQ8096=y
+CONFIG_CLK_QCOM_MILOS=y
CONFIG_CLK_QCOM_QCM2290=y
CONFIG_CLK_QCOM_QCS404=y
CONFIG_CLK_QCOM_QCS615=y
@@ -126,11 +128,14 @@ CONFIG_MSM_SERIAL=y
CONFIG_MSM_GENI_SERIAL=y
CONFIG_SOC_QCOM=y
CONFIG_QCOM_COMMAND_DB=y
+CONFIG_QCOM_RPMH_POWER_DOMAIN=y
CONFIG_QCOM_RPMH=y
CONFIG_SPMI_MSM=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SMBIOS=y
+CONFIG_SYSRESET_CMD_RESET_ARGS=y
CONFIG_SYSRESET_QCOM_PSHOLD=y
+CONFIG_SYSRESET_QCOM_PSCI=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
diff --git a/doc/usage/cmd/reset.rst b/doc/usage/cmd/reset.rst
index 126db21cdb8..366b17eea16 100644
--- a/doc/usage/cmd/reset.rst
+++ b/doc/usage/cmd/reset.rst
@@ -22,6 +22,8 @@ DDR and peripherals, on some boards also resets external PMIC.
-w
Do warm WARM, reset CPU but keep peripheral/DDR/PMIC active.
+-edl
+ Boot to Emergency DownLoad mode on supported Qualcomm platforms.
Return value
------------
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 8504ed5d656..0a2ce55aaa2 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -47,6 +47,14 @@ config CLK_QCOM_IPQ9574
on the Snapdragon IPQ9574 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
+config CLK_QCOM_MILOS
+ bool "Qualcomm Milos GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon Milos SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
config CLK_QCOM_QCM2290
bool "Qualcomm QCM2290 GCC"
select CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 82a5b166196..b96d61b603e 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o
obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o
obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o
obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o
+obj-$(CONFIG_CLK_QCOM_MILOS) += clock-milos.o
obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o
obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o
obj-$(CONFIG_CLK_QCOM_QCS8300) += clock-qcs8300.o
diff --git a/drivers/clk/qcom/clock-milos.c b/drivers/clk/qcom/clock-milos.c
new file mode 100644
index 00000000000..afe59108559
--- /dev/null
+++ b/drivers/clk/qcom/clock-milos.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm Milos
+ *
+ * (C) Copyright 2024 Linaro Ltd.
+ * (C) Copyright 2026 Luca Weiss <[email protected]>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,milos-gcc.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+
+#include "clock-qcom.h"
+
+/* On-board TCXO, TOFIX get from DT */
+#define TCXO_RATE 76800000
+
+/* bi_tcxo_div4 divided after RPMh output */
+#define TCXO_DIV4_RATE (TCXO_RATE / 4)
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s3_clk_src[] = {
+ F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625),
+ F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625),
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625),
+ F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75),
+ F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25),
+ F(51200000, CFG_CLK_SRC_GPLL0_EVEN, 1, 64, 375),
+ F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75),
+ F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0),
+ F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15),
+ F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25),
+ F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, CFG_CLK_SRC_CXO, 12, 1, 4),
+ F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0),
+ F(37500000, CFG_CLK_SRC_GPLL0_EVEN, 8, 0, 0),
+ F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0),
+ F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0),
+ /* TOFIX F(202000000, CFG_CLK_SRC_GPLL9, 4, 0, 0), */
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0),
+ F(133333333, CFG_CLK_SRC_GPLL0, 4.5, 0, 0),
+ F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0),
+ F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static ulong milos_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_WRAP0_S5_CLK: /* UART5 */
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s3_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, 0x18500,
+ freq->pre_div, freq->m, freq->n, freq->src, 16);
+ return freq->freq;
+ case GCC_SDCC2_APPS_CLK:
+ freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, 0x14018,
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, 0x3902c,
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ case GCC_USB30_PRIM_MOCK_UTMI_CLK:
+ clk_rcg_set_rate(priv->base, 0x39044, 0, 0);
+ return TCXO_DIV4_RATE;
+ default:
+ return 0;
+ }
+}
+
+static const struct gate_clk milos_clks[] = {
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x39090, BIT(0)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(27)),
+ GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x52008, BIT(20)),
+ GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x52008, BIT(21)),
+ GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14010, BIT(0)),
+ GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x39018, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x39028, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x39024, BIT(0)),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x3908c, BIT(0)),
+};
+
+static int milos_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case GCC_AGGRE_USB3_PRIM_AXI_CLK:
+ qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK);
+ break;
+ }
+
+ return qcom_gate_clk_en(priv, clk->id);
+}
+
+static const struct qcom_reset_map milos_gcc_resets[] = {
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+ [GCC_SDCC1_BCR] = { 0xa3000 },
+ [GCC_SDCC2_BCR] = { 0x14000 },
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB30_PRIM_BCR] = { 0x39000 },
+};
+
+static const struct qcom_power_map milos_gdscs[] = {
+ [UFS_PHY_GDSC] = { 0x77004 },
+ [UFS_MEM_PHY_GDSC] = { 0x9e000 },
+ [USB30_PRIM_GDSC] = { 0x39004 },
+};
+
+static struct msm_clk_data milos_gcc_data = {
+ .resets = milos_gcc_resets,
+ .num_resets = ARRAY_SIZE(milos_gcc_resets),
+ .clks = milos_clks,
+ .num_clks = ARRAY_SIZE(milos_clks),
+ .power_domains = milos_gdscs,
+ .num_power_domains = ARRAY_SIZE(milos_gdscs),
+
+ .enable = milos_enable,
+ .set_rate = milos_set_rate,
+};
+
+static const struct udevice_id gcc_milos_of_match[] = {
+ {
+ .compatible = "qcom,milos-gcc",
+ .data = (ulong)&milos_gcc_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_milos) = {
+ .name = "gcc_milos",
+ .id = UCLASS_NOP,
+ .of_match = gcc_milos_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
+
+static ulong milos_rpmh_clk_set_rate(struct clk *clk, ulong rate)
+{
+ return (clk->rate = rate);
+}
+
+static ulong milos_rpmh_clk_get_rate(struct clk *clk)
+{
+ switch (clk->id) {
+ case RPMH_CXO_CLK:
+ return TCXO_DIV4_RATE;
+ default:
+ return clk->rate;
+ }
+}
+
+static int milos_rpmh_clk_nop(struct clk *clk)
+{
+ return 0;
+}
+
+static struct clk_ops milos_rpmh_clk_ops = {
+ .set_rate = milos_rpmh_clk_set_rate,
+ .get_rate = milos_rpmh_clk_get_rate,
+ .enable = milos_rpmh_clk_nop,
+ .disable = milos_rpmh_clk_nop,
+};
+
+static const struct udevice_id milos_rpmh_clk_ids[] = {
+ { .compatible = "qcom,milos-rpmh-clk" },
+ { }
+};
+
+U_BOOT_DRIVER(milos_rpmh_clk) = {
+ .name = "milos_rpmh_clk",
+ .id = UCLASS_CLK,
+ .of_match = milos_rpmh_clk_ids,
+ .ops = &milos_rpmh_clk_ops,
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index 7b6ed826023..01c8587ac39 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -116,6 +116,7 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf01c, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf054, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf058, 1),
+ GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0xf05c, 1),
GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x9e07c, 1),
GATE_CLK(GCC_USB30_SEC_MASTER_CLK, 0x9e010, 1),
GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x9e080, 1),
@@ -155,6 +156,8 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_UFS_1_CLKREF_EN, 0x8c000, BIT(0)),
GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)),
GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)),
+ GATE_CLK(GCC_SDCC1_AHB_CLK, 0x75004, BIT(0)),
+ GATE_CLK(GCC_SDCC1_APPS_CLK, 0x75008, BIT(0)),
};
static int sc7280_enable(struct clk *clk)
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 2e3223e1c32..b6838a244d2 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -186,6 +186,10 @@ static int psci_bind(struct udevice *dev)
NULL);
if (ret)
pr_debug("PSCI System Reset was not bound.\n");
+ if (IS_ENABLED(CONFIG_SYSRESET_QCOM_PSCI) &&
+ device_bind_driver(dev, "qcom_psci-sysreset",
+ "qcom_psci-sysreset", NULL))
+ pr_debug("QCOM PSCI System Reset was not bound.\n");
}
/* From PSCI v1.0 onward we can discover services through ARM_SMCCC_FEATURE */
diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c
index 1a7c7c48dfc..77a69140213 100644
--- a/drivers/gpio/qcom_spmi_gpio.c
+++ b/drivers/gpio/qcom_spmi_gpio.c
@@ -747,6 +747,7 @@ static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = {
{ .compatible = "qcom,pm6350-gpio" },
{ .compatible = "qcom,pm660l-gpio" },
{ .compatible = "qcom,pm7325-gpio" },
+ { .compatible = "qcom,pm7550-gpio" },
{ .compatible = "qcom,pm8550-gpio" },
{ .compatible = "qcom,pm8550b-gpio" },
{ .compatible = "qcom,pm8550ve-gpio" },
diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig
index 0dd69f7ffd0..49f830abf01 100644
--- a/drivers/phy/qcom/Kconfig
+++ b/drivers/phy/qcom/Kconfig
@@ -12,6 +12,14 @@ config PHY_QCOM_IPQ4019_USB
help
Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s.
+config PHY_QCOM_QMP_COMBO
+ bool "Qualcomm QMP USB3-DP Combo PHY driver"
+ depends on PHY && ARCH_SNAPDRAGON
+ help
+ Enable this to support the USB3-DP Combo QMP PHY on various Qualcomm
+ chipsets. This driver supports the USB3 PHY functionality of the combo
+ PHY (USB3 + DisplayPort). Currently only USB3 mode is supported.
+
config PHY_QCOM_QMP_PCIE
tristate "Qualcomm QMP PCIe PHY driver"
depends on PHY && ARCH_SNAPDRAGON
diff --git a/drivers/phy/qcom/Makefile b/drivers/phy/qcom/Makefile
index 1c4e7d8d391..714013dc572 100644
--- a/drivers/phy/qcom/Makefile
+++ b/drivers/phy/qcom/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
+obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o
obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o
obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
diff --git a/drivers/phy/qcom/phy-qcom-qmp-combo.c b/drivers/phy/qcom/phy-qcom-qmp-combo.c
new file mode 100644
index 00000000000..0d63e482ee4
--- /dev/null
+++ b/drivers/phy/qcom/phy-qcom-qmp-combo.c
@@ -0,0 +1,643 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <power/regulator.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/err.h>
+
+#include "phy-qcom-qmp-common.h"
+
+#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-pcs-usb-v4.h"
+#include "phy-qcom-qmp-dp-com-v3.h"
+
+/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */
+/* DP PHY soft reset */
+#define SW_DPPHY_RESET BIT(0)
+/* mux to select DP PHY reset control, 0:HW control, 1: software reset */
+#define SW_DPPHY_RESET_MUX BIT(1)
+/* USB3 PHY soft reset */
+#define SW_USB3PHY_RESET BIT(2)
+/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */
+#define SW_USB3PHY_RESET_MUX BIT(3)
+
+/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */
+#define USB3_MODE BIT(0) /* enables USB3 mode */
+#define DP_MODE BIT(1) /* enables DP mode */
+
+/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
+#define SW_PORTSELECT_MUX BIT(1)
+
+/* PHY slot identifiers for device tree phandle arguments */
+#define QMP_USB43DP_USB3_PHY 0
+#define QMP_USB43DP_DP_PHY 1
+
+#define PHY_INIT_COMPLETE_TIMEOUT 10000
+
+struct qmp_combo_offsets {
+ u16 com;
+ u16 txa;
+ u16 rxa;
+ u16 txb;
+ u16 rxb;
+ u16 usb3_serdes;
+ u16 usb3_pcs_misc;
+ u16 usb3_pcs;
+ u16 usb3_pcs_usb;
+};
+
+/*
+ * Initialisation tables
+ */
+
+static const struct qmp_combo_offsets qmp_combo_offsets_v3 = {
+ .com = 0x0000,
+ .txa = 0x1200,
+ .rxa = 0x1400,
+ .txb = 0x1600,
+ .rxb = 0x1800,
+ .usb3_serdes = 0x1000,
+ .usb3_pcs_misc = 0x1a00,
+ .usb3_pcs = 0x1c00,
+ .usb3_pcs_usb = 0x1f00,
+};
+
+static const struct qmp_phy_init_tbl sm8150_usb3_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0xde),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_IPTRIM, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0xea),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xea),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xca),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11),
+};
+
+static const struct qmp_phy_init_tbl sm8250_usb3_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5),
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x40, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x54, 2),
+};
+
+static const struct qmp_phy_init_tbl sm8250_usb3_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0xff, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0x7f, 2),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x7f, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff, 2),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x97),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x7b),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb4),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10),
+};
+
+static const struct qmp_phy_init_tbl sm8250_usb3_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xa9),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10),
+};
+
+static const struct qmp_phy_init_tbl sm8250_usb3_pcs_usb_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
+};
+
+struct qmp_phy_cfg {
+ const struct qmp_combo_offsets *offsets;
+ const struct qmp_phy_init_tbl *serdes_tbl;
+ int serdes_tbl_num;
+ const struct qmp_phy_init_tbl *tx_tbl;
+ int tx_tbl_num;
+ const struct qmp_phy_init_tbl *rx_tbl;
+ int rx_tbl_num;
+ const struct qmp_phy_init_tbl *pcs_tbl;
+ int pcs_tbl_num;
+ const struct qmp_phy_init_tbl *pcs_usb_tbl;
+ int pcs_usb_tbl_num;
+ const char * const *vreg_list;
+ int num_vregs;
+ /* true, if PHY needs delay after POWER_DOWN */
+ bool has_pwrdn_delay;
+};
+
+/* list of clocks required by phy */
+static const char * const qmp_combo_phy_clk_l[] = {
+ "aux", "com_aux",
+};
+
+/* list of regulators */
+static const char * const qmp_phy_vreg_l[] = {
+ "vdda-phy-supply",
+ "vdda-pll-supply",
+};
+
+struct qmp_combo {
+ struct udevice *dev;
+ void __iomem *com;
+ void __iomem *serdes;
+ void __iomem *tx;
+ void __iomem *rx;
+ void __iomem *tx2;
+ void __iomem *rx2;
+ void __iomem *pcs;
+ void __iomem *pcs_usb;
+ void __iomem *pcs_misc;
+ struct clk *clks;
+ struct clk *pipe_clk;
+ int num_clks;
+ struct reset_ctl_bulk resets;
+ int num_resets;
+ struct udevice **vregs;
+ int num_vregs;
+ const struct qmp_phy_cfg *cfg;
+};
+
+static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
+{
+ u32 reg;
+
+ reg = readl(base + offset);
+ reg |= val;
+ writel(reg, base + offset);
+
+ /* ensure that above write is through */
+ readl(base + offset);
+}
+
+static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val)
+{
+ u32 reg;
+
+ reg = readl(base + offset);
+ reg &= ~val;
+ writel(reg, base + offset);
+
+ /* ensure that above write is through */
+ readl(base + offset);
+}
+
+static int qmp_combo_com_exit(struct qmp_combo *qmp)
+{
+ int i, ret;
+
+ for (i = 0; i < qmp->num_clks; i++)
+ clk_disable(&qmp->clks[i]);
+
+ reset_assert_bulk(&qmp->resets);
+
+ for (i = qmp->num_vregs - 1; i >= 0; i--) {
+ ret = regulator_set_enable(qmp->vregs[i], false);
+ if (ret)
+ dev_warn(qmp->dev, "failed to disable %s: %d\n",
+ qmp->cfg->vreg_list[i], ret);
+ }
+
+ return 0;
+}
+
+static int qmp_combo_com_init(struct qmp_combo *qmp)
+{
+ void __iomem *com = qmp->com;
+ void __iomem *pcs = qmp->pcs;
+ u32 val;
+ int ret, i;
+
+ ret = reset_assert_bulk(&qmp->resets);
+ if (ret) {
+ printf("Failed to assert resets: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert_bulk(&qmp->resets);
+ if (ret) {
+ printf("Failed to deassert resets: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < qmp->num_vregs; i++) {
+ ret = regulator_set_enable(qmp->vregs[i], true);
+ if (ret) {
+ dev_err(qmp->dev, "Failed to enable regulator %d: %d\n", i, ret);
+ while (--i >= 0)
+ regulator_set_enable(qmp->vregs[i], false);
+ reset_assert_bulk(&qmp->resets);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < qmp->num_clks; i++) {
+ ret = clk_enable(&qmp->clks[i]);
+ if (ret) {
+ printf("Failed to enable clock %d: %d\n", i, ret);
+ while (--i >= 0)
+ clk_disable(&qmp->clks[i]);
+ for (i = qmp->num_vregs - 1; i >= 0; i--)
+ regulator_set_enable(qmp->vregs[i], false);
+ reset_assert_bulk(&qmp->resets);
+ return ret;
+ }
+ }
+
+ /* Common block register writes */
+ qphy_setbits(com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN);
+ qphy_setbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
+ SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
+ SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
+
+ val = SW_PORTSELECT_MUX;
+ writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL);
+
+ writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL);
+
+ qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
+ SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
+ SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
+
+ qphy_clrbits(com, QPHY_V3_DP_COM_SWI_CTRL, 0x03);
+
+ qphy_clrbits(com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
+
+ qphy_setbits(pcs, QPHY_V4_PCS_POWER_DOWN_CONTROL, SW_PWRDN);
+
+ return 0;
+}
+
+static int qmp_combo_usb_power_on(struct qmp_combo *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ void __iomem *serdes = qmp->serdes;
+ void __iomem *tx = qmp->tx;
+ void __iomem *rx = qmp->rx;
+ void __iomem *tx2 = qmp->tx2;
+ void __iomem *rx2 = qmp->rx2;
+ void __iomem *pcs = qmp->pcs;
+ void __iomem *pcs_usb = qmp->pcs_usb;
+ u32 val;
+ int ret;
+
+ /* Serdes configuration */
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl, cfg->serdes_tbl_num);
+
+ ret = clk_prepare_enable(qmp->pipe_clk);
+ if (ret) {
+ dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
+ return ret;
+ }
+
+ /* Tx, Rx configurations */
+ qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+ qmp_configure_lane(qmp->dev, tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
+
+ qmp_configure_lane(qmp->dev, rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
+ qmp_configure_lane(qmp->dev, rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
+
+ /* PCS configuration */
+ qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+
+ if (pcs_usb) {
+ qmp_configure(qmp->dev, pcs_usb,
+ cfg->pcs_usb_tbl,
+ cfg->pcs_usb_tbl_num);
+ }
+
+ if (cfg->has_pwrdn_delay)
+ udelay(20);
+
+ /* Pull PHY out of reset */
+ qphy_clrbits(pcs, QPHY_V4_PCS_SW_RESET, SW_RESET);
+
+ /* Start SerDes and Phy-Coding-Sublayer */
+ qphy_setbits(pcs, QPHY_V4_PCS_START_CONTROL,
+ SERDES_START | PCS_START);
+
+ /* Wait for PHY initialization */
+ ret = readl_poll_timeout(pcs + QPHY_V4_PCS_PCS_STATUS1, val,
+ !(val & PHYSTATUS), PHY_INIT_COMPLETE_TIMEOUT);
+
+ if (ret) {
+ printf("QMP USB3 PHY initialization timeout\n");
+ clk_disable(qmp->pipe_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qmp_combo_power_on(struct phy *phy)
+{
+ struct qmp_combo *qmp = dev_get_priv(phy->dev);
+ int ret;
+
+ /* Initialize common block */
+ ret = qmp_combo_com_init(qmp);
+ if (ret)
+ return ret;
+
+ /* Initialize USB3-specific configuration */
+ ret = qmp_combo_usb_power_on(qmp);
+ if (ret) {
+ qmp_combo_com_exit(qmp);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qmp_combo_power_off(struct phy *phy)
+{
+ struct qmp_combo *qmp = dev_get_priv(phy->dev);
+ void __iomem *com = qmp->com;
+
+ clk_disable(qmp->pipe_clk);
+
+ /* PHY reset */
+ qphy_setbits(qmp->pcs, QPHY_V4_PCS_SW_RESET, SW_RESET);
+
+ /* Stop SerDes and Phy-Coding-Sublayer */
+ qphy_clrbits(qmp->pcs, QPHY_V4_PCS_START_CONTROL,
+ SERDES_START | PCS_START);
+
+ /* Put PHY into POWER DOWN state: active low */
+ qphy_clrbits(qmp->pcs, QPHY_V4_PCS_POWER_DOWN_CONTROL, SW_PWRDN);
+
+ /* Power down common block */
+ qphy_clrbits(com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN);
+
+ return qmp_combo_com_exit(qmp);
+}
+
+static int qmp_combo_reset_init(struct qmp_combo *qmp)
+{
+ struct udevice *dev = qmp->dev;
+ int ret;
+
+ ret = reset_get_bulk(dev, &qmp->resets);
+ if (ret) {
+ printf("Failed to get resets: %d\n", ret);
+ return ret;
+ }
+
+ qmp->num_resets = qmp->resets.count;
+
+ return 0;
+}
+
+static int qmp_combo_clk_init(struct qmp_combo *qmp)
+{
+ struct udevice *dev = qmp->dev;
+ int num = ARRAY_SIZE(qmp_combo_phy_clk_l);
+ int i, ret;
+
+ qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);
+ if (!qmp->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++) {
+ ret = clk_get_by_name(dev, qmp_combo_phy_clk_l[i], &qmp->clks[i]);
+ if (ret) {
+ dev_err(dev, "failed to get %s clock: %d\n",
+ qmp_combo_phy_clk_l[i], ret);
+ return ret;
+ }
+ }
+
+ qmp->num_clks = num;
+ return 0;
+}
+
+static int qmp_combo_vreg_init(struct qmp_combo *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ struct udevice *dev = qmp->dev;
+ int num = cfg->num_vregs;
+ int i, ret;
+
+ if (!num)
+ return 0;
+
+ qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
+ if (!qmp->vregs)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++) {
+ ret = device_get_supply_regulator(dev, cfg->vreg_list[i],
+ &qmp->vregs[i]);
+ if (ret) {
+ dev_err(dev, "failed to get regulator %s: %d\n",
+ cfg->vreg_list[i], ret);
+ return ret;
+ }
+ }
+
+ qmp->num_vregs = num;
+ return 0;
+}
+
+static int qmp_combo_parse_dt(struct qmp_combo *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ const struct qmp_combo_offsets *offs = cfg->offsets;
+ struct udevice *dev = qmp->dev;
+ void __iomem *base;
+ int ret;
+
+ if (!offs)
+ return -EINVAL;
+
+ base = (void __iomem *)dev_read_addr(dev);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ qmp->com = base + offs->com;
+ qmp->serdes = base + offs->usb3_serdes;
+ qmp->tx = base + offs->txa;
+ qmp->rx = base + offs->rxa;
+ qmp->tx2 = base + offs->txb;
+ qmp->rx2 = base + offs->rxb;
+ qmp->pcs = base + offs->usb3_pcs;
+ qmp->pcs_usb = base + offs->usb3_pcs_usb;
+ qmp->pcs_misc = base + offs->usb3_pcs_misc;
+
+ ret = qmp_combo_clk_init(qmp);
+ if (ret)
+ return ret;
+
+ qmp->pipe_clk = devm_clk_get(dev, "usb3_pipe");
+ if (IS_ERR(qmp->pipe_clk)) {
+ dev_err(dev, "failed to get pipe clock (%ld)\n",
+ PTR_ERR(qmp->pipe_clk));
+ return ret;
+ }
+
+ ret = qmp_combo_reset_init(qmp);
+ if (ret)
+ return ret;
+
+ ret = qmp_combo_vreg_init(qmp);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int qmp_combo_probe(struct udevice *dev)
+{
+ struct qmp_combo *qmp = dev_get_priv(dev);
+ int ret;
+
+ qmp->dev = dev;
+ qmp->cfg = (const struct qmp_phy_cfg *)dev_get_driver_data(dev);
+ if (!qmp->cfg) {
+ printf("Failed to get PHY configuration\n");
+ return -EINVAL;
+ }
+
+ ret = qmp_combo_parse_dt(qmp);
+
+ return ret;
+}
+
+static const struct qmp_phy_cfg sc7280_usb3dpphy_cfg = {
+ .offsets = &qmp_combo_offsets_v3,
+ .serdes_tbl = sm8150_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl),
+ .tx_tbl = sm8250_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sm8250_usb3_tx_tbl),
+ .rx_tbl = sm8250_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sm8250_usb3_rx_tbl),
+ .pcs_tbl = sm8250_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_tbl),
+ .pcs_usb_tbl = sm8250_usb3_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_usb_tbl),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+
+ .has_pwrdn_delay = true,
+};
+
+static int qmp_combo_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ if (args->args_count != 1) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ /* We only support the USB3 phy at slot 0 */
+ if (args->args[0] == QMP_USB43DP_DP_PHY)
+ return -EINVAL;
+
+ phy->id = QMP_USB43DP_USB3_PHY;
+
+ return 0;
+}
+
+static struct phy_ops qmp_combo_ops = {
+ .init = qmp_combo_power_on,
+ .exit = qmp_combo_power_off,
+ .of_xlate = qmp_combo_xlate,
+};
+
+static const struct udevice_id qmp_combo_ids[] = {
+ {
+ .compatible = "qcom,sc7280-qmp-usb3-dp-phy",
+ .data = (ulong)&sc7280_usb3dpphy_cfg,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(qmp_combo) = {
+ .name = "qcom-qmp-usb3-dp-phy",
+ .id = UCLASS_PHY,
+ .of_match = qmp_combo_ids,
+ .ops = &qmp_combo_ops,
+ .probe = qmp_combo_probe,
+ .priv_auto = sizeof(struct qmp_combo),
+};
diff --git a/drivers/phy/qcom/phy-qcom-qmp-common.h b/drivers/phy/qcom/phy-qcom-qmp-common.h
new file mode 100644
index 00000000000..71356fb7dd0
--- /dev/null
+++ b/drivers/phy/qcom/phy-qcom-qmp-common.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_COMMON_H_
+#define QCOM_PHY_QMP_COMMON_H_
+
+struct qmp_phy_init_tbl {
+ unsigned int offset;
+ unsigned int val;
+ char *name;
+ /*
+ * mask of lanes for which this register is written
+ * for cases when second lane needs different values
+ */
+ u8 lane_mask;
+};
+
+#define QMP_PHY_INIT_CFG(o, v) \
+ { \
+ .offset = o, \
+ .val = v, \
+ .name = #o, \
+ .lane_mask = 0xff, \
+ }
+
+#define QMP_PHY_INIT_CFG_LANE(o, v, l) \
+ { \
+ .offset = o, \
+ .val = v, \
+ .name = #o, \
+ .lane_mask = l, \
+ }
+
+static inline void qmp_configure_lane(struct udevice *dev, void __iomem *base,
+ const struct qmp_phy_init_tbl tbl[],
+ int num, u8 lane_mask)
+{
+ int i;
+ const struct qmp_phy_init_tbl *t = tbl;
+
+ if (!t)
+ return;
+
+ for (i = 0; i < num; i++, t++) {
+ if (!(t->lane_mask & lane_mask))
+ continue;
+
+ dev_dbg(dev, "Writing Reg: %s Offset: 0x%04x Val: 0x%02x\n",
+ t->name, t->offset, t->val);
+ writel(t->val, base + t->offset);
+ }
+}
+
+static inline void qmp_configure(struct udevice *dev, void __iomem *base,
+ const struct qmp_phy_init_tbl tbl[], int num)
+{
+ qmp_configure_lane(dev, base, tbl, num, 0xff);
+}
+
+#endif
diff --git a/drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h b/drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h
new file mode 100644
index 00000000000..396179ef38b
--- /dev/null
+++ b/drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_DP_COM_V3_H_
+#define QCOM_PHY_QMP_DP_COM_V3_H_
+
+/* Only for QMP V3 & V4 PHY - DP COM registers */
+#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00
+#define QPHY_V3_DP_COM_SW_RESET 0x04
+#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08
+#define QPHY_V3_DP_COM_SWI_CTRL 0x0c
+#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10
+#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14
+#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c
+
+#endif
diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h
new file mode 100644
index 00000000000..d7fd4ac0fc5
--- /dev/null
+++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_USB_V4_H_
+#define QCOM_PHY_QMP_PCS_USB_V4_H_
+
+/* Only for QMP V4 PHY - USB3 PCS registers */
+#define QPHY_V4_PCS_USB3_POWER_STATE_CONFIG1 0x000
+#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_STATUS 0x004
+#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL 0x008
+#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL2 0x00c
+#define QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x010
+#define QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR 0x014
+#define QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0x018
+#define QPHY_V4_PCS_USB3_LFPS_TX_ECSTART 0x01c
+#define QPHY_V4_PCS_USB3_LFPS_PER_TIMER_VAL 0x020
+#define QPHY_V4_PCS_USB3_LFPS_TX_END_CNT_U3_START 0x024
+#define QPHY_V4_PCS_USB3_RXEQTRAINING_LOCK_TIME 0x028
+#define QPHY_V4_PCS_USB3_RXEQTRAINING_WAIT_TIME 0x02c
+#define QPHY_V4_PCS_USB3_RXEQTRAINING_CTLE_TIME 0x030
+#define QPHY_V4_PCS_USB3_RXEQTRAINING_WAIT_TIME_S2 0x034
+#define QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x038
+#define QPHY_V4_PCS_USB3_RCVR_DTCT_DLY_U3_L 0x03c
+#define QPHY_V4_PCS_USB3_RCVR_DTCT_DLY_U3_H 0x040
+#define QPHY_V4_PCS_USB3_ARCVR_DTCT_EN_PERIOD 0x044
+#define QPHY_V4_PCS_USB3_ARCVR_DTCT_CM_DLY 0x048
+#define QPHY_V4_PCS_USB3_TXONESZEROS_RUN_LENGTH 0x04c
+#define QPHY_V4_PCS_USB3_ALFPS_DEGLITCH_VAL 0x050
+#define QPHY_V4_PCS_USB3_SIGDET_STARTUP_TIMER_VAL 0x054
+#define QPHY_V4_PCS_USB3_TEST_CONTROL 0x058
+
+#endif
diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c
index 907f34744eb..80eba734a63 100644
--- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c
@@ -119,6 +119,68 @@ static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
};
+static const struct qmp_ufs_init_tbl milos_ufsphy_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x98),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x32),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0f),
+};
+
+static const struct qmp_ufs_init_tbl milos_ufsphy_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0xcc),
+};
+
+static const struct qmp_ufs_init_tbl milos_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x3e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B3, 0x9e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CTRL1, 0x94),
+};
+
+static const struct qmp_ufs_init_tbl milos_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x0b),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
+};
+
static const struct qmp_ufs_init_tbl sdm845_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
@@ -982,6 +1044,31 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = {
.rx2 = 0x1a00,
};
+static const struct qmp_ufs_cfg milos_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets_v6,
+
+ .tbls = {
+ .serdes = milos_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(milos_ufsphy_serdes),
+ .tx = milos_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(milos_ufsphy_tx),
+ .rx = milos_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(milos_ufsphy_rx),
+ .pcs = milos_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(milos_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8550_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
+ },
+
+ .vreg_list = qmp_ufs_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l),
+ .regs = ufsphy_v6_regs_layout,
+};
+
static const struct qmp_ufs_cfg sdm845_ufsphy_cfg = {
.lanes = 2,
@@ -1651,6 +1738,7 @@ static struct phy_ops qmp_ufs_ops = {
};
static const struct udevice_id qmp_ufs_ids[] = {
+ { .compatible = "qcom,milos-qmp-ufs-phy", .data = (ulong)&milos_ufsphy_cfg, },
{ .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg, },
{ .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg },
{ .compatible = "qcom,sm6350-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg },
diff --git a/drivers/phy/qcom/phy-qcom-qmp.h b/drivers/phy/qcom/phy-qcom-qmp.h
index 99f4d447caf..06dac21ddc4 100644
--- a/drivers/phy/qcom/phy-qcom-qmp.h
+++ b/drivers/phy/qcom/phy-qcom-qmp.h
@@ -12,12 +12,17 @@
#include "phy-qcom-qmp-qserdes-com-v3.h"
#include "phy-qcom-qmp-qserdes-txrx-v3.h"
+#include "phy-qcom-qmp-qserdes-com-v4.h"
+#include "phy-qcom-qmp-qserdes-txrx-v4.h"
+
#include "phy-qcom-qmp-qserdes-pll.h"
#include "phy-qcom-qmp-pcs-v2.h"
#include "phy-qcom-qmp-pcs-v3.h"
+#include "phy-qcom-qmp-pcs-v4.h"
+
/* Only for QMP V3 & V4 PHY - DP COM registers */
#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00
#define QPHY_V3_DP_COM_SW_RESET 0x04
@@ -112,4 +117,16 @@
#define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0
#define QSERDES_V6_DP_PHY_STATUS 0x0e4
+/* QPHY_SW_RESET bit */
+#define SW_RESET BIT(0)
+/* QPHY_POWER_DOWN_CONTROL */
+#define SW_PWRDN BIT(0)
+
+/* QPHY_START_CONTROL bits */
+#define SERDES_START BIT(0)
+#define PCS_START BIT(1)
+
+/* QPHY_PCS_STATUS bit */
+#define PHYSTATUS BIT(6)
+
#endif
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 580308621b1..11e6763b5f3 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -54,6 +54,14 @@ config PINCTRL_QCOM_IPQ9574
Say Y here to enable support for pinctrl on the IPQ9574 SoC,
as well as the associated GPIO driver.
+config PINCTRL_QCOM_MILOS
+ bool "Qualcomm Milos Pinctrl"
+ default y if PINCTRL_QCOM_GENERIC
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon Milos SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_QCM2290
bool "Qualcomm QCM2290 Pinctrl"
default y if PINCTRL_QCOM_GENERIC
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index b5a111605ed..4096c1aa491 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o
obj-$(CONFIG_PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o
obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o
obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o
+obj-$(CONFIG_PINCTRL_QCOM_MILOS) += pinctrl-milos.o
obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o
obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o
obj-$(CONFIG_PINCTRL_QCOM_QCS615) += pinctrl-qcs615.o
diff --git a/drivers/pinctrl/qcom/pinctrl-milos.c b/drivers/pinctrl/qcom/pinctrl-milos.c
new file mode 100644
index 00000000000..4f958fbfbf3
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-milos.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm Milos pinctrl
+ *
+ * (C) Copyright 2024 Linaro Ltd.
+ * (C) Copyright 2026 Luca Weiss <[email protected]>
+ *
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ {"qup0_se5", 1},
+ {"sdc2_clk", 1},
+ {"sdc2_cmd", 1},
+ {"sdc2_data", 1},
+ {"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", 0xb4004, 0xb5000),
+ [1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xab000, 0, 6),
+ [2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xab000, 12, 3),
+ [3] = SDC_QDSD_PINGROUP("sdc2_data", 0xab000, 9, 0),
+};
+
+static const char *milos_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *milos_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector >= 167 && selector <= 170)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ msm_special_pins_data[selector - 167].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int milos_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static struct msm_pinctrl_data milos_data = {
+ .pin_data = {
+ .pin_count = 171,
+ .special_pins_start = 167,
+ .special_pins_data = msm_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = milos_get_function_name,
+ .get_function_mux = milos_get_function_mux,
+ .get_pin_name = milos_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,milos-tlmm", .data = (ulong)&milos_data },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_milos) = {
+ .name = "pinctrl_milos",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c
index d62b2cc6fb6..d0242fc1c17 100644
--- a/drivers/pinctrl/qcom/pinctrl-sc7280.c
+++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c
@@ -13,11 +13,22 @@
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
-static const struct pinctrl_function msm_pinctrl_functions[] = {
- { "qup05", 1 },
- { "gpio", 0 },
- { "pcie1_clkreqn", 3},
-};
+typedef unsigned int msm_pin_function[10];
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\
+ { \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }
+
#define SDC_PINGROUP(pg_name, ctl, pull, drv) \
{ \
.name = pg_name, \
@@ -42,6 +53,492 @@ static const struct pinctrl_function msm_pinctrl_functions[] = {
.out_bit = 0, \
}
+enum sc7280_functions {
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_usb0,
+ msm_mux_atest_usb00,
+ msm_mux_atest_usb01,
+ msm_mux_atest_usb02,
+ msm_mux_atest_usb03,
+ msm_mux_atest_usb1,
+ msm_mux_atest_usb10,
+ msm_mux_atest_usb11,
+ msm_mux_atest_usb12,
+ msm_mux_atest_usb13,
+ msm_mux_audio_ref,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cmu_rng0,
+ msm_mux_cmu_rng1,
+ msm_mux_cmu_rng2,
+ msm_mux_cmu_rng3,
+ msm_mux_coex_uart1,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_dp_hot,
+ msm_mux_dp_lcd,
+ msm_mux_edp_hot,
+ msm_mux_edp_lcd,
+ msm_mux_egpio,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gpio,
+ msm_mux_host2wlan_sol,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_lpass_slimbus,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync0,
+ msm_mux_mdp_vsync1,
+ msm_mux_mdp_vsync2,
+ msm_mux_mdp_vsync3,
+ msm_mux_mdp_vsync4,
+ msm_mux_mdp_vsync5,
+ msm_mux_mi2s0_data0,
+ msm_mux_mi2s0_data1,
+ msm_mux_mi2s0_sck,
+ msm_mux_mi2s0_ws,
+ msm_mux_mi2s1_data0,
+ msm_mux_mi2s1_data1,
+ msm_mux_mi2s1_sck,
+ msm_mux_mi2s1_ws,
+ msm_mux_mi2s2_data0,
+ msm_mux_mi2s2_data1,
+ msm_mux_mi2s2_sck,
+ msm_mux_mi2s2_ws,
+ msm_mux_mss_grfc0,
+ msm_mux_mss_grfc1,
+ msm_mux_mss_grfc10,
+ msm_mux_mss_grfc11,
+ msm_mux_mss_grfc12,
+ msm_mux_mss_grfc2,
+ msm_mux_mss_grfc3,
+ msm_mux_mss_grfc4,
+ msm_mux_mss_grfc5,
+ msm_mux_mss_grfc6,
+ msm_mux_mss_grfc7,
+ msm_mux_mss_grfc8,
+ msm_mux_mss_grfc9,
+ msm_mux_nav_gpio0,
+ msm_mux_nav_gpio1,
+ msm_mux_nav_gpio2,
+ msm_mux_pa_indicator,
+ msm_mux_pcie0_clkreqn,
+ msm_mux_pcie1_clkreqn,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_bypassnl,
+ msm_mux_pll_clk,
+ msm_mux_pll_reset,
+ msm_mux_pri_mi2s,
+ msm_mux_prng_rosc,
+ msm_mux_qdss,
+ msm_mux_qdss_cti,
+ msm_mux_qlink0_enable,
+ msm_mux_qlink0_request,
+ msm_mux_qlink0_wmss,
+ msm_mux_qlink1_enable,
+ msm_mux_qlink1_request,
+ msm_mux_qlink1_wmss,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qspi_data,
+ msm_mux_qup00,
+ msm_mux_qup01,
+ msm_mux_qup02,
+ msm_mux_qup03,
+ msm_mux_qup04,
+ msm_mux_qup05,
+ msm_mux_qup06,
+ msm_mux_qup07,
+ msm_mux_qup10,
+ msm_mux_qup11,
+ msm_mux_qup12,
+ msm_mux_qup13,
+ msm_mux_qup14,
+ msm_mux_qup15,
+ msm_mux_qup16,
+ msm_mux_qup17,
+ msm_mux_sd_write,
+ msm_mux_sdc40,
+ msm_mux_sdc41,
+ msm_mux_sdc42,
+ msm_mux_sdc43,
+ msm_mux_sdc4_clk,
+ msm_mux_sdc4_cmd,
+ msm_mux_sec_mi2s,
+ msm_mux_tb_trig,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_uim0_clk,
+ msm_mux_uim0_data,
+ msm_mux_uim0_present,
+ msm_mux_uim0_reset,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_usb2phy_ac,
+ msm_mux_usb_phy,
+ msm_mux_vfr_0,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger,
+ msm_mux__,
+};
+
+#define MSM_PIN_FUNCTION(fname) \
+ [msm_mux_##fname] = {#fname, msm_mux_##fname}
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_char0),
+ MSM_PIN_FUNCTION(atest_char1),
+ MSM_PIN_FUNCTION(atest_char2),
+ MSM_PIN_FUNCTION(atest_char3),
+ MSM_PIN_FUNCTION(atest_usb0),
+ MSM_PIN_FUNCTION(atest_usb00),
+ MSM_PIN_FUNCTION(atest_usb01),
+ MSM_PIN_FUNCTION(atest_usb02),
+ MSM_PIN_FUNCTION(atest_usb03),
+ MSM_PIN_FUNCTION(atest_usb1),
+ MSM_PIN_FUNCTION(atest_usb10),
+ MSM_PIN_FUNCTION(atest_usb11),
+ MSM_PIN_FUNCTION(atest_usb12),
+ MSM_PIN_FUNCTION(atest_usb13),
+ MSM_PIN_FUNCTION(audio_ref),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async),
+ MSM_PIN_FUNCTION(cci_i2c),
+ MSM_PIN_FUNCTION(cci_timer0),
+ MSM_PIN_FUNCTION(cci_timer1),
+ MSM_PIN_FUNCTION(cci_timer2),
+ MSM_PIN_FUNCTION(cci_timer3),
+ MSM_PIN_FUNCTION(cci_timer4),
+ MSM_PIN_FUNCTION(cmu_rng0),
+ MSM_PIN_FUNCTION(cmu_rng1),
+ MSM_PIN_FUNCTION(cmu_rng2),
+ MSM_PIN_FUNCTION(cmu_rng3),
+ MSM_PIN_FUNCTION(coex_uart1),
+ MSM_PIN_FUNCTION(cri_trng),
+ MSM_PIN_FUNCTION(cri_trng0),
+ MSM_PIN_FUNCTION(cri_trng1),
+ MSM_PIN_FUNCTION(dbg_out),
+ MSM_PIN_FUNCTION(ddr_bist),
+ MSM_PIN_FUNCTION(ddr_pxi0),
+ MSM_PIN_FUNCTION(ddr_pxi1),
+ MSM_PIN_FUNCTION(dp_hot),
+ MSM_PIN_FUNCTION(dp_lcd),
+ MSM_PIN_FUNCTION(edp_hot),
+ MSM_PIN_FUNCTION(edp_lcd),
+ MSM_PIN_FUNCTION(egpio),
+ MSM_PIN_FUNCTION(gcc_gp1),
+ MSM_PIN_FUNCTION(gcc_gp2),
+ MSM_PIN_FUNCTION(gcc_gp3),
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(host2wlan_sol),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(lpass_slimbus),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(mdp_vsync0),
+ MSM_PIN_FUNCTION(mdp_vsync1),
+ MSM_PIN_FUNCTION(mdp_vsync2),
+ MSM_PIN_FUNCTION(mdp_vsync3),
+ MSM_PIN_FUNCTION(mdp_vsync4),
+ MSM_PIN_FUNCTION(mdp_vsync5),
+ MSM_PIN_FUNCTION(mi2s0_data0),
+ MSM_PIN_FUNCTION(mi2s0_data1),
+ MSM_PIN_FUNCTION(mi2s0_sck),
+ MSM_PIN_FUNCTION(mi2s0_ws),
+ MSM_PIN_FUNCTION(mi2s1_data0),
+ MSM_PIN_FUNCTION(mi2s1_data1),
+ MSM_PIN_FUNCTION(mi2s1_sck),
+ MSM_PIN_FUNCTION(mi2s1_ws),
+ MSM_PIN_FUNCTION(mi2s2_data0),
+ MSM_PIN_FUNCTION(mi2s2_data1),
+ MSM_PIN_FUNCTION(mi2s2_sck),
+ MSM_PIN_FUNCTION(mi2s2_ws),
+ MSM_PIN_FUNCTION(mss_grfc0),
+ MSM_PIN_FUNCTION(mss_grfc1),
+ MSM_PIN_FUNCTION(mss_grfc10),
+ MSM_PIN_FUNCTION(mss_grfc11),
+ MSM_PIN_FUNCTION(mss_grfc12),
+ MSM_PIN_FUNCTION(mss_grfc2),
+ MSM_PIN_FUNCTION(mss_grfc3),
+ MSM_PIN_FUNCTION(mss_grfc4),
+ MSM_PIN_FUNCTION(mss_grfc5),
+ MSM_PIN_FUNCTION(mss_grfc6),
+ MSM_PIN_FUNCTION(mss_grfc7),
+ MSM_PIN_FUNCTION(mss_grfc8),
+ MSM_PIN_FUNCTION(mss_grfc9),
+ MSM_PIN_FUNCTION(nav_gpio0),
+ MSM_PIN_FUNCTION(nav_gpio1),
+ MSM_PIN_FUNCTION(nav_gpio2),
+ MSM_PIN_FUNCTION(pa_indicator),
+ MSM_PIN_FUNCTION(pcie0_clkreqn),
+ MSM_PIN_FUNCTION(pcie1_clkreqn),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist),
+ MSM_PIN_FUNCTION(pll_bypassnl),
+ MSM_PIN_FUNCTION(pll_clk),
+ MSM_PIN_FUNCTION(pll_reset),
+ MSM_PIN_FUNCTION(pri_mi2s),
+ MSM_PIN_FUNCTION(prng_rosc),
+ MSM_PIN_FUNCTION(qdss),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qlink0_enable),
+ MSM_PIN_FUNCTION(qlink0_request),
+ MSM_PIN_FUNCTION(qlink0_wmss),
+ MSM_PIN_FUNCTION(qlink1_enable),
+ MSM_PIN_FUNCTION(qlink1_request),
+ MSM_PIN_FUNCTION(qlink1_wmss),
+ MSM_PIN_FUNCTION(qspi_clk),
+ MSM_PIN_FUNCTION(qspi_cs),
+ MSM_PIN_FUNCTION(qspi_data),
+ MSM_PIN_FUNCTION(qup00),
+ MSM_PIN_FUNCTION(qup01),
+ MSM_PIN_FUNCTION(qup02),
+ MSM_PIN_FUNCTION(qup03),
+ MSM_PIN_FUNCTION(qup04),
+ MSM_PIN_FUNCTION(qup05),
+ MSM_PIN_FUNCTION(qup06),
+ MSM_PIN_FUNCTION(qup07),
+ MSM_PIN_FUNCTION(qup10),
+ MSM_PIN_FUNCTION(qup11),
+ MSM_PIN_FUNCTION(qup12),
+ MSM_PIN_FUNCTION(qup13),
+ MSM_PIN_FUNCTION(qup14),
+ MSM_PIN_FUNCTION(qup15),
+ MSM_PIN_FUNCTION(qup16),
+ MSM_PIN_FUNCTION(qup17),
+ MSM_PIN_FUNCTION(sd_write),
+ MSM_PIN_FUNCTION(sdc40),
+ MSM_PIN_FUNCTION(sdc41),
+ MSM_PIN_FUNCTION(sdc42),
+ MSM_PIN_FUNCTION(sdc43),
+ MSM_PIN_FUNCTION(sdc4_clk),
+ MSM_PIN_FUNCTION(sdc4_cmd),
+ MSM_PIN_FUNCTION(sec_mi2s),
+ MSM_PIN_FUNCTION(tb_trig),
+ MSM_PIN_FUNCTION(tgu_ch0),
+ MSM_PIN_FUNCTION(tgu_ch1),
+ MSM_PIN_FUNCTION(tsense_pwm1),
+ MSM_PIN_FUNCTION(tsense_pwm2),
+ MSM_PIN_FUNCTION(uim0_clk),
+ MSM_PIN_FUNCTION(uim0_data),
+ MSM_PIN_FUNCTION(uim0_present),
+ MSM_PIN_FUNCTION(uim0_reset),
+ MSM_PIN_FUNCTION(uim1_clk),
+ MSM_PIN_FUNCTION(uim1_data),
+ MSM_PIN_FUNCTION(uim1_present),
+ MSM_PIN_FUNCTION(uim1_reset),
+ MSM_PIN_FUNCTION(usb2phy_ac),
+ MSM_PIN_FUNCTION(usb_phy),
+ MSM_PIN_FUNCTION(vfr_0),
+ MSM_PIN_FUNCTION(vfr_1),
+ MSM_PIN_FUNCTION(vsense_trigger),
+};
+
+static const msm_pin_function sc7280_pin_functions[] = {
+ [0] = PINGROUP(0, qup00, ibi_i3c, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, qup00, ibi_i3c, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, qup00, qup07, _, qdss, _, _, _, _, _),
+ [3] = PINGROUP(3, qup00, qup07, _, qdss, _, _, _, _, _),
+ [4] = PINGROUP(4, qup01, ibi_i3c, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, qup01, ibi_i3c, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, qup01, qup07, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, qup01, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, qup02, _, qdss, _, _, _, _, _, _),
+ [9] = PINGROUP(9, qup02, _, qdss, _, _, _, _, _, _),
+ [10] = PINGROUP(10, qup02, _, qdss, _, _, _, _, _, _),
+ [11] = PINGROUP(11, qup02, _, qdss, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup03, qspi_data, sdc40, tb_trig, phase_flag, qdss, ddr_pxi1, _, _),
+ [13] = PINGROUP(13, qup03, qspi_data, sdc41, tb_trig, phase_flag, qdss, ddr_pxi1, _, _),
+ [14] = PINGROUP(14, qup03, qspi_clk, sdc4_clk, mdp_vsync, phase_flag, ddr_pxi0, _, _, _),
+ [15] = PINGROUP(15, qup03, qspi_cs, tb_trig, phase_flag, qdss_cti, ddr_pxi0, _, _, _),
+ [16] = PINGROUP(16, qup04, qspi_data, sdc42, mdp_vsync, phase_flag, qdss_cti, _, _, _),
+ [17] = PINGROUP(17, qup04, qspi_data, sdc43, _, phase_flag, _, _, _, _),
+ [18] = PINGROUP(18, qup04, _, phase_flag, qdss_cti, _, _, _, _, _),
+ [19] = PINGROUP(19, qup04, qspi_cs, sdc4_cmd, _, phase_flag, qdss_cti, _, _, _),
+ [20] = PINGROUP(20, qup05, cci_timer0, _, qdss, _, _, _, _, _),
+ [21] = PINGROUP(21, qup05, cci_timer1, _, qdss, _, _, _, _, _),
+ [22] = PINGROUP(22, qup05, _, qdss, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup05, _, qdss, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup06, _, qdss, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup06, _, qdss, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup06, host2wlan_sol, _, qdss, _, _, _, _, _),
+ [27] = PINGROUP(27, qup06, _, qdss, _, _, _, _, _, _),
+ [28] = PINGROUP(28, qup07, _, qdss, _, _, _, _, _, _),
+ [29] = PINGROUP(29, qup07, qdss, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, qup07, _, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, qup07, _, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, qup10, _, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup10, _, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, qup10, _, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, qup10, _, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup11, ibi_i3c, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup11, ibi_i3c, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, qup11, qup14, dbg_out, _, _, _, _, _, _),
+ [39] = PINGROUP(39, qup11, _, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup12, _, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, qup12, _, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, qup12, _, _, _, _, _, _, _, _),
+ [43] = PINGROUP(43, qup12, _, _, _, _, _, _, _, _),
+ [44] = PINGROUP(44, qup13, _, _, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup13, _, _, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup13, edp_lcd, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, qup13, dp_hot, _, _, _, _, _, _, _),
+ [48] = PINGROUP(48, qup14, _, _, _, _, _, _, _, _),
+ [49] = PINGROUP(49, qup14, _, _, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup14, qup16, _, _, _, _, _, _, _),
+ [51] = PINGROUP(51, qup14, _, _, _, _, _, _, _, _),
+ [52] = PINGROUP(52, qup15, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, qup15, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, qup15, qup14, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup15, qup14, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup16, ddr_bist, phase_flag, _, _, _, _, _, _),
+ [57] = PINGROUP(57, qup16, ddr_bist, phase_flag, _, _, _, _, _, _),
+ [58] = PINGROUP(58, qup16, ddr_bist, phase_flag, qdss, _, _, _, _, _),
+ [59] = PINGROUP(59, qup16, ddr_bist, phase_flag, qdss, _, _, _, _, _),
+ [60] = PINGROUP(60, qup17, edp_hot, _, phase_flag, _, _, _, _, _),
+ [61] = PINGROUP(61, qup17, sd_write, phase_flag, tsense_pwm1, tsense_pwm2, _, _, _, _),
+ [62] = PINGROUP(62, qup17, qup16, phase_flag, _, _, _, _, _, _),
+ [63] = PINGROUP(63, qup17, qup16, phase_flag, _, _, _, _, _, _),
+ [64] = PINGROUP(64, cam_mclk, _, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, cam_mclk, tgu_ch0, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, cam_mclk, pll_bypassnl, tgu_ch1, _, _, _, _, _, _),
+ [67] = PINGROUP(67, cam_mclk, pll_reset, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, cam_mclk, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, cci_i2c, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, cci_i2c, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, cci_i2c, _, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, cci_i2c, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, cci_i2c, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, cci_i2c, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, cci_i2c, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, cci_i2c, gcc_gp1, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, cci_timer2, gcc_gp2, _, atest_usb13, atest_char0, _, _, _, _),
+ [78] = PINGROUP(78, cci_timer3, cci_async, gcc_gp3, _, atest_usb12, atest_char1, _, _, _),
+ [79] = PINGROUP(79, cci_timer4, cci_async, pcie1_clkreqn, mdp_vsync, jitter_bist,
+ atest_usb11, atest_char2, _, _),
+ [80] = PINGROUP(80, mdp_vsync, vfr_0, mdp_vsync0, mdp_vsync1, mdp_vsync4, pll_bist,
+ atest_usb10, atest_char3, _),
+ [81] = PINGROUP(81, mdp_vsync, dp_lcd, mdp_vsync2, mdp_vsync3, mdp_vsync5, atest_usb1,
+ atest_char, _, _),
+ [82] = PINGROUP(82, _, _, _, _, _, _, _, _, _),
+ [83] = PINGROUP(83, _, _, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, usb2phy_ac, _, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, usb2phy_ac, _, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, _, _, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, _, _, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, pcie0_clkreqn, _, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, _, _, _, _, _, _, _, _, _),
+ [90] = PINGROUP(90, _, _, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, _, _, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, _, _, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, cam_mclk, cci_async, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, lpass_slimbus, _, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, lpass_slimbus, _, _, _, _, _, _, _, _),
+ [96] = PINGROUP(96, pri_mi2s, _, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, mi2s0_sck, _, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, mi2s0_data0, _, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, mi2s0_data1, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, mi2s0_ws, _, vsense_trigger, _, _, _, _, _, _),
+ [101] = PINGROUP(101, mi2s2_sck, _, qdss, _, _, _, _, _, _),
+ [102] = PINGROUP(102, mi2s2_data0, _, _, qdss, _, _, _, _, _),
+ [103] = PINGROUP(103, mi2s2_ws, vfr_1, _, _, qdss, _, atest_usb03, _, _),
+ [104] = PINGROUP(104, mi2s2_data1, _, _, qdss, _, atest_usb02, _, _, _),
+ [105] = PINGROUP(105, sec_mi2s, mi2s1_data1, audio_ref, gcc_gp1, _, qdss,
+ atest_usb01, _, _),
+ [106] = PINGROUP(106, mi2s1_sck, gcc_gp2, _, qdss, atest_usb00, _, _, _, _),
+ [107] = PINGROUP(107, mi2s1_data0, gcc_gp3, _, qdss, atest_usb0, _, _, _, _),
+ [108] = PINGROUP(108, mi2s1_ws, _, qdss, _, _, _, _, _, _),
+ [109] = PINGROUP(109, uim1_data, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, uim1_clk, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, uim1_reset, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, uim1_present, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, uim0_data, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, uim0_clk, _, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, uim0_reset, _, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, uim0_present, _, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, _, mss_grfc0, cmu_rng3, phase_flag, _, _, _, _, _),
+ [118] = PINGROUP(118, _, mss_grfc1, cmu_rng2, phase_flag, _, _, _, _, _),
+ [119] = PINGROUP(119, _, mss_grfc2, cmu_rng1, phase_flag, _, _, _, _, _),
+ [120] = PINGROUP(120, _, mss_grfc3, cmu_rng0, phase_flag, _, _, _, _, _),
+ [121] = PINGROUP(121, _, mss_grfc4, cri_trng0, phase_flag, _, _, _, _, _),
+ [122] = PINGROUP(122, _, mss_grfc5, cri_trng1, phase_flag, _, _, _, _, _),
+ [123] = PINGROUP(123, _, mss_grfc6, prng_rosc, phase_flag, _, _, _, _, _),
+ [124] = PINGROUP(124, _, mss_grfc7, cri_trng, phase_flag, _, _, _, _, _),
+ [125] = PINGROUP(125, _, mss_grfc8, phase_flag, _, _, _, _, _, _),
+ [126] = PINGROUP(126, _, mss_grfc9, phase_flag, _, _, _, _, _, _),
+ [127] = PINGROUP(127, coex_uart1, mss_grfc10, phase_flag, _, _, _, _, _, _),
+ [128] = PINGROUP(128, coex_uart1, mss_grfc11, phase_flag, _, _, _, _, _, _),
+ [129] = PINGROUP(129, nav_gpio0, phase_flag, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, nav_gpio1, phase_flag, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, mss_grfc12, nav_gpio2, pa_indicator, phase_flag, _, _, _, _, _),
+ [132] = PINGROUP(132, mss_grfc0, phase_flag, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, qlink0_request, _, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, qlink0_enable, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, qlink0_wmss, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, qlink1_request, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, qlink1_enable, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, qlink1_wmss, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, usb_phy, pll_clk, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, _, _, _, _, _, _, _, _, egpio),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, egpio),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, egpio),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, egpio),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, egpio),
+ [149] = PINGROUP(149, _, _, _, _, _, _, _, _, egpio),
+ [150] = PINGROUP(150, qdss, _, _, _, _, _, _, _, egpio),
+ [151] = PINGROUP(151, qdss, _, _, _, _, _, _, _, egpio),
+ [152] = PINGROUP(152, qdss, _, _, _, _, _, _, _, egpio),
+ [153] = PINGROUP(153, qdss, _, _, _, _, _, _, _, egpio),
+ [154] = PINGROUP(154, _, _, _, _, _, _, _, _, egpio),
+ [155] = PINGROUP(155, _, _, _, _, _, _, _, _, egpio),
+ [156] = PINGROUP(156, qdss_cti, _, _, _, _, _, _, _, egpio),
+ [157] = PINGROUP(157, qdss_cti, _, _, _, _, _, _, _, egpio),
+ [158] = PINGROUP(158, _, _, _, _, _, _, _, _, egpio),
+ [159] = PINGROUP(159, _, _, _, _, _, _, _, _, egpio),
+ [160] = PINGROUP(160, _, _, _, _, _, _, _, _, egpio),
+ [161] = PINGROUP(161, _, _, _, _, _, _, _, _, egpio),
+ [162] = PINGROUP(162, _, _, _, _, _, _, _, _, egpio),
+ [163] = PINGROUP(163, _, _, _, _, _, _, _, _, egpio),
+ [164] = PINGROUP(164, _, _, _, _, _, _, _, _, egpio),
+ [165] = PINGROUP(165, qdss_cti, _, _, _, _, _, _, _, egpio),
+ [166] = PINGROUP(166, qdss_cti, _, _, _, _, _, _, _, egpio),
+ [167] = PINGROUP(167, _, _, _, _, _, _, _, _, egpio),
+ [168] = PINGROUP(168, _, _, _, _, _, _, _, _, egpio),
+ [169] = PINGROUP(169, _, _, _, _, _, _, _, _, egpio),
+ [170] = PINGROUP(170, _, _, _, _, _, _, _, _, egpio),
+ [171] = PINGROUP(171, qdss, _, _, _, _, _, _, _, egpio),
+ [172] = PINGROUP(172, qdss, _, _, _, _, _, _, _, egpio),
+ [173] = PINGROUP(173, qdss, _, _, _, _, _, _, _, egpio),
+ [174] = PINGROUP(174, qdss, _, _, _, _, _, _, _, egpio),
+};
+
static const struct msm_special_pin_data sc7280_special_pins_data[] = {
[0] = UFS_RESET("ufs_reset", 0xbe000),
[1] = SDC_PINGROUP("sdc1_rclk", 0xb3004, 0, 6),
@@ -71,7 +568,20 @@ static const char *sc7280_get_pin_name(struct udevice *dev, unsigned int selecto
static int sc7280_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
{
- return msm_pinctrl_functions[selector].val;
+ unsigned int i;
+ const msm_pin_function *func = NULL;
+
+ if (pin >= ARRAY_SIZE(sc7280_pin_functions))
+ return -EINVAL;
+
+ func = sc7280_pin_functions + pin;
+ for (i = 0; i < 10; i++)
+ if ((*func)[i] == selector)
+ return i;
+
+ pr_err("Can't find requested function for pin %u pin\n", pin);
+
+ return -EINVAL;
}
static struct msm_pinctrl_data sc7280_data = {
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index 2f63a8e54e5..012d7762384 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -90,6 +90,14 @@ config MESON_SECURE_POWER_DOMAIN
Enable support for manipulating Amlogic Meson Secure power domains.
Support for Amlogic A1 series.
+config QCOM_RPMH_POWER_DOMAIN
+ bool "Enable the QCOM RPMH Power domain driver"
+ depends on POWER_DOMAIN && ARCH_SNAPDRAGON
+ help
+ Generic RPMH power domain implementation for QCOM devices.
+ The RPMH power domain driver is responsible for managing power
+ domains on Qualcomm SoCs.
+
config SANDBOX_POWER_DOMAIN
bool "Enable the sandbox power domain test driver"
depends on POWER_DOMAIN && SANDBOX
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index b2c0bd8a61a..f373fc01395 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
obj-$(CONFIG_TI_OMAP_PRM_POWER_DOMAIN) += ti-omap-prm.o
obj-$(CONFIG_ZYNQMP_POWER_DOMAIN) += zynqmp-power-domain.o
+obj-$(CONFIG_QCOM_RPMH_POWER_DOMAIN) += qcom-rpmhpd.o
diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c
index cea68945cbd..b4cda5f6c16 100644
--- a/drivers/power/domain/power-domain-uclass.c
+++ b/drivers/power/domain/power-domain-uclass.c
@@ -10,6 +10,7 @@
#include <malloc.h>
#include <power-domain.h>
#include <power-domain-uclass.h>
+#include <dm/device_compat.h>
#include <dm/device-internal.h>
struct power_domain_priv {
@@ -187,6 +188,12 @@ static int dev_power_domain_ctrl(struct udevice *dev, bool on)
"#power-domain-cells", 0);
for (i = 0; i < count; i++) {
ret = power_domain_get_by_index(dev, &pd, i);
+
+ if (ret == -ENODEV) {
+ dev_warn(dev, "power-domain driver not found\n");
+ return 0;
+ }
+
if (ret)
return ret;
if (on)
diff --git a/drivers/power/domain/qcom-rpmhpd.c b/drivers/power/domain/qcom-rpmhpd.c
new file mode 100644
index 00000000000..f51bc9a4bbb
--- /dev/null
+++ b/drivers/power/domain/qcom-rpmhpd.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+// Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <power-domain.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+
+#include <power-domain-uclass.h>
+#include <soc/qcom/cmd-db.h>
+#include <soc/qcom/rpmh.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+#include <dm/device_compat.h>
+
+#define RPMH_ARC_MAX_LEVELS 16
+
+/**
+ * struct rpmhpd - top level RPMh power domain resource data structure
+ * @dev: rpmh power domain controller device
+ * @pd: generic_pm_domain corresponding to the power domain
+ * @parent: generic_pm_domain corresponding to the parent's power domain
+ * @enable_corner: lowest non-zero corner
+ * @level: An array of level (vlvl) to corner (hlvl) mappings
+ * derived from cmd-db
+ * @level_count: Number of levels supported by the power domain. max
+ * being 16 (0 - 15)
+ * @enabled: true if the power domain is enabled
+ * @res_name: Resource name used for cmd-db lookup
+ * @addr: Resource address as looped up using resource name from
+ * @skip_retention_level: Indicate that retention level should not be used for the power domain
+ */
+struct rpmhpd {
+ struct udevice *dev;
+ struct power_domain pd;
+ struct power_domain *parent;
+ unsigned int enable_corner;
+ u32 level[RPMH_ARC_MAX_LEVELS];
+ size_t level_count;
+ bool enabled;
+ const char *res_name;
+ u32 addr;
+ bool skip_retention_level;
+};
+
+struct rpmhpd_desc {
+ struct rpmhpd **rpmhpds;
+ size_t num_pds;
+};
+
+/* RPMH powerdomains */
+static struct rpmhpd mmcx_ao;
+static struct rpmhpd mmcx = {
+ .res_name = "mmcx.lvl",
+};
+
+static struct rpmhpd mmcx_ao = {
+ .res_name = "mmcx.lvl",
+};
+
+/* SA8775P RPMH power domains */
+static struct rpmhpd *sa8775p_rpmhpds[] = {
+ [SA8775P_MMCX] = &mmcx,
+ [SA8775P_MMCX_AO] = &mmcx_ao,
+};
+
+static const struct rpmhpd_desc sa8775p_desc = {
+ .rpmhpds = sa8775p_rpmhpds,
+ .num_pds = ARRAY_SIZE(sa8775p_rpmhpds),
+};
+
+/* stub RPMH power domains mapped for unsupported platforms */
+static struct rpmhpd *stub_rpmhpds[] = {};
+
+static const struct rpmhpd_desc stub_desc = {
+ .rpmhpds = stub_rpmhpds,
+ .num_pds = ARRAY_SIZE(stub_rpmhpds),
+};
+
+static const struct udevice_id rpmhpd_match_table[] = {
+ { .compatible = "qcom,sa8775p-rpmhpd", .data = (ulong)&sa8775p_desc },
+ { .compatible = "qcom,qcs615-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,qcs8300-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,qdu1000-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sa8155p-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sa8540p-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sar2130p-rpmhpd", .data = (ulong)&stub_desc},
+ { .compatible = "qcom,sc7180-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sc7280-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sc8180x-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sc8280xp-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sdm670-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sdm845-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sdx55-rpmhpd", .data = (ulong)&stub_desc},
+ { .compatible = "qcom,sdx65-rpmhpd", .data = (ulong)&stub_desc},
+ { .compatible = "qcom,sdx75-rpmhpd", .data = (ulong)&stub_desc},
+ { .compatible = "qcom,sm4450-rpmhpd", .data = (ulong)&stub_desc},
+ { .compatible = "qcom,sm6350-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm7150-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8150-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8250-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8350-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8450-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8550-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8650-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,sm8750-rpmhpd", .data = (ulong)&stub_desc },
+ { .compatible = "qcom,x1e80100-rpmhpd", .data = (ulong)&stub_desc },
+ { }
+};
+
+static int rpmhpd_send_corner(struct rpmhpd *pd, int state,
+ unsigned int corner, bool sync)
+{
+ struct tcs_cmd cmd = {
+ .addr = pd->addr,
+ .data = corner,
+ };
+
+ return rpmh_write(pd->dev, state, &cmd, 1);
+}
+
+static int rpmhpd_power_on(struct power_domain *pd)
+{
+ int ret;
+ unsigned int corner;
+ struct rpmhpd **rpmhpds;
+ const struct rpmhpd_desc *desc;
+ struct rpmhpd *curr_rpmhpd;
+
+ desc = (const struct rpmhpd_desc *)dev_get_driver_data(pd->dev);
+ if (!desc)
+ return -EINVAL;
+
+ rpmhpds = desc->rpmhpds;
+ curr_rpmhpd = rpmhpds[pd->id];
+
+ /* Do nothing for undefined power domains */
+ if (!curr_rpmhpd) {
+ log_warning("Power domain id (%ld) not supported\n",
+ pd->id);
+ return 0;
+ }
+
+ corner = curr_rpmhpd->enable_corner;
+
+ ret = rpmhpd_send_corner(curr_rpmhpd, RPMH_ACTIVE_ONLY_STATE, corner,
+ false);
+ if (!ret)
+ curr_rpmhpd->enabled = true;
+
+ return ret;
+}
+
+static int rpmhpd_power_off(struct power_domain *pd)
+{
+ int ret;
+ unsigned int corner;
+ struct rpmhpd **rpmhpds;
+ const struct rpmhpd_desc *desc;
+ struct rpmhpd *curr_rpmhpd;
+
+ desc = (const struct rpmhpd_desc *)dev_get_driver_data(pd->dev);
+ if (!desc)
+ return -EINVAL;
+
+ rpmhpds = desc->rpmhpds;
+ curr_rpmhpd = rpmhpds[pd->id];
+
+ /* Do nothing for undefined power domains */
+ if (!curr_rpmhpd) {
+ log_warning("Power domain id (%ld) not supported\n",
+ pd->id);
+ return 0;
+ }
+
+ corner = 0;
+
+ ret = rpmhpd_send_corner(curr_rpmhpd, RPMH_ACTIVE_ONLY_STATE, corner,
+ false);
+ if (!ret)
+ curr_rpmhpd->enabled = false;
+
+ return ret;
+}
+
+static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
+{
+ int i;
+ const u16 *buf;
+
+ buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ /* 2 bytes used for each command DB aux data entry */
+ rpmhpd->level_count >>= 1;
+
+ if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS)
+ return -EINVAL;
+
+ for (i = 0; i < rpmhpd->level_count; i++) {
+ if (rpmhpd->skip_retention_level && buf[i] == RPMH_REGULATOR_LEVEL_RETENTION)
+ continue;
+
+ rpmhpd->level[i] = buf[i];
+
+ /* Remember the first corner with non-zero level */
+ if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i])
+ rpmhpd->enable_corner = i;
+
+ /*
+ * The AUX data may be zero padded. These 0 valued entries at
+ * the end of the map must be ignored.
+ */
+ if (i > 0 && rpmhpd->level[i] == 0) {
+ rpmhpd->level_count = i;
+ break;
+ }
+ debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i,
+ rpmhpd->level[i]);
+ }
+
+ return 0;
+}
+
+static int rpmhpd_probe(struct udevice *dev)
+{
+ int i, ret = 0;
+ struct rpmhpd **rpmhpds;
+ struct rpmhpd *priv;
+ const struct rpmhpd_desc *desc;
+
+ desc = (const struct rpmhpd_desc *)dev_get_driver_data(dev);
+ if (!desc)
+ return -EINVAL;
+
+ rpmhpds = desc->rpmhpds;
+
+ for (i = 0; i < desc->num_pds; i++) {
+ if (!rpmhpds[i])
+ continue;
+
+ priv = rpmhpds[i];
+ priv->dev = dev;
+ priv->addr = cmd_db_read_addr(priv->res_name);
+ if (!priv->addr) {
+ dev_err(dev, "Could not find RPMh address for resource %s\n",
+ priv->res_name);
+ return -ENODEV;
+ }
+
+ ret = cmd_db_read_slave_id(priv->res_name);
+ if (ret != CMD_DB_HW_ARC) {
+ dev_err(dev, "RPMh slave ID mismatch\n");
+ return -EINVAL;
+ }
+
+ ret = rpmhpd_update_level_mapping(priv);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct power_domain_ops qcom_rpmhpd_power_ops = {
+ .on = rpmhpd_power_on,
+ .off = rpmhpd_power_off,
+};
+
+U_BOOT_DRIVER(qcom_rpmhpd_drv) = {
+ .name = "qcom_rpmhpd_drv",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = rpmhpd_match_table,
+ .probe = rpmhpd_probe,
+ .ops = &qcom_rpmhpd_power_ops,
+};
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index 3f0f1845469..4d65aae1690 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -640,6 +640,35 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
{}
};
+static const struct rpmh_vreg_init_data pm7550_vreg_data[] = {
+ /* smps1 - smps6 are not added to u-boot yet */
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l5"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-l4-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo515_mv, "vdd-l12-l14"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo515_mv, "vdd-l13-l16"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l12-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo22", "ldo%s22", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo23", "ldo%s23", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ {}
+};
+
static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
@@ -947,6 +976,10 @@ static const struct udevice_id rpmh_regulator_ids[] = {
.data = (ulong)pm7325_vreg_data,
},
{
+ .compatible = "qcom,pm7550-rpmh-regulators",
+ .data = (ulong)pm7550_vreg_data,
+ },
+ {
.compatible = "qcom,pm8150-rpmh-regulators",
.data = (ulong)pm8150_vreg_data,
},
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 16ef434a8d9..90f740f51d4 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -49,6 +49,14 @@ config SYSRESET_CMD_RESET
help
Enable sysreset implementation of the reset command.
+config SYSRESET_CMD_RESET_ARGS
+ bool "Enable reset command to take arguments"
+ help
+ Pass on the arguments received by the 'reset' command to the
+ sysreset driver(s). The sysreset driver(s) may make use of the
+ additional arguments for implementing arch/board specific
+ functionality.
+
if CMD_POWEROFF
config SYSRESET_CMD_POWEROFF
@@ -293,6 +301,13 @@ config SYSRESET_RAA215300
help
Add support for the system reboot via the Renesas RAA215300 PMIC.
+config SYSRESET_QCOM_PSCI
+ bool "Support reset to EDL for Qualcomm SoCs via PSCI"
+ depends on ARM_SMCCC
+ help
+ Add support for the reset to EDL (Emergency Download) on Qualcomm
+ SoCs via PSCI.
+
config SYSRESET_QCOM_PSHOLD
bool "Support sysreset for Qualcomm SoCs via PSHOLD"
help
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index d18a5d52360..b5b99235b6e 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o
obj-$(CONFIG_$(PHASE_)SYSRESET_AT91) += sysreset_at91.o
obj-$(CONFIG_$(PHASE_)SYSRESET_X86) += sysreset_x86.o
obj-$(CONFIG_SYSRESET_RAA215300) += sysreset_raa215300.o
+obj-$(CONFIG_SYSRESET_QCOM_PSCI) += sysreset_qcom-psci.o
obj-$(CONFIG_SYSRESET_QCOM_PSHOLD) += sysreset_qcom-pshold.o
obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
obj-$(CONFIG_SYSRESET_QEMU_VIRT_CTRL) += sysreset_qemu_virt_ctrl.o
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c
index 536ac727142..f25e09e9cd0 100644
--- a/drivers/sysreset/sysreset-uclass.c
+++ b/drivers/sysreset/sysreset-uclass.c
@@ -32,6 +32,18 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type)
return ops->request(dev, type);
}
+#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET_ARGS)
+int sysreset_request_arg(struct udevice *dev, int argc, char * const argv[])
+{
+ struct sysreset_ops *ops = sysreset_get_ops(dev);
+
+ if (!ops->request_arg)
+ return -ENOSYS;
+
+ return ops->request_arg(dev, argc, argv);
+}
+#endif /* CONFIG_SYSRESET_CMD_RESET_ARGS */
+
int sysreset_get_status(struct udevice *dev, char *buf, int size)
{
struct sysreset_ops *ops = sysreset_get_ops(dev);
@@ -71,6 +83,26 @@ int sysreset_walk(enum sysreset_t type)
return ret;
}
+#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET_ARGS)
+int sysreset_walk_arg(int argc, char * const argv[])
+{
+ struct udevice *dev;
+ int ret = -ENOSYS;
+
+ while (ret != -EINPROGRESS && ret != -EPROTONOSUPPORT) {
+ for (uclass_first_device(UCLASS_SYSRESET, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ ret = sysreset_request_arg(dev, argc, argv);
+ if (ret == -EINPROGRESS || ret == -EPROTONOSUPPORT)
+ break;
+ }
+ }
+
+ return ret;
+}
+#endif /* CONFIG_SYSRESET_CMD_RESET_ARGS */
+
int sysreset_get_last_walk(void)
{
struct udevice *dev;
@@ -132,6 +164,11 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
printf("resetting ...\n");
mdelay(100);
+#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET_ARGS)
+ if (argc > 1 && sysreset_walk_arg(argc, argv) == -EINPROGRESS)
+ return 0;
+#endif
+
sysreset_walk_halt(reset_type);
return 0;
diff --git a/drivers/sysreset/sysreset_qcom-psci.c b/drivers/sysreset/sysreset_qcom-psci.c
new file mode 100644
index 00000000000..3627bbf5c82
--- /dev/null
+++ b/drivers/sysreset/sysreset_qcom-psci.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Masahiro Yamada <[email protected]>
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <dm.h>
+#include <sysreset.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/psci.h>
+#include <asm/psci.h>
+
+static int qcom_psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+ return -EOPNOTSUPP;
+}
+
+static int qcom_psci_sysreset_request_arg(struct udevice *dev, int argc,
+ char * const argv[])
+{
+ if (!strncasecmp(argv[1], "-edl", 4)) {
+ /* Supported in qcs9100, qcs8300, sc7280, qcs615 */
+ if (psci_features(ARM_PSCI_1_1_FN64_SYSTEM_RESET2) ==
+ ARM_PSCI_RET_SUCCESS) {
+ psci_system_reset2(0, 1);
+ return -EINPROGRESS;
+ }
+ printf("PSCI SYSTEM_RESET2 not supported\n");
+ }
+
+ return -EPROTONOSUPPORT;
+}
+
+static struct sysreset_ops qcom_psci_sysreset_ops = {
+ .request_arg = qcom_psci_sysreset_request_arg,
+ .get_status = qcom_psci_sysreset_get_status,
+};
+
+U_BOOT_DRIVER(qcom_psci_sysreset) = {
+ .name = "qcom_psci-sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &qcom_psci_sysreset_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5fc0505c788..4d67c948ec1 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -795,6 +795,11 @@ static optee_invoke_fn *get_invoke_func(struct udevice *dev)
return ERR_PTR(-EINVAL);
}
+bool is_optee_smc_api(void)
+{
+ return is_optee_api(optee_smccc_smc);
+}
+
static int optee_of_to_plat(struct udevice *dev)
{
struct optee_pdata *pdata = dev_get_plat(dev);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 65c4d1a4e6f..0dee14c8b59 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -106,6 +106,8 @@ done:
if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
mdelay(50);
+ mdelay(100);
+
return 0;
}
diff --git a/include/sysreset.h b/include/sysreset.h
index ff20abdeed3..d1cc9ebc542 100644
--- a/include/sysreset.h
+++ b/include/sysreset.h
@@ -43,6 +43,24 @@ struct sysreset_ops {
* (in which case this method will not actually return)
*/
int (*request)(struct udevice *dev, enum sysreset_t type);
+
+ /**
+ * @request_arg: Reset handler implementations that might need to process
+ * arguments given to the 'reset' command.
+ *
+ * Note that this function may return before the reset takes effect.
+ *
+ * @dev: Device to be used for system reset
+ * @argc: No. of items in @argv
+ * @argv: Arguments given to 'reset' command
+ * Return:
+ * -EINPROGRESS if the reset has started and will complete soon
+ * -EPROTONOSUPPORT if not supported by this device
+ * 0 if the reset has already happened
+ * (in which case this method will not actually return)
+ */
+ int (*request_arg)(struct udevice *dev, int argc, char * const argv[]);
+
/**
* @get_status: get printable reset status information
*
diff --git a/include/tee/optee.h b/include/tee/optee.h
index 77729450bb6..d1194493780 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -65,4 +65,13 @@ static inline int optee_copy_fdt_nodes(void *new_blob)
}
#endif
+#if defined(CONFIG_OPTEE)
+bool is_optee_smc_api(void);
+#else
+static inline bool is_optee_smc_api(void)
+{
+ return false;
+}
+#endif
+
#endif /* _OPTEE_H */
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index bae98e07d23..48c62999787 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -102,8 +102,7 @@ config EFI_SET_TIME
can be used by an EFI application to adjust the real time clock.
config EFI_HAVE_RUNTIME_RESET
- # bool "Reset runtime service is available"
- bool
+ bool "Reset runtime service"
default y
depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \
SANDBOX || SYSRESET_SBI || SYSRESET_X86