mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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(®s);
|
||||
else
|
||||
hvc_call(®s);
|
||||
|
||||
return regs.regs[0];
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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__);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
5
board/qualcomm/debug-milos.config
Normal file
5
board/qualcomm/debug-milos.config
Normal 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
|
||||
4
board/qualcomm/tfa-optee.config
Normal file
4
board/qualcomm/tfa-optee.config
Normal 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
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
196
drivers/clk/qcom/clock-milos.c
Normal file
196
drivers/clk/qcom/clock-milos.c
Normal 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,
|
||||
};
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
643
drivers/phy/qcom/phy-qcom-qmp-combo.c
Normal file
643
drivers/phy/qcom/phy-qcom-qmp-combo.c
Normal 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),
|
||||
};
|
||||
62
drivers/phy/qcom/phy-qcom-qmp-common.h
Normal file
62
drivers/phy/qcom/phy-qcom-qmp-common.h
Normal 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
|
||||
18
drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h
Normal file
18
drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h
Normal 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
|
||||
34
drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h
Normal file
34
drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h
Normal 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
|
||||
@@ -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 },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
103
drivers/pinctrl/qcom/pinctrl-milos.c
Normal file
103
drivers/pinctrl/qcom/pinctrl-milos.c
Normal 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,
|
||||
};
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
278
drivers/power/domain/qcom-rpmhpd.c
Normal file
278
drivers/power/domain/qcom-rpmhpd.c
Normal 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,
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
45
drivers/sysreset/sysreset_qcom-psci.c
Normal file
45
drivers/sysreset/sysreset_qcom-psci.c
Normal 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,
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -106,6 +106,8 @@ done:
|
||||
if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
|
||||
mdelay(50);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user