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.
This commit is contained in:
Tom Rini
2026-04-27 08:05:40 -06:00
44 changed files with 2351 additions and 51 deletions

View File

@@ -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

View File

@@ -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];
}

View File

@@ -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

View File

@@ -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[];

View File

@@ -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__);

View File

@@ -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;
}
/* 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");
fw = of_find_node_by_path("/firmware");
if (!fw) {
log_err("Failed to find /firmware node\n");
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_add_subnode(fw, "optee", strlen("optee") + 1, &optee);
if (ret) {
log_err("Failed to add 'optee' subnode: %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, "compatible", strlen("linaro,optee-tz") + 1,
"linaro,optee-tz");
if (ret) {
log_err("Failed to add optee 'compatible' property: %d\n", ret);
return;
}
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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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"
);

View File

@@ -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

View File

@@ -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

View File

@@ -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
------------

View File

@@ -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

View File

@@ -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

View File

@@ -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 <luca.weiss@fairphone.com>
*/
#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,
};

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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" },

View File

@@ -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

View File

@@ -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

View File

@@ -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),
};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 },

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Qualcomm Milos pinctrl
*
* (C) Copyright 2024 Linaro Ltd.
* (C) Copyright 2026 Luca Weiss <luca.weiss@fairphone.com>
*
*/
#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,
};

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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,
};

View File

@@ -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"),
@@ -946,6 +975,10 @@ static const struct udevice_id rpmh_regulator_ids[] = {
.compatible = "qcom,pm7325-rpmh-regulators",
.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,

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com>
* 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,
};

View File

@@ -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);

View File

@@ -106,6 +106,8 @@ done:
if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
mdelay(50);
mdelay(100);
return 0;
}

View File

@@ -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
*

View File

@@ -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 */

View File

@@ -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