summaryrefslogtreecommitdiff
path: root/drivers/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/Kconfig15
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/cadence/phy-cadence-sierra.c13
-rw-r--r--drivers/phy/cadence/phy-cadence-torrent.c1
-rw-r--r--drivers/phy/marvell/comphy_core.c4
-rw-r--r--drivers/phy/marvell/comphy_core.h4
-rw-r--r--drivers/phy/phy-exynos-usbdrd.c386
-rw-r--r--drivers/phy/phy-imx8mq-usb.c91
-rw-r--r--drivers/phy/qcom/phy-qcom-snps-eusb2.c3
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-usb2.c47
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c368
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c2
-rw-r--r--drivers/phy/rockchip/phy-rockchip-usbdp.c101
13 files changed, 855 insertions, 181 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index d3fe90d939e..d36a5f00ef8 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -259,6 +259,15 @@ config MT76X8_USB_PHY
This PHY is found on MT76x8 devices supporting USB.
+config PHY_EXYNOS_USBDRD
+ bool "Exynos SoC series USB DRD PHY driver"
+ depends on PHY && CLK
+ depends on ARCH_EXYNOS
+ select REGMAP
+ select SYSCON
+ help
+ Enable USB DRD PHY support for Exynos SoC series.
+
config PHY_MTK_TPHY
bool "MediaTek T-PHY Driver"
depends on PHY
@@ -280,11 +289,11 @@ config PHY_NPCM_USB
Support the USB PHY in NPCM SoCs
config PHY_IMX8MQ_USB
- bool "NXP i.MX8MQ/i.MX8MP USB PHY Driver"
+ bool "NXP i.MX8MQ/i.MX8MP/i.MX95 USB PHY Driver"
depends on PHY
- depends on IMX8MQ || IMX8MP
+ depends on IMX8MQ || IMX8MP || IMX95
help
- Support the USB3.0 PHY in NXP i.MX8MQ or i.MX8MP SoC
+ Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, and i.MX95 SoC
config PHY_IMX8M_PCIE
bool "NXP i.MX8MM/i.MX8MP PCIe PHY Driver"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index b4d01fc700d..98c1ef8683b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
obj-$(CONFIG_MT7620_USB_PHY) += mt7620-usb-phy.o
obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
+obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c
index 2c9d5a12127..bd7ab9d1b77 100644
--- a/drivers/phy/cadence/phy-cadence-sierra.c
+++ b/drivers/phy/cadence/phy-cadence-sierra.c
@@ -225,11 +225,6 @@ static const struct reg_field pllctrl_lock =
static const struct reg_field phy_iso_link_ctrl_1 =
REG_FIELD(SIERRA_PHY_ISO_LINK_CTRL, 1, 1);
-static const char * const clk_names[] = {
- [CDNS_SIERRA_PLL_CMNLC] = "pll_cmnlc",
- [CDNS_SIERRA_PLL_CMNLC1] = "pll_cmnlc1",
-};
-
enum cdns_sierra_cmn_plllc {
CMN_PLLLC,
CMN_PLLLC1,
@@ -602,7 +597,7 @@ static int cdns_sierra_pll_bind_of_clocks(struct cdns_sierra_phy *sp)
struct udevice *dev = sp->dev;
struct driver *cdns_sierra_clk_drv;
struct cdns_sierra_pll_mux_sel *data = pll_clk_mux_sel;
- int i, rc;
+ int rc;
cdns_sierra_clk_drv = lists_driver_lookup_name("cdns_sierra_mux_clk");
if (!cdns_sierra_clk_drv) {
@@ -612,10 +607,8 @@ static int cdns_sierra_pll_bind_of_clocks(struct cdns_sierra_phy *sp)
rc = device_bind(dev, cdns_sierra_clk_drv, "pll_mux_clk",
data, dev_ofnode(dev), NULL);
- if (rc) {
- dev_err(dev, "cannot bind driver for clock %s\n",
- clk_names[i]);
- }
+ if (rc)
+ dev_err(dev, "cannot bind driver for clock pll_mux_clk\n");
return 0;
}
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 1f566d082f9..28fe026223c 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -719,6 +719,7 @@ static int cdns_torrent_phy_probe(struct udevice *dev)
if (total_num_lanes > MAX_NUM_LANES) {
dev_err(dev, "Invalid lane configuration\n");
+ ret = -EINVAL;
goto put_lnk_rst;
}
diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c
index a666a4e794e..a4121423873 100644
--- a/drivers/phy/marvell/comphy_core.c
+++ b/drivers/phy/marvell/comphy_core.c
@@ -28,7 +28,7 @@ static const char *get_speed_string(u32 speed)
"10.3125 Gbps"
};
- if (speed < 0 || speed > COMPHY_SPEED_MAX)
+ if (speed < 0 || speed >= COMPHY_SPEED_MAX)
return "invalid";
return speed_strings[speed];
@@ -44,7 +44,7 @@ static const char *get_type_string(u32 type)
"IGNORE"
};
- if (type < 0 || type > COMPHY_TYPE_MAX)
+ if (type < 0 || type >= COMPHY_TYPE_MAX)
return "invalid";
return type_strings[type];
diff --git a/drivers/phy/marvell/comphy_core.h b/drivers/phy/marvell/comphy_core.h
index f3d04939387..086a4d82f26 100644
--- a/drivers/phy/marvell/comphy_core.h
+++ b/drivers/phy/marvell/comphy_core.h
@@ -47,8 +47,8 @@ struct chip_serdes_phy_config {
int (*rx_training)(struct chip_serdes_phy_config *, u32);
void __iomem *comphy_base_addr;
void __iomem *hpipe3_base_addr;
- u32 comphy_lanes_count;
- u32 comphy_mux_bitcount;
+ int comphy_lanes_count;
+ int comphy_mux_bitcount;
const fdt32_t *comphy_mux_lane_order;
u32 cp_index;
struct comphy_map comphy_map_data[MAX_LANE_OPTIONS];
diff --git a/drivers/phy/phy-exynos-usbdrd.c b/drivers/phy/phy-exynos-usbdrd.c
new file mode 100644
index 00000000000..db5815ed184
--- /dev/null
+++ b/drivers/phy/phy-exynos-usbdrd.c
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Linaro Ltd.
+ * Sam Protsenko <semen.protsenko@linaro.org>
+ *
+ * Samsung Exynos SoC series USB DRD PHY driver.
+ * Based on Linux kernel PHY driver: drivers/phy/samsung/phy-exynos5-usbdrd.c
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+/* Offset of PMU register controlling USB PHY output isolation */
+#define EXYNOS_USBDRD_PHY_CONTROL 0x0704
+#define EXYNOS_PHY_ENABLE BIT(0)
+
+/* Exynos USB PHY registers */
+#define EXYNOS5_FSEL_9MHZ6 0x0
+#define EXYNOS5_FSEL_10MHZ 0x1
+#define EXYNOS5_FSEL_12MHZ 0x2
+#define EXYNOS5_FSEL_19MHZ2 0x3
+#define EXYNOS5_FSEL_20MHZ 0x4
+#define EXYNOS5_FSEL_24MHZ 0x5
+#define EXYNOS5_FSEL_26MHZ 0x6
+#define EXYNOS5_FSEL_50MHZ 0x7
+
+/* Exynos850: USB DRD PHY registers */
+#define EXYNOS850_DRD_LINKCTRL 0x04
+#define LINKCTRL_FORCE_QACT BIT(8)
+#define LINKCTRL_BUS_FILTER_BYPASS GENMASK(7, 4)
+
+#define EXYNOS850_DRD_CLKRST 0x20
+#define CLKRST_LINK_SW_RST BIT(0)
+#define CLKRST_PORT_RST BIT(1)
+#define CLKRST_PHY_SW_RST BIT(3)
+
+#define EXYNOS850_DRD_SSPPLLCTL 0x30
+#define SSPPLLCTL_FSEL GENMASK(2, 0)
+
+#define EXYNOS850_DRD_UTMI 0x50
+#define UTMI_FORCE_SLEEP BIT(0)
+#define UTMI_FORCE_SUSPEND BIT(1)
+#define UTMI_DM_PULLDOWN BIT(2)
+#define UTMI_DP_PULLDOWN BIT(3)
+#define UTMI_FORCE_BVALID BIT(4)
+#define UTMI_FORCE_VBUSVALID BIT(5)
+
+#define EXYNOS850_DRD_HSP 0x54
+#define HSP_COMMONONN BIT(8)
+#define HSP_EN_UTMISUSPEND BIT(9)
+#define HSP_VBUSVLDEXT BIT(12)
+#define HSP_VBUSVLDEXTSEL BIT(13)
+#define HSP_FSV_OUT_EN BIT(24)
+
+#define EXYNOS850_DRD_HSP_TEST 0x5c
+#define HSP_TEST_SIDDQ BIT(24)
+
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+/**
+ * struct exynos_usbdrd_phy - driver data for Exynos USB PHY
+ * @reg_phy: USB PHY controller register memory base
+ * @clk: clock for register access
+ * @core_clk: core clock for phy (ref clock)
+ * @reg_pmu: regmap for PMU block
+ * @extrefclk: frequency select settings when using 'separate reference clocks'
+ */
+struct exynos_usbdrd_phy {
+ void __iomem *reg_phy;
+ struct clk *clk;
+ struct clk *core_clk;
+ struct regmap *reg_pmu;
+ u32 extrefclk;
+};
+
+static void exynos_usbdrd_phy_isol(struct regmap *reg_pmu, bool isolate)
+{
+ unsigned int val;
+
+ if (!reg_pmu)
+ return;
+
+ val = isolate ? 0 : EXYNOS_PHY_ENABLE;
+ regmap_update_bits(reg_pmu, EXYNOS_USBDRD_PHY_CONTROL,
+ EXYNOS_PHY_ENABLE, val);
+}
+
+/*
+ * Convert the supplied clock rate to the value that can be written to the PHY
+ * register.
+ */
+static unsigned int exynos_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ switch (rate) {
+ case 9600 * KHZ:
+ *reg = EXYNOS5_FSEL_9MHZ6;
+ break;
+ case 10 * MHZ:
+ *reg = EXYNOS5_FSEL_10MHZ;
+ break;
+ case 12 * MHZ:
+ *reg = EXYNOS5_FSEL_12MHZ;
+ break;
+ case 19200 * KHZ:
+ *reg = EXYNOS5_FSEL_19MHZ2;
+ break;
+ case 20 * MHZ:
+ *reg = EXYNOS5_FSEL_20MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS5_FSEL_24MHZ;
+ break;
+ case 26 * MHZ:
+ *reg = EXYNOS5_FSEL_26MHZ;
+ break;
+ case 50 * MHZ:
+ *reg = EXYNOS5_FSEL_50MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos850_usbdrd_utmi_init(struct phy *phy)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
+ void __iomem *regs_base = phy_drd->reg_phy;
+ u32 reg;
+
+ /*
+ * Disable HWACG (hardware auto clock gating control). This will force
+ * QACTIVE signal in Q-Channel interface to HIGH level, to make sure
+ * the PHY clock is not gated by the hardware.
+ */
+ reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
+ reg |= LINKCTRL_FORCE_QACT;
+ writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
+
+ /* Start PHY Reset (POR=high) */
+ reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
+ reg |= CLKRST_PHY_SW_RST;
+ writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
+
+ /* Enable UTMI+ */
+ reg = readl(regs_base + EXYNOS850_DRD_UTMI);
+ reg &= ~(UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP | UTMI_DP_PULLDOWN |
+ UTMI_DM_PULLDOWN);
+ writel(reg, regs_base + EXYNOS850_DRD_UTMI);
+
+ /* Set PHY clock and control HS PHY */
+ reg = readl(regs_base + EXYNOS850_DRD_HSP);
+ reg |= HSP_EN_UTMISUSPEND | HSP_COMMONONN;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP);
+
+ /* Set VBUS Valid and D+ pull-up control by VBUS pad usage */
+ reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
+ reg |= FIELD_PREP(LINKCTRL_BUS_FILTER_BYPASS, 0xf);
+ writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
+
+ reg = readl(regs_base + EXYNOS850_DRD_UTMI);
+ reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
+ writel(reg, regs_base + EXYNOS850_DRD_UTMI);
+
+ reg = readl(regs_base + EXYNOS850_DRD_HSP);
+ reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP);
+
+ reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL);
+ reg &= ~SSPPLLCTL_FSEL;
+ switch (phy_drd->extrefclk) {
+ case EXYNOS5_FSEL_50MHZ:
+ reg |= FIELD_PREP(SSPPLLCTL_FSEL, 7);
+ break;
+ case EXYNOS5_FSEL_26MHZ:
+ reg |= FIELD_PREP(SSPPLLCTL_FSEL, 6);
+ break;
+ case EXYNOS5_FSEL_24MHZ:
+ reg |= FIELD_PREP(SSPPLLCTL_FSEL, 2);
+ break;
+ case EXYNOS5_FSEL_20MHZ:
+ reg |= FIELD_PREP(SSPPLLCTL_FSEL, 1);
+ break;
+ case EXYNOS5_FSEL_19MHZ2:
+ reg |= FIELD_PREP(SSPPLLCTL_FSEL, 0);
+ break;
+ default:
+ dev_warn(phy->dev, "unsupported ref clk: %#.2x\n",
+ phy_drd->extrefclk);
+ break;
+ }
+ writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL);
+
+ /* Power up PHY analog blocks */
+ reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
+ reg &= ~HSP_TEST_SIDDQ;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
+
+ /* Finish PHY reset (POR=low) */
+ udelay(10); /* required before doing POR=low */
+ reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
+ reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST);
+ writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
+ udelay(75); /* required after POR=low for guaranteed PHY clock */
+
+ /* Disable single ended signal out */
+ reg = readl(regs_base + EXYNOS850_DRD_HSP);
+ reg &= ~HSP_FSV_OUT_EN;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP);
+}
+
+static void exynos850_usbdrd_utmi_exit(struct phy *phy)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
+ void __iomem *regs_base = phy_drd->reg_phy;
+ u32 reg;
+
+ /* Set PHY clock and control HS PHY */
+ reg = readl(regs_base + EXYNOS850_DRD_UTMI);
+ reg &= ~(UTMI_DP_PULLDOWN | UTMI_DM_PULLDOWN);
+ reg |= UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP;
+ writel(reg, regs_base + EXYNOS850_DRD_UTMI);
+
+ /* Power down PHY analog blocks */
+ reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
+ reg |= HSP_TEST_SIDDQ;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
+
+ /* Link reset */
+ reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
+ reg |= CLKRST_LINK_SW_RST;
+ writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
+ udelay(10); /* required before doing POR=low */
+ reg &= ~CLKRST_LINK_SW_RST;
+ writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
+}
+
+static int exynos_usbdrd_phy_init(struct phy *phy)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
+ int ret;
+
+ ret = clk_prepare_enable(phy_drd->clk);
+ if (ret)
+ return ret;
+
+ exynos850_usbdrd_utmi_init(phy);
+
+ clk_disable_unprepare(phy_drd->clk);
+
+ return 0;
+}
+
+static int exynos_usbdrd_phy_exit(struct phy *phy)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
+ int ret;
+
+ ret = clk_prepare_enable(phy_drd->clk);
+ if (ret)
+ return ret;
+
+ exynos850_usbdrd_utmi_exit(phy);
+
+ clk_disable_unprepare(phy_drd->clk);
+
+ return 0;
+}
+
+static int exynos_usbdrd_phy_power_on(struct phy *phy)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
+ int ret;
+
+ dev_dbg(phy->dev, "Request to power_on usbdrd_phy phy\n");
+
+ ret = clk_prepare_enable(phy_drd->core_clk);
+ if (ret)
+ return ret;
+
+ /* Power-on PHY */
+ exynos_usbdrd_phy_isol(phy_drd->reg_pmu, false);
+
+ return 0;
+}
+
+static int exynos_usbdrd_phy_power_off(struct phy *phy)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
+
+ dev_dbg(phy->dev, "Request to power_off usbdrd_phy phy\n");
+
+ /* Power-off the PHY */
+ exynos_usbdrd_phy_isol(phy_drd->reg_pmu, true);
+
+ clk_disable_unprepare(phy_drd->core_clk);
+
+ return 0;
+}
+
+static int exynos_usbdrd_phy_init_clk(struct udevice *dev)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev);
+ unsigned long ref_rate;
+ int err;
+
+ phy_drd->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(phy_drd->clk)) {
+ err = PTR_ERR(phy_drd->clk);
+ dev_err(dev, "Failed to get phy clock (err=%d)\n", err);
+ return err;
+ }
+
+ phy_drd->core_clk = devm_clk_get(dev, "ref");
+ if (IS_ERR(phy_drd->core_clk)) {
+ err = PTR_ERR(phy_drd->core_clk);
+ dev_err(dev, "Failed to get ref clock (err=%d)\n", err);
+ return err;
+ }
+
+ ref_rate = clk_get_rate(phy_drd->core_clk);
+ err = exynos_rate_to_clk(ref_rate, &phy_drd->extrefclk);
+ if (err) {
+ dev_err(dev, "Clock rate %lu not supported\n", ref_rate);
+ return err;
+ }
+
+ return 0;
+}
+
+static int exynos_usbdrd_phy_probe(struct udevice *dev)
+{
+ struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev);
+ int err;
+
+ phy_drd->reg_phy = dev_read_addr_ptr(dev);
+ if (!phy_drd->reg_phy)
+ return -EINVAL;
+
+ err = exynos_usbdrd_phy_init_clk(dev);
+ if (err)
+ return err;
+
+ phy_drd->reg_pmu = syscon_regmap_lookup_by_phandle(dev,
+ "samsung,pmu-syscon");
+ if (IS_ERR(phy_drd->reg_pmu)) {
+ err = PTR_ERR(phy_drd->reg_pmu);
+ dev_err(dev, "Failed to lookup PMU regmap\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops exynos_usbdrd_phy_ops = {
+ .init = exynos_usbdrd_phy_init,
+ .exit = exynos_usbdrd_phy_exit,
+ .power_on = exynos_usbdrd_phy_power_on,
+ .power_off = exynos_usbdrd_phy_power_off,
+};
+
+static const struct udevice_id exynos_usbdrd_phy_of_match[] = {
+ {
+ .compatible = "samsung,exynos850-usbdrd-phy",
+ },
+ { }
+};
+
+U_BOOT_DRIVER(exynos_usbdrd_phy) = {
+ .name = "exynos-usbdrd-phy",
+ .id = UCLASS_PHY,
+ .of_match = exynos_usbdrd_phy_of_match,
+ .probe = exynos_usbdrd_phy_probe,
+ .ops = &exynos_usbdrd_phy_ops,
+ .priv_auto = sizeof(struct exynos_usbdrd_phy),
+};
diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c
index 75763046adc..387db843c50 100644
--- a/drivers/phy/phy-imx8mq-usb.c
+++ b/drivers/phy/phy-imx8mq-usb.c
@@ -71,9 +71,57 @@
#define PHY_STS0_FSVPLUS BIT(3)
#define PHY_STS0_FSVMINUS BIT(2)
+#define TCA_CLK_RST 0x00
+#define TCA_CLK_RST_SW BIT(9)
+#define TCA_CLK_RST_REF_CLK_EN BIT(1)
+#define TCA_CLK_RST_SUSPEND_CLK_EN BIT(0)
+
+#define TCA_INTR_EN 0x04
+#define TCA_INTR_STS 0x08
+
+#define TCA_GCFG 0x10
+#define TCA_GCFG_ROLE_HSTDEV BIT(4)
+#define TCA_GCFG_OP_MODE GENMASK(1, 0)
+#define TCA_GCFG_OP_MODE_SYSMODE 0
+#define TCA_GCFG_OP_MODE_SYNCMODE 1
+
+#define TCA_TCPC 0x14
+#define TCA_TCPC_VALID BIT(4)
+#define TCA_TCPC_LOW_POWER_EN BIT(3)
+#define TCA_TCPC_ORIENTATION_NORMAL BIT(2)
+#define TCA_TCPC_MUX_CONTRL GENMASK(1, 0)
+#define TCA_TCPC_MUX_CONTRL_NO_CONN 0
+#define TCA_TCPC_MUX_CONTRL_USB_CONN 1
+
+#define TCA_SYSMODE_CFG 0x18
+#define TCA_SYSMODE_TCPC_DISABLE BIT(3)
+#define TCA_SYSMODE_TCPC_FLIP BIT(2)
+
+#define TCA_CTRLSYNCMODE_CFG0 0x20
+#define TCA_CTRLSYNCMODE_CFG1 0x20
+
+#define TCA_PSTATE 0x30
+#define TCA_PSTATE_CM_STS BIT(4)
+#define TCA_PSTATE_TX_STS BIT(3)
+#define TCA_PSTATE_RX_PLL_STS BIT(2)
+#define TCA_PSTATE_PIPE0_POWER_DOWN GENMASK(1, 0)
+
+#define TCA_GEN_STATUS 0x34
+#define TCA_GEN_DEV_POR BIT(12)
+#define TCA_GEN_REF_CLK_SEL BIT(8)
+#define TCA_GEN_TYPEC_FLIP_INVERT BIT(4)
+#define TCA_GEN_PHY_TYPEC_DISABLE BIT(3)
+#define TCA_GEN_PHY_TYPEC_FLIP BIT(2)
+
+#define TCA_VBUS_CTRL 0x40
+#define TCA_VBUS_STATUS 0x44
+
+#define TCA_INFO 0xfc
+
enum imx8mpq_phy_type {
IMX8MQ_PHY,
IMX8MP_PHY,
+ IMX95_PHY,
};
struct imx8mq_usb_phy {
@@ -81,14 +129,49 @@ struct imx8mq_usb_phy {
void __iomem *base;
enum imx8mpq_phy_type type;
struct udevice *vbus_supply;
+ void __iomem *tca_base;
};
static const struct udevice_id imx8mq_usb_phy_of_match[] = {
{ .compatible = "fsl,imx8mq-usb-phy", .data = IMX8MQ_PHY },
{ .compatible = "fsl,imx8mp-usb-phy", .data = IMX8MP_PHY },
+ { .compatible = "fsl,imx95-usb-phy", .data = IMX95_PHY },
{},
};
+static void tca_blk_init(struct phy *usb_phy)
+{
+ struct udevice *dev = usb_phy->dev;
+ struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
+ void __iomem *base = imx_phy->tca_base;
+ u32 val;
+
+ /* reset XBar block */
+ val = readl(base + TCA_CLK_RST);
+ val &= ~TCA_CLK_RST_SW;
+ writel(val, base + TCA_CLK_RST);
+
+ udelay(100);
+
+ /* clear reset */
+ val |= TCA_CLK_RST_SW;
+ writel(val, base + TCA_CLK_RST);
+
+ /*
+ * use Controller Synced Mode for TCA low power enable and
+ * put PHY to USB safe state.
+ */
+ val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE);
+ writel(val, base + TCA_GCFG);
+
+ val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN;
+ writel(val, base + TCA_TCPC);
+
+ /* use System Configuration Mode for TCA mux control. */
+ val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE);
+ writel(val, base + TCA_GCFG);
+}
+
static int imx8mq_usb_phy_init(struct phy *usb_phy)
{
struct udevice *dev = usb_phy->dev;
@@ -154,6 +237,9 @@ static int imx8mp_usb_phy_init(struct phy *usb_phy)
value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
writel(value, imx_phy->base + PHY_CTRL1);
+ if (imx_phy->tca_base)
+ tca_blk_init(usb_phy);
+
return 0;
}
@@ -162,7 +248,7 @@ static int imx8mpq_usb_phy_init(struct phy *usb_phy)
struct udevice *dev = usb_phy->dev;
struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
- if (imx_phy->type == IMX8MP_PHY)
+ if (imx_phy->type == IMX8MP_PHY || imx_phy->type == IMX95_PHY)
return imx8mp_usb_phy_init(usb_phy);
else
return imx8mq_usb_phy_init(usb_phy);
@@ -264,6 +350,9 @@ int imx8mq_usb_phy_probe(struct udevice *dev)
}
}
+ if (priv->type == IMX95_PHY)
+ priv->tca_base = dev_read_addr_index_ptr(dev, 1);
+
return 0;
}
diff --git a/drivers/phy/qcom/phy-qcom-snps-eusb2.c b/drivers/phy/qcom/phy-qcom-snps-eusb2.c
index b2655ac007c..28502c46f67 100644
--- a/drivers/phy/qcom/phy-qcom-snps-eusb2.c
+++ b/drivers/phy/qcom/phy-qcom-snps-eusb2.c
@@ -331,8 +331,9 @@ static int qcom_snps_eusb2_phy_probe(struct udevice *dev)
qcom_snps_eusb2->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(qcom_snps_eusb2->ref_clk)) {
+ ret = PTR_ERR(qcom_snps_eusb2->ref_clk);
printf("%s: failed to get ref clk %d\n", __func__, ret);
- return PTR_ERR(qcom_snps_eusb2->ref_clk);
+ return ret;
}
ret = reset_get_bulk(dev, &qcom_snps_eusb2->resets);
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 88b33de1b2a..4ea6600ce7f 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -167,20 +167,27 @@ static struct phy_ops rockchip_usb2phy_ops = {
.of_xlate = rockchip_usb2phy_of_xlate,
};
-static void rockchip_usb2phy_clkout_ctl(struct clk *clk, struct regmap **base,
- const struct usb2phy_reg **clkout_ctl)
+static int rockchip_usb2phy_clkout_ctl(struct clk *clk, struct regmap **base,
+ const struct usb2phy_reg **clkout_ctl)
{
struct udevice *parent = dev_get_parent(clk->dev);
struct rockchip_usb2phy *priv = dev_get_priv(parent);
const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
- if (priv->phy_cfg->clkout_ctl_phy.enable) {
+ // phy_cfg can be NULL if this function called before probe (when parent
+ // clocks are enabled)
+ if (!phy_cfg)
+ return -EINVAL;
+
+ if (phy_cfg->clkout_ctl_phy.enable) {
*base = priv->phy_base;
*clkout_ctl = &phy_cfg->clkout_ctl_phy;
} else {
*base = priv->reg_base;
*clkout_ctl = &phy_cfg->clkout_ctl;
}
+
+ return 0;
}
/**
@@ -206,7 +213,8 @@ int rockchip_usb2phy_clk_enable(struct clk *clk)
const struct usb2phy_reg *clkout_ctl;
struct regmap *base;
- rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl);
+ if (rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl))
+ return -ENOSYS;
/* turn on 480m clk output if it is off */
if (!property_enabled(base, clkout_ctl)) {
@@ -230,7 +238,8 @@ int rockchip_usb2phy_clk_disable(struct clk *clk)
const struct usb2phy_reg *clkout_ctl;
struct regmap *base;
- rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl);
+ if (rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl))
+ return -ENOSYS;
/* turn off 480m clk output */
property_enable(base, clkout_ctl, false);
@@ -456,6 +465,28 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
{ /* sentinel */ }
};
+static const struct rockchip_usb2phy_cfg rk3576_phy_cfgs[] = {
+ {
+ .reg = 0x0000,
+ .clkout_ctl = { 0x0008, 0, 0, 1, 0 },
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x0000, 1, 0, 2, 1 },
+ }
+ },
+ },
+ {
+ .reg = 0x2000,
+ .clkout_ctl = { 0x2008, 0, 0, 1, 0 },
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x2000, 1, 0, 2, 1 },
+ }
+ },
+ },
+ { /* sentinel */ }
+};
+
static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = {
{
.reg = 0x0000,
@@ -518,6 +549,10 @@ static const struct udevice_id rockchip_usb2phy_ids[] = {
.data = (ulong)&rk3568_phy_cfgs,
},
{
+ .compatible = "rockchip,rk3576-usb2phy",
+ .data = (ulong)&rk3576_phy_cfgs,
+ },
+ {
.compatible = "rockchip,rk3588-usb2phy",
.data = (ulong)&rk3588_phy_cfgs,
},
@@ -538,7 +573,7 @@ U_BOOT_DRIVER(rockchip_usb2phy_clock) = {
U_BOOT_DRIVER(rockchip_usb2phy) = {
.name = "rockchip_usb2phy",
- .id = UCLASS_PHY,
+ .id = UCLASS_NOP,
.of_match = rockchip_usb2phy_ids,
.probe = rockchip_usb2phy_probe,
.bind = rockchip_usb2phy_bind,
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 5145b517aa4..d602f965d6a 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -37,6 +37,7 @@ struct rockchip_combphy_grfcfg {
struct combphy_reg pipe_rxterm_set;
struct combphy_reg pipe_txelec_set;
struct combphy_reg pipe_txcomp_set;
+ struct combphy_reg pipe_clk_24m;
struct combphy_reg pipe_clk_25m;
struct combphy_reg pipe_clk_100m;
struct combphy_reg pipe_phymode_sel;
@@ -98,104 +99,41 @@ static int param_write(struct regmap *base,
return regmap_write(base, reg->offset, val);
}
-static int rockchip_combphy_pcie_init(struct rockchip_combphy_priv *priv)
-{
- int ret = 0;
-
- if (priv->cfg->combphy_cfg) {
- ret = priv->cfg->combphy_cfg(priv);
- if (ret) {
- dev_err(priv->dev, "failed to init phy for pcie\n");
- return ret;
- }
- }
-
- return ret;
-}
-
-static int rockchip_combphy_usb3_init(struct rockchip_combphy_priv *priv)
-{
- int ret = 0;
-
- if (priv->cfg->combphy_cfg) {
- ret = priv->cfg->combphy_cfg(priv);
- if (ret) {
- dev_err(priv->dev, "failed to init phy for usb3\n");
- return ret;
- }
- }
-
- return ret;
-}
-
-static int rockchip_combphy_sata_init(struct rockchip_combphy_priv *priv)
-{
- int ret = 0;
-
- if (priv->cfg->combphy_cfg) {
- ret = priv->cfg->combphy_cfg(priv);
- if (ret) {
- dev_err(priv->dev, "failed to init phy for sata\n");
- return ret;
- }
- }
-
- return ret;
-}
-
-static int rockchip_combphy_sgmii_init(struct rockchip_combphy_priv *priv)
+static int rockchip_combphy_init(struct phy *phy)
{
- int ret = 0;
-
- if (priv->cfg->combphy_cfg) {
- ret = priv->cfg->combphy_cfg(priv);
- if (ret) {
- dev_err(priv->dev, "failed to init phy for sgmii\n");
- return ret;
- }
- }
+ struct rockchip_combphy_priv *priv = dev_get_priv(phy->dev);
+ int ret;
- return ret;
-}
+ ret = clk_enable(&priv->ref_clk);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
-static int rockchip_combphy_set_mode(struct rockchip_combphy_priv *priv)
-{
switch (priv->mode) {
case PHY_TYPE_PCIE:
- rockchip_combphy_pcie_init(priv);
- break;
case PHY_TYPE_USB3:
- rockchip_combphy_usb3_init(priv);
- break;
case PHY_TYPE_SATA:
- rockchip_combphy_sata_init(priv);
- break;
case PHY_TYPE_SGMII:
case PHY_TYPE_QSGMII:
- return rockchip_combphy_sgmii_init(priv);
+ if (priv->cfg->combphy_cfg)
+ ret = priv->cfg->combphy_cfg(priv);
+ else
+ ret = 0;
+ break;
default:
dev_err(priv->dev, "incompatible PHY type\n");
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
- return 0;
-}
-
-static int rockchip_combphy_init(struct phy *phy)
-{
- struct rockchip_combphy_priv *priv = dev_get_priv(phy->dev);
- int ret;
-
- ret = clk_enable(&priv->ref_clk);
- if (ret < 0 && ret != -ENOSYS)
- return ret;
+ if (ret) {
+ dev_err(priv->dev, "failed to init phy for phy type %x\n", priv->mode);
+ goto err_clk;
+ }
- ret = rockchip_combphy_set_mode(priv);
+ ret = reset_deassert_bulk(&priv->phy_rsts);
if (ret)
goto err_clk;
- reset_deassert_bulk(&priv->phy_rsts);
-
return 0;
err_clk:
@@ -223,6 +161,7 @@ static int rockchip_combphy_xlate(struct phy *phy, struct ofnode_phandle_args *a
return -EINVAL;
}
+ phy->id = priv->id;
priv->mode = args->args[0];
return 0;
@@ -237,22 +176,19 @@ static const struct phy_ops rockchip_combphy_ops = {
static int rockchip_combphy_parse_dt(struct udevice *dev,
struct rockchip_combphy_priv *priv)
{
- struct udevice *syscon;
int ret;
- ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,pipe-grf", &syscon);
- if (ret) {
- dev_err(dev, "failed to find peri_ctrl pipe-grf regmap");
- return ret;
+ priv->pipe_grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,pipe-grf");
+ if (IS_ERR(priv->pipe_grf)) {
+ dev_err(dev, "failed to find peri_ctrl pipe-grf regmap\n");
+ return PTR_ERR(priv->pipe_grf);
}
- priv->pipe_grf = syscon_get_regmap(syscon);
- ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,pipe-phy-grf", &syscon);
- if (ret) {
+ priv->phy_grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,pipe-phy-grf");
+ if (IS_ERR(priv->phy_grf)) {
dev_err(dev, "failed to find peri_ctrl pipe-phy-grf regmap\n");
- return ret;
+ return PTR_ERR(priv->phy_grf);
}
- priv->phy_grf = syscon_get_regmap(syscon);
ret = clk_get_by_index(dev, 0, &priv->ref_clk);
if (ret) {
@@ -304,12 +240,109 @@ static int rockchip_combphy_probe(struct udevice *udev)
}
priv->dev = udev;
- priv->mode = PHY_TYPE_SATA;
+ priv->mode = PHY_NONE;
priv->cfg = phy_cfg;
return rockchip_combphy_parse_dt(udev, priv);
}
+static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+ u32 val;
+
+ switch (priv->mode) {
+ case PHY_TYPE_PCIE:
+ /* Set SSC downward spread spectrum */
+ val = readl(priv->mmio + 0x18);
+ val &= ~GENMASK(5, 4);
+ val |= 0x01 << 4;
+ writel(val, priv->mmio + 0x18);
+
+ param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ break;
+ case PHY_TYPE_USB3:
+ /* Set SSC downward spread spectrum */
+ val = readl(priv->mmio + 0x18);
+ val &= ~GENMASK(5, 4);
+ val |= 0x01 << 4;
+ writel(val, priv->mmio + 0x18);
+
+ /* Enable adaptive CTLE for USB3.0 Rx */
+ val = readl(priv->mmio + 0x200);
+ val &= ~GENMASK(17, 17);
+ val |= 0x01 << 17;
+ writel(val, priv->mmio + 0x200);
+
+ /* Set Rx squelch input filler bandwidth */
+ val = readl(priv->mmio + 0x20c);
+ val &= ~GENMASK(2, 0);
+ val |= 0x06;
+ writel(val, priv->mmio + 0x20c);
+
+ param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
+ param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
+ param_write(priv->phy_grf, &cfg->usb_mode_set, true);
+ param_write(priv->pipe_grf, &cfg->u3otg0_port_en, true);
+ break;
+ default:
+ dev_err(priv->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
+
+ if (priv->mode == PHY_TYPE_PCIE) {
+ /* PLL KVCO tuning fine */
+ val = readl(priv->mmio + 0x18);
+ val &= ~(0x7 << 10);
+ val |= 0x2 << 10;
+ writel(val, priv->mmio + 0x18);
+
+ /* su_trim[6:4]=111, [10:7]=1001, [2:0]=000 */
+ val = readl(priv->mmio + 0x108);
+ val &= ~(0x7f7);
+ val |= 0x4f0;
+ writel(val, priv->mmio + 0x108);
+ }
+
+ return 0;
+}
+
+static const struct rockchip_combphy_grfcfg rk3528_combphy_grfcfgs = {
+ /* pipe-phy-grf */
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
+ .pipe_clk_24m = { 0x0004, 14, 13, 0x00, 0x00 },
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x110 },
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x00 },
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x101 },
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
+ /* pipe-grf */
+ .u3otg0_port_en = { 0x0044, 15, 0, 0x0181, 0x1100 },
+};
+
+static const struct rockchip_combphy_cfg rk3528_combphy_cfgs = {
+ .num_phys = 1,
+ .phy_ids = {
+ 0xffdc0000,
+ },
+ .grfcfg = &rk3528_combphy_grfcfgs,
+ .combphy_cfg = rk3528_combphy_cfg,
+};
+
static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
{
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
@@ -453,6 +486,149 @@ static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
.combphy_cfg = rk3568_combphy_cfg,
};
+static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+ u32 val;
+
+ switch (priv->mode) {
+ case PHY_TYPE_PCIE:
+ param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ break;
+ case PHY_TYPE_USB3:
+ /* Set SSC downward spread spectrum */
+ val = readl(priv->mmio + (0x1f << 2));
+ val &= ~GENMASK(5, 4);
+ val |= 0x01 << 4;
+ writel(val, priv->mmio + 0x7c);
+
+ /* Enable adaptive CTLE for USB3.0 Rx */
+ val = readl(priv->mmio + (0x0e << 2));
+ val &= ~GENMASK(0, 0);
+ val |= 0x01;
+ writel(val, priv->mmio + (0x0e << 2));
+
+ /* Set PLL KVCO fine tuning signals */
+ val = readl(priv->mmio + (0x20 << 2));
+ val &= ~(0x7 << 2);
+ val |= 0x2 << 2;
+ writel(val, priv->mmio + (0x20 << 2));
+
+ /* Set PLL LPF R1 to su_trim[10:7]=1001 */
+ writel(0x4, priv->mmio + (0xb << 2));
+
+ /* Set PLL input clock divider 1/2 */
+ val = readl(priv->mmio + (0x5 << 2));
+ val &= ~(0x3 << 6);
+ val |= 0x1 << 6;
+ writel(val, priv->mmio + (0x5 << 2));
+
+ /* Set PLL loop divider */
+ writel(0x32, priv->mmio + (0x11 << 2));
+
+ /* Set PLL KVCO to min and set PLL charge pump current to max */
+ writel(0xf0, priv->mmio + (0xa << 2));
+
+ /* Set Rx squelch input filler bandwidth */
+ writel(0x0d, priv->mmio + (0x14 << 2));
+
+ param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
+ param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
+ param_write(priv->phy_grf, &cfg->usb_mode_set, true);
+ param_write(priv->pipe_grf, &cfg->u3otg1_port_en, true);
+ break;
+ case PHY_TYPE_SATA:
+ /* Enable adaptive CTLE for SATA Rx */
+ val = readl(priv->mmio + (0x0e << 2));
+ val &= ~GENMASK(0, 0);
+ val |= 0x01;
+ writel(val, priv->mmio + (0x0e << 2));
+ /* Set tx_rterm = 50 ohm and rx_rterm = 43.5 ohm */
+ writel(0x8F, priv->mmio + (0x06 << 2));
+
+ param_write(priv->phy_grf, &cfg->con0_for_sata, true);
+ param_write(priv->phy_grf, &cfg->con1_for_sata, true);
+ param_write(priv->phy_grf, &cfg->con2_for_sata, true);
+ param_write(priv->phy_grf, &cfg->con3_for_sata, true);
+ param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
+ param_write(priv->pipe_grf, &cfg->pipe_con1_for_sata, true);
+ break;
+ case PHY_TYPE_SGMII:
+ case PHY_TYPE_QSGMII:
+ default:
+ dev_err(priv->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ /* 100MHz refclock signal is good */
+ clk_set_rate(&priv->ref_clk, 100000000);
+ param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
+ if (priv->mode == PHY_TYPE_PCIE) {
+ /* gate_tx_pck_sel length select work for L1SS */
+ writel(0xc0, priv->mmio + 0x74);
+
+ /* PLL KVCO tuning fine */
+ val = readl(priv->mmio + (0x20 << 2));
+ val &= ~(0x7 << 2);
+ val |= 0x2 << 2;
+ writel(val, priv->mmio + (0x20 << 2));
+
+ /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */
+ writel(0x4c, priv->mmio + (0x1b << 2));
+
+ /* Set up su_trim: T3_P1 650mv */
+ writel(0x90, priv->mmio + (0xa << 2));
+ writel(0x43, priv->mmio + (0xb << 2));
+ writel(0x88, priv->mmio + (0xc << 2));
+ writel(0x56, priv->mmio + (0xd << 2));
+ }
+
+ return 0;
+}
+
+static const struct rockchip_combphy_grfcfg rk3576_combphy_grfcfgs = {
+ /* pipe-phy-grf */
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
+ .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
+ .pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
+ .pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
+ .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0129 },
+ .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c1 },
+ .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x0407 },
+ /* php-grf */
+ .pipe_con0_for_sata = { 0x001C, 2, 0, 0x00, 0x2 },
+ .pipe_con1_for_sata = { 0x0020, 2, 0, 0x00, 0x2 },
+ .u3otg1_port_en = { 0x0038, 15, 0, 0x0181, 0x1100 },
+};
+
+static const struct rockchip_combphy_cfg rk3576_combphy_cfgs = {
+ .num_phys = 2,
+ .phy_ids = {
+ 0x2b050000,
+ 0x2b060000,
+ },
+ .grfcfg = &rk3576_combphy_grfcfgs,
+ .combphy_cfg = rk3576_combphy_cfg,
+};
+
static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv)
{
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
@@ -561,10 +737,18 @@ static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = {
static const struct udevice_id rockchip_combphy_ids[] = {
{
+ .compatible = "rockchip,rk3528-naneng-combphy",
+ .data = (ulong)&rk3528_combphy_cfgs
+ },
+ {
.compatible = "rockchip,rk3568-naneng-combphy",
.data = (ulong)&rk3568_combphy_cfgs
},
{
+ .compatible = "rockchip,rk3576-naneng-combphy",
+ .data = (ulong)&rk3576_combphy_cfgs
+ },
+ {
.compatible = "rockchip,rk3588-naneng-combphy",
.data = (ulong)&rk3588_combphy_cfgs
},
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index c48a5cd5267..66d1d32d25c 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -788,7 +788,7 @@ U_BOOT_DRIVER(rockchip_tcphy_usb3_port) = {
U_BOOT_DRIVER(rockchip_typec_phy) = {
.name = "rockchip_typec_phy",
- .id = UCLASS_PHY,
+ .id = UCLASS_NOP,
.of_match = rockchip_typec_phy_ids,
.probe = rockchip_tcphy_probe,
.bind = rockchip_tcphy_bind,
diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 9deec47ae46..cca67dd3611 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -96,9 +96,7 @@ struct rockchip_udphy {
/* PHY status management */
bool flip;
- bool mode_change;
u8 mode;
- u8 status;
/* utilized for USB */
bool hs; /* flag for high-speed */
@@ -525,80 +523,26 @@ static int udphy_parse_dt(struct rockchip_udphy *udphy, struct udevice *dev)
return 0;
}
-static int udphy_power_on(struct rockchip_udphy *udphy, u8 mode)
-{
- int ret;
-
- if (!(udphy->mode & mode)) {
- dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
- return 0;
- }
-
- if (udphy->status == UDPHY_MODE_NONE) {
- udphy->mode_change = false;
- ret = udphy_setup(udphy);
- if (ret)
- return ret;
-
- if (udphy->mode & UDPHY_MODE_USB)
- udphy_u3_port_disable(udphy, false);
- } else if (udphy->mode_change) {
- udphy->mode_change = false;
- udphy->status = UDPHY_MODE_NONE;
- if (udphy->mode == UDPHY_MODE_DP)
- udphy_u3_port_disable(udphy, true);
-
- ret = udphy_disable(udphy);
- if (ret)
- return ret;
- ret = udphy_setup(udphy);
- if (ret)
- return ret;
- }
-
- udphy->status |= mode;
-
- return 0;
-}
-
-static int udphy_power_off(struct rockchip_udphy *udphy, u8 mode)
-{
- int ret;
-
- if (!(udphy->mode & mode)) {
- dev_info(udphy->dev, "mode 0x%02x is not supported\n", mode);
- return 0;
- }
-
- if (!udphy->status)
- return 0;
-
- udphy->status &= ~mode;
-
- if (udphy->status == UDPHY_MODE_NONE) {
- ret = udphy_disable(udphy);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static int rockchip_u3phy_of_xlate(struct phy *phy,
struct ofnode_phandle_args *args)
{
+ struct rockchip_udphy *udphy = dev_get_priv(phy->dev);
+
if (args->args_count == 0)
return -EINVAL;
if (args->args[0] != PHY_TYPE_USB3)
return -EINVAL;
+ phy->id = udphy->id;
+
return 0;
}
static int rockchip_u3phy_init(struct phy *phy)
{
struct rockchip_udphy *udphy = dev_get_priv(phy->dev);
+ int ret;
/* DP only or high-speed, disable U3 port */
if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
@@ -606,7 +550,12 @@ static int rockchip_u3phy_init(struct phy *phy)
return 0;
}
- return udphy_power_on(udphy, UDPHY_MODE_USB);
+ ret = udphy_setup(udphy);
+ if (ret)
+ return ret;
+
+ udphy_u3_port_disable(udphy, false);
+ return 0;
}
static int rockchip_u3phy_exit(struct phy *phy)
@@ -617,7 +566,7 @@ static int rockchip_u3phy_exit(struct phy *phy)
if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
return 0;
- return udphy_power_off(udphy, UDPHY_MODE_USB);
+ return udphy_disable(udphy);
}
static const struct phy_ops rockchip_u3phy_ops = {
@@ -813,6 +762,28 @@ static const char * const rk3588_udphy_rst_l[] = {
"init", "cmn", "lane", "pcs_apb", "pma_apb"
};
+static const struct rockchip_udphy_cfg rk3576_udphy_cfgs = {
+ .num_phys = 1,
+ .phy_ids = {
+ 0x2b010000,
+ },
+ .num_rsts = ARRAY_SIZE(rk3588_udphy_rst_l),
+ .rst_list = rk3588_udphy_rst_l,
+ .grfcfg = {
+ /* u2phy-grf */
+ .bvalid_phy_con = { 0x0010, 1, 0, 0x2, 0x3 },
+ .bvalid_grf_con = { 0x0000, 15, 14, 0x1, 0x3 },
+
+ /* usb-grf */
+ .usb3otg0_cfg = { 0x0030, 15, 0, 0x1100, 0x0188 },
+
+ /* usbdpphy-grf */
+ .low_pwrn = { 0x0004, 13, 13, 0, 1 },
+ .rx_lfps = { 0x0004, 14, 14, 0, 1 },
+ },
+ .combophy_init = rk3588_udphy_init,
+};
+
static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = {
.num_phys = 2,
.phy_ids = {
@@ -839,6 +810,10 @@ static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = {
static const struct udevice_id rockchip_udphy_dt_match[] = {
{
+ .compatible = "rockchip,rk3576-usbdp-phy",
+ .data = (ulong)&rk3576_udphy_cfgs
+ },
+ {
.compatible = "rockchip,rk3588-usbdp-phy",
.data = (ulong)&rk3588_udphy_cfgs
},