armbian-build/patch/u-boot/v2026.01/phy-allwinner-add-pcie-usb3-driver.patch
2026-02-01 17:45:45 +01:00

704 lines
19 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sat, 25 Oct 2025 20:32:35 +0000
Subject: phy: allwinner: Add SUN55I INNO combo PHY driver for PCIe/USB3
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
drivers/phy/allwinner/Kconfig | 8 +
drivers/phy/allwinner/Makefile | 1 +
drivers/phy/allwinner/phy-sun55i-pcie-usb3.c | 656 ++++++++++
3 files changed, 665 insertions(+)
diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig
index 111111111111..222222222222 100644
--- a/drivers/phy/allwinner/Kconfig
+++ b/drivers/phy/allwinner/Kconfig
@@ -33,3 +33,11 @@ config PHY_SUN50I_USB3
help
Enable this to support the USB3 transceiver that is part of
Allwinner sun50i SoCs.
+
+config PHY_SUN55I_PCIE_USB3
+ tristate "Allwinner SUN55I INNO COMBO PHY Driver"
+ depends on ARCH_SUNXI
+ select PHY
+ help
+ Enable this to support the Allwinner sun55i PCIe/USB3.0 combo PHY
+ with INNOSILICON IP block.
diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile
index 111111111111..222222222222 100644
--- a/drivers/phy/allwinner/Makefile
+++ b/drivers/phy/allwinner/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o
+obj-$(CONFIG_PHY_SUN55I_PCIE_USB3) += phy-sun55i-pcie-usb3.o
\ No newline at end of file
diff --git a/drivers/phy/allwinner/phy-sun55i-pcie-usb3.c b/drivers/phy/allwinner/phy-sun55i-pcie-usb3.c
new file mode 100644
index 000000000000..111111111111
--- /dev/null
+++ b/drivers/phy/allwinner/phy-sun55i-pcie-usb3.c
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner PIPE USB3.0 PCIE Combo Phy driver
+ *
+ * Copyright(c) 2020 - 2024 Allwinner Technology Co.,Ltd. All rights reserved.
+ *
+ * sun55i-inno-combophy.c: chenhuaqiang <chenhuaqiang@allwinnertech.com>
+ */
+
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dt-bindings/phy/phy.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <power-domain.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+#include <reset.h>
+
+
+#define sun55i_COMBOPHY_CTL_BASE 0x04f00000
+#define sun55i_COMBOPHY_CLK_BASE 0x04f80000
+
+/* PCIE USB3 Sub-System Registers */
+/* Sub-System Version Reset Register */
+#define PCIE_USB3_SYS_VER 0x00
+
+/* CCMU Base Address */
+#define SUNXI_CCMU_BASE 0x02001000
+#define SUNXI_CCM_BASE (SUNXI_CCMU_BASE)
+
+/* Sub-System PCIE Bus Gating Reset Register */
+#define PCIE_BRG_REG_RST 16
+#define PCIE_BGR_REG (SUNXI_CCM_BASE + 0x0aac)
+
+/* Sub-System PCIE Bus Gating Reset Register */
+#define PCIE_COMBO_PHY_BGR 0x04
+#define PCIE_SLV_ACLK_EN BIT(18)
+#define PCIE_ACLK_EN BIT(17)
+#define PCIE_HCLK_EN BIT(16)
+#define PCIE_PERSTN BIT(1)
+#define PCIE_PW_UP_RSTN BIT(0)
+
+/* Sub-System USB3 Bus Gating Reset Register */
+#define USB3_COMBO_PHY_BGR 0x08
+#define USB3_ACLK_EN BIT(17)
+#define USB3_HCLK_EN BIT(16)
+#define USB3_U2_PHY_RSTN BIT(4)
+#define USB3_U2_PHY_MUX_EN BIT(3)
+#define USB3_U2_PHY_MUX_SEL BIT(0)
+#define USB3_RESETN BIT(0)
+
+/* Sub-System PCIE PHY Control Register */
+#define PCIE_COMBO_PHY_CTL 0x10
+#define PHY_USE_SEL BIT(31) /* 0:PCIE; 1:USB3 */
+#define PHY_CLK_SEL BIT(30) /* 0:internal clk; 1:external clk */
+#define PHY_BIST_EN BIT(16)
+#define PHY_PIPE_SW BIT(9)
+#define PHY_PIPE_SEL BIT(8) /* 0:rstn by PCIE or USB3; 1:rstn by PHY_PIPE_SW */
+#define PHY_PIPE_CLK_INVERT BIT(4)
+#define PHY_FPGA_SYS_RSTN BIT(1) /* for FPGA */
+#define PHY_RSTN BIT(0)
+
+/* PHY CLK Registers (offset from sun55i_COMBOPHY_CLK_BASE) */
+#define PCIE_REF_CLK_REG_PCIE_REF_CLK_GATING_CLEAR_MASK 0x80000000
+
+/* Registers */
+#define COMBO_REG_SYSVER(comb_base_addr) ((comb_base_addr) \
+ + PCIE_USB3_SYS_VER)
+#define COMBO_REG_PCIEBGR(comb_base_addr) ((comb_base_addr) \
+ + PCIE_COMBO_PHY_BGR)
+#define COMBO_REG_USB3BGR(comb_base_addr) ((comb_base_addr) \
+ + USB3_COMBO_PHY_BGR)
+#define COMBO_REG_PHYCTRL(comb_base_addr) ((comb_base_addr) \
+ + PCIE_COMBO_PHY_CTL)
+
+/* Sub-System Version Number */
+#define COMBO_VERSION_01 (0x10000)
+#define COMBO_VERSION_ANY (0x0)
+
+enum phy_use_sel {
+ PHY_USE_BY_PCIE = 0, /* PHY used by PCIE */
+ PHY_USE_BY_USB3, /* PHY used by USB3 */
+ PHY_USE_BY_PCIE_USB3_U2,/* PHY used by PCIE & USB3_U2 */
+};
+
+enum phy_refclk_sel {
+ INTER_SIG_REF_CLK = 0, /* PHY use internal single end reference clock */
+ EXTER_DIF_REF_CLK, /* PHY use external single end reference clock */
+};
+
+struct sun55i_combophy_of_data {
+ bool has_cfg_clk;
+ bool has_slv_clk;
+ bool has_phy_mbus_clk;
+ bool has_phy_ahb_clk;
+ bool has_pcie_axi_clk;
+ bool has_u2_phy_mux;
+ bool need_noppu_rst;
+ bool has_u3_phy_data_quirk;
+ bool need_optimize_jitter;
+};
+
+struct sun55i_combphy {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *phy_ctl; /* parse dts, control the phy mode, reset and power */
+ void __iomem *phy_clk; /* parse dts, set the phy clock */
+
+ struct reset_ctl reset;
+ struct reset_ctl noppu_reset;
+
+ struct clk *phyclk_ref;
+ struct clk *refclk_par;
+ struct clk *phyclk_cfg;
+ struct clk *cfgclk_par;
+ struct clk *phy_mclk;
+ struct clk *phy_hclk;
+ struct clk *phy_axi;
+ struct clk *phy_axi_par;
+ __u8 mode;
+ __u32 vernum; /* version number */
+ enum phy_use_sel user;
+ enum phy_refclk_sel ref;
+ const struct sun55i_combophy_of_data *drvdata;
+
+ struct udevice *select3v3_supply;
+ bool initialized;
+};
+
+static void sun55i_combphy_usb3_phy_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val, tmp = 0;
+
+ val = readl(combphy->phy_clk + 0x1418);
+ tmp = GENMASK(17, 16);
+ if (enable) {
+ val &= ~tmp;
+ val |= BIT(25);
+ } else {
+ val |= tmp;
+ val &= ~BIT(25);
+ }
+ writel(val, combphy->phy_clk + 0x1418);
+
+ /* reg_rx_eq_bypass[3]=1, rx_ctle_res_cal_bypass */
+ val = readl(combphy->phy_clk + 0x0674);
+ if (enable)
+ val |= BIT(3);
+ else
+ val &= ~BIT(3);
+ writel(val, combphy->phy_clk + 0x0674);
+
+ /* rx_ctle_res_cal=0xf, 0x4->0xf */
+ val = readl(combphy->phy_clk + 0x0704);
+ tmp = GENMASK(9, 8) | BIT(11);
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, combphy->phy_clk + 0x0704);
+
+ /* CDR_div_fin_gain1 */
+ val = readl(combphy->phy_clk + 0x0400);
+ if (enable)
+ val |= BIT(4);
+ else
+ val &= ~BIT(4);
+ writel(val, combphy->phy_clk + 0x0400);
+
+ /* CDR_div1_fin_gain1 */
+ val = readl(combphy->phy_clk + 0x0404);
+ tmp = GENMASK(3, 0) | BIT(5);
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, combphy->phy_clk + 0x0404);
+
+ /* CDR_div3_fin_gain1 */
+ val = readl(combphy->phy_clk + 0x0408);
+ if (enable)
+ val |= BIT(5);
+ else
+ val &= ~BIT(5);
+ writel(val, combphy->phy_clk + 0x0408);
+
+ val = readl(combphy->phy_clk + 0x109c);
+ if (enable)
+ val |= BIT(1);
+ else
+ val &= ~BIT(1);
+ writel(val, combphy->phy_clk + 0x109c);
+
+ /* balance parm configure */
+ if (combphy->drvdata->has_u3_phy_data_quirk) {
+ val = readl(combphy->phy_clk + 0x0804);
+ if (enable)
+ val |= (0x6<<4);
+ else
+ val &= ~(0xf<<4);
+ writel(val, combphy->phy_clk + 0x0804);
+ }
+
+ /* SSC configure */
+ val = readl(combphy->phy_clk + 0x107c);
+ tmp = 0x3f << 12;
+ val = val & (~tmp);
+ val |= ((0x1 << 12) & tmp); /* div_N */
+ writel(val, combphy->phy_clk + 0x107c);
+
+ val = readl(combphy->phy_clk + 0x1020);
+ tmp = 0x1f << 0;
+ val = val & (~tmp);
+ val |= ((0x6 << 0) & tmp); /* modulation freq div */
+ writel(val, combphy->phy_clk + 0x1020);
+
+ val = readl(combphy->phy_clk + 0x1034);
+ tmp = 0x7f << 16;
+ val = val & (~tmp);
+ val |= ((0x9 << 16) & tmp); /* spread[6:0], 400*9=4410ppm ssc */
+ writel(val, combphy->phy_clk + 0x1034);
+
+ val = readl(combphy->phy_clk + 0x101c);
+ tmp = 0x1 << 27;
+ val = val & (~tmp);
+ val |= ((0x1 << 27) & tmp); /* choose downspread */
+
+ tmp = 0x1 << 28;
+ val = val & (~tmp);
+ if (enable)
+ val |= ((0x0 << 28) & tmp); /* don't disable ssc = 0 */
+ else
+ val |= ((0x1 << 28) & tmp); /* don't enable ssc = 1 */
+ writel(val, combphy->phy_clk + 0x101c);
+
+#ifdef SUN55i_INNO_COMMBOPHY_DEBUG
+ /* TX Eye configure bypass_en */
+ val = readl(combphy->phy_clk + 0x0ddc);
+ if (enable)
+ val |= BIT(4); /* 0x0ddc[4]=1 */
+ else
+ val &= ~BIT(4);
+ writel(val, combphy->phy_clk + 0x0ddc);
+
+ /* Leg_cur[6:0] - 7'd84 */
+ val = readl(combphy->phy_clk + 0x0ddc);
+ val |= ((0x54 & BIT(6)) >> 3); /* 0x0ddc[3] */
+ writel(val, combphy->phy_clk + 0x0ddc);
+
+ val = readl(combphy->phy_clk + 0x0de0);
+ val |= ((0x54 & GENMASK(5, 0)) << 2); /* 0x0de0[7:2] */
+ writel(val, combphy->phy_clk + 0x0de0);
+
+ /* Leg_curb[5:0] - 6'd18 */
+ val = readl(combphy->phy_clk + 0x0de4);
+ val |= ((0x12 & GENMASK(5, 1)) >> 1); /* 0x0de4[4:0] */
+ writel(val, combphy->phy_clk + 0x0de4);
+
+ val = readl(combphy->phy_clk + 0x0de8);
+ val |= ((0x12 & BIT(0)) << 7); /* 0x0de8[7] */
+ writel(val, combphy->phy_clk + 0x0de8);
+
+ /* Exswing_isel */
+ val = readl(combphy->phy_clk + 0x0028);
+ val |= (0x4 << 28); /* 0x28[30:28] */
+ writel(val, combphy->phy_clk + 0x0028);
+
+ /* Exswing_en */
+ val = readl(combphy->phy_clk + 0x0028);
+ if (enable)
+ val |= BIT(31); /* 0x28[31]=1 */
+ else
+ val &= ~BIT(31);
+ writel(val, combphy->phy_clk + 0x0028);
+#endif
+}
+
+static int sun55i_combphy_usb3_init(struct sun55i_combphy *combphy)
+{
+ sun55i_combphy_usb3_phy_set(combphy, true);
+
+ return 0;
+}
+
+// static int sun55i_combphy_usb3_exit(struct sun55i_combphy *combphy)
+// {
+// sun55i_combphy_usb3_phy_set(combphy, false);
+
+// return 0;
+// }
+
+static void sun55i_combphy_pcie_phy_enable(struct sun55i_combphy *combphy)
+{
+ u32 val;
+
+ /* set the phy:
+ * bit(18): slv aclk enable
+ * bit(17): aclk enable
+ * bit(16): hclk enbale
+ * bit(1) : pcie_presetn
+ * bit(0) : pcie_power_up_rstn
+ */
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_BGR);
+ val &= (~(0x03<<0));
+ val &= (~(0x03<<16));
+ val |= (0x03<<0);
+ if (combphy->drvdata->has_slv_clk)
+ val |= (0x07<<16);
+ else
+ val |= (0x03<<16);
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_BGR);
+
+
+ /* select phy mode, phy assert */
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+ val &= (~PHY_USE_SEL);
+ val &= (~(0x03<<8));
+ val &= (~PHY_FPGA_SYS_RSTN);
+ val &= (~PHY_RSTN);
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+
+ /* phy De-assert */
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+ val &= (~PHY_CLK_SEL);
+ val &= (~(0x03<<8));
+ val &= (~PHY_FPGA_SYS_RSTN);
+ val &= (~PHY_RSTN);
+ val |= PHY_RSTN;
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+ val &= (~PHY_CLK_SEL);
+ val &= (~(0x03<<8));
+ val &= (~PHY_FPGA_SYS_RSTN);
+ val &= (~PHY_RSTN);
+ val |= PHY_RSTN;
+ val |= (PHY_FPGA_SYS_RSTN);
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+
+}
+
+static void sun55i_combphy_pcie_phy_100M(struct sun55i_combphy *combphy)
+{
+ u32 val;
+
+ val = readl(combphy->phy_clk + 0x1004);
+ val &= ~(0x3<<3);
+ val &= ~(0x1<<0);
+ val |= (0x1<<0);
+ val |= (0x1<<2);
+ val |= (0x1<<4);
+ writel(val, combphy->phy_clk + 0x1004);
+
+ val = readl(combphy->phy_clk + 0x1018);
+ val &= ~(0x3<<4);
+ val |= (0x3<<4);
+ writel(val, combphy->phy_clk + 0x1018);
+
+ val = readl(combphy->phy_clk + 0x101c);
+ val &= ~(0x0fffffff);
+ writel(val, combphy->phy_clk + 0x101c);
+
+ /* if need optimize jitter parm*/
+ if (combphy->drvdata->need_optimize_jitter) {
+ val = readl(combphy->phy_clk + 0x107c);
+ val &= ~(0x3ffff);
+ val |= (0x4<<12);
+ val |= 0x64;
+ writel(val, combphy->phy_clk + 0x107c);
+
+ val = readl(combphy->phy_clk + 0x1030);
+ val &= ~(0x3<<20);
+ writel(val, combphy->phy_clk + 0x1030);
+
+ val = readl(combphy->phy_clk + 0x1050);
+ val &= ~(0x7<<0);
+ val &= ~(0x7<<5);
+ val &= ~(0x3<<3);
+ val |= (0x3<<3);
+ writel(val, combphy->phy_clk + 0x1050);
+ } else {
+ val = readl(combphy->phy_clk + 0x107c);
+ val &= ~(0x3ffff);
+ val |= (0x2<<12);
+ val |= 0x32;
+ writel(val, combphy->phy_clk + 0x107c);
+
+ val = readl(combphy->phy_clk + 0x1030);
+ val &= ~(0x3<<20);
+ writel(val, combphy->phy_clk + 0x1030);
+
+ val = readl(combphy->phy_clk + 0x1050);
+ val &= ~(0x7<<5);
+ val |= (0x1<<5);
+ writel(val, combphy->phy_clk + 0x1050);
+ }
+
+ val = readl(combphy->phy_clk + 0x1054);
+ val &= ~(0x7<<5);
+ val |= (0x1<<5);
+ writel(val, combphy->phy_clk + 0x1054);
+
+ val = readl(combphy->phy_clk + 0x0804);
+ val &= ~(0xf<<4);
+ val |= (0xc<<4);
+ writel(val, combphy->phy_clk + 0x0804);
+
+ val = readl(combphy->phy_clk + 0x109c);
+ val &= ~(0x3<<8);
+ val |= (0x1<<1);
+ writel(val, combphy->phy_clk + 0x109c);
+
+ writel(0x80540a0a, combphy->phy_clk + 0x1418);
+}
+
+static int sun55i_combphy_pcie_init(struct sun55i_combphy *combphy)
+{
+ sun55i_combphy_pcie_phy_100M(combphy);
+
+ sun55i_combphy_pcie_phy_enable(combphy);
+
+ return 0;
+}
+
+static int sun55i_combphy_set_mode(struct sun55i_combphy *combphy)
+{
+ switch (combphy->mode) {
+ case PHY_TYPE_PCIE:
+ sun55i_combphy_pcie_init(combphy);
+ break;
+ case PHY_TYPE_USB3:
+ if (combphy->user == PHY_USE_BY_PCIE_USB3_U2) {
+ sun55i_combphy_pcie_init(combphy);
+ } else if (combphy->user == PHY_USE_BY_USB3) {
+ sun55i_combphy_usb3_init(combphy);
+ }
+ break;
+ default:
+ printf("incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void combo_phy_mode_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val;
+
+ val = readl(COMBO_REG_PHYCTRL(combphy->phy_ctl));
+
+ /* Set PHY_USE_SEL based on user (default: clear for PCIE/PCIE_USB3_U2, set for USB3) */
+ val &= ~PHY_USE_SEL; /* Default: clear (PCIE mode) */
+ if (combphy->user == PHY_USE_BY_USB3)
+ val |= PHY_USE_SEL;
+
+ /* Set PHY_CLK_SEL based on ref (default: clear for internal, set for external) */
+ val &= ~PHY_CLK_SEL; /* Default: clear (internal clock) */
+ if (combphy->ref == EXTER_DIF_REF_CLK)
+ val |= PHY_CLK_SEL;
+
+ /* Set or clear PHY_RSTN based on enable */
+ if (enable)
+ val |= PHY_RSTN;
+ else
+ val &= ~PHY_RSTN;
+
+ writel(val, COMBO_REG_PHYCTRL(combphy->phy_ctl));
+}
+
+/* PCIE USB3 Sub-system Application */
+static void combo_pcie_clk_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val, tmp = 0;
+
+ val = readl(COMBO_REG_PCIEBGR(combphy->phy_ctl));
+ if (combphy->drvdata->has_slv_clk)
+ tmp = PCIE_SLV_ACLK_EN | PCIE_ACLK_EN | PCIE_HCLK_EN | PCIE_PERSTN | PCIE_PW_UP_RSTN;
+ else
+ tmp = PCIE_ACLK_EN | PCIE_HCLK_EN | PCIE_PERSTN | PCIE_PW_UP_RSTN;
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, COMBO_REG_PCIEBGR(combphy->phy_ctl));
+}
+
+static void combo_usb3_clk_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val, tmp = 0;
+
+ val = readl(COMBO_REG_USB3BGR(combphy->phy_ctl));
+ if (combphy->drvdata->has_u2_phy_mux)
+ tmp = USB3_ACLK_EN | USB3_HCLK_EN | USB3_U2_PHY_MUX_SEL | USB3_U2_PHY_RSTN | USB3_U2_PHY_MUX_EN;
+ else
+ tmp = USB3_ACLK_EN | USB3_HCLK_EN | USB3_RESETN;
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, COMBO_REG_USB3BGR(combphy->phy_ctl));
+}
+
+static u32 combo_sysver_get(struct sun55i_combphy *combphy)
+{
+ u32 reg;
+
+ reg = readl(COMBO_REG_SYSVER(combphy->phy_ctl));
+
+ return reg;
+}
+
+static void pcie_usb3_sub_system_enable(struct sun55i_combphy *combphy)
+{
+ combo_phy_mode_set(combphy, true);
+
+ if (combphy->user == PHY_USE_BY_PCIE)
+ combo_pcie_clk_set(combphy, true);
+ else if (combphy->user == PHY_USE_BY_USB3)
+ combo_usb3_clk_set(combphy, true);
+ else if (combphy->user == PHY_USE_BY_PCIE_USB3_U2) {
+ combo_pcie_clk_set(combphy, true);
+ combo_usb3_clk_set(combphy, true);
+ }
+
+ combphy->vernum = combo_sysver_get(combphy);
+}
+
+static int pcie_usb3_sub_system_init(void *phy)
+{
+ struct sun55i_combphy *combphy = (struct sun55i_combphy *)(phy);
+ unsigned long reg_value = 0;
+
+ if (combphy->initialized)
+ return 0;
+
+ reg_value = readl(PCIE_BGR_REG);
+ reg_value |= (1 << PCIE_BRG_REG_RST);
+ writel(reg_value, PCIE_BGR_REG);
+
+ reg_value = 0x81000001;
+ writel(reg_value, 0x2001a84);
+
+ pcie_usb3_sub_system_enable(combphy);
+
+ combphy->initialized = true;
+
+ return 0;
+}
+
+int sun55i_combphy_init(struct phy *phy)
+{
+ struct sun55i_combphy *combphy = dev_get_priv(phy->dev);
+ int ret;
+
+ if (!combphy) {
+ printf("PHY drvdata not set!\n");
+ return -EIO;
+ }
+
+ if (combphy->select3v3_supply) {
+ ret = regulator_set_enable_if_allowed(combphy->select3v3_supply, true);
+ if (ret && ret != -EALREADY) {
+ printf("PHY: Failed to enable 3.3V supply: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = reset_deassert(&combphy->reset);
+ if (ret) {
+ printf("PHY: Failed to deassert reset: %d\n", ret);
+ regulator_set_enable(combphy->select3v3_supply, false);
+ return ret;
+ }
+
+ ret = pcie_usb3_sub_system_init(combphy);
+ if (ret) {
+ printf("PHY: failed to init sub system\n");
+ reset_assert(&combphy->reset);
+ regulator_set_enable(combphy->select3v3_supply, false);
+ return ret;
+ }
+
+ ret = sun55i_combphy_set_mode(combphy);
+ if (ret) {
+ printf("PHY: invalid number of arguments\n");
+ reset_assert(&combphy->reset);
+ regulator_set_enable(combphy->select3v3_supply, false);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct sun55i_combophy_of_data sun55i_inno_v1_of_data = {
+ .has_cfg_clk = false,
+};
+
+static int sun55i_inno_phy_probe(struct udevice *dev)
+{
+ struct sun55i_combphy *combphy = dev_get_priv(dev);
+ int ret;
+
+ combphy->phy_ctl = dev_read_addr_name_ptr(dev, "phy-ctl");
+ if (!combphy->phy_ctl)
+ return -ENODEV;
+
+ combphy->phy_clk = dev_read_addr_name_ptr(dev, "phy-clk");
+ if (!combphy->phy_clk)
+ return -ENODEV;
+
+ ret = reset_get_by_index(dev, 0, &combphy->reset);
+ if (ret)
+ return ret;
+
+ ret = device_get_supply_regulator(dev, "select3v3-supply", &combphy->select3v3_supply);
+ if (ret)
+ return ret;
+
+ combphy->drvdata = (const struct sun55i_combophy_of_data *)dev_get_driver_data(dev);
+ combphy->user = PHY_USE_BY_PCIE;
+ combphy->mode = PHY_TYPE_PCIE;
+ combphy->ref = EXTER_DIF_REF_CLK;
+
+ return 0;
+}
+
+static const struct phy_ops sun55i_inno_phy_ops = {
+ .init = sun55i_combphy_init,
+};
+
+static const struct udevice_id sun55i_inno_phy_of_match_table[] = {
+ {
+ .compatible = "allwinner,inno-combphy",
+ .data = (ulong)&sun55i_inno_v1_of_data,
+ },
+};
+
+U_BOOT_DRIVER(sun55i_inno_combophy) = {
+ .name = "sun55i_inno_combophy",
+ .id = UCLASS_PHY,
+ .of_match = sun55i_inno_phy_of_match_table,
+ .ops = &sun55i_inno_phy_ops,
+ .probe = sun55i_inno_phy_probe,
+ .priv_auto = sizeof(struct sun55i_combphy),
+};
--
Armbian