diff mbox series

[1/7] phy: spacemit: k1: enable refclk and deassert the PHY reset at probe

Message ID 40be5679408eabffea146616801c6d976dc45ff9.1790975597.git.DaveWK225@protonmail.com
State New
Delegated to: Tim Ouyang
Headers show
Series phy: spacemit: k1: fix the PCIe and combo PHY driver | expand

Commit Message

Dave Klotz Oct. 2, 2026, 9:29 p.m. UTC
The driver gets the clocks and resets listed in the device tree with
clk_get_bulk() and reset_get_bulk(), but never enables or deasserts
any of them, and only warns if getting them fails. The combo PHY
instead clears GLOBAL_PHY_RST by hand in the APMU before calibrating,
and ports B and C rely on the PCIe controller driver to do the same
for them.

Linux gets the "phy" reset of every K1 PCIe PHY deasserted at probe
(devm_reset_control_get_exclusive_deasserted()) and leaves it that
way; the "refclk" oscillator is the parent of the PHY PLL and is
enabled with it. Do the same here: at probe, before any PHY register
is accessed, enable "refclk" and deassert the "phy" reset, and fail
the probe if either cannot be got or enabled. The combo PHY's PCIe
port A application clocks and resets are not part of this: the
calibration handles them, as it does in Linux.

The calibration no longer needs to clear GLOBAL_PHY_RST itself, since
that is the bit the "phy" reset controls.

Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
 drivers/phy/spacemit/phy-k1-pcie.c | 69 ++++++++++++++++++++++--------
 1 file changed, 50 insertions(+), 19 deletions(-)
diff mbox series

Patch

diff --git a/drivers/phy/spacemit/phy-k1-pcie.c b/drivers/phy/spacemit/phy-k1-pcie.c
index e54742a2a9..b445ee9d01 100644
--- a/drivers/phy/spacemit/phy-k1-pcie.c
+++ b/drivers/phy/spacemit/phy-k1-pcie.c
@@ -92,7 +92,6 @@ 
 #define PCIE_CLK_RES_CTRL		0x03cc
 #define PCIE_APP_HOLD_PHY_RST		BIT(30)
 #define DEVICE_TYPE_RC			BIT(31)
-#define GLOBAL_PHY_RST			BIT(8)
 
 #define APMU_CLK_GATE_MASK		0x3f
 
@@ -107,8 +106,8 @@  struct k1_pcie_phy {
 	void __iomem *apmu_base;	/* only for combo PHY */
 	u32 pcie_lanes;
 	bool is_combo;
-	struct clk_bulk clks;
-	struct reset_ctl_bulk rst;
+	struct clk refclk;
+	struct reset_ctl phy_rst;
 };
 
 static bool k1_phy_rterm_valid(void)
@@ -155,13 +154,11 @@  int k1_pcie_combo_phy_calibrate(struct udevice *dev, struct k1_pcie_phy *k1_phy)
 
 	/*
 	 * Initialize the APMU control register: set RC mode, enable
-	 * clock gates (bits 0-5), deassert PHY global reset, then
-	 * release the PHY hold.  Without this the PHY registers are
-	 * not accessible and reads will hang.
+	 * clock gates (bits 0-5), then release the PHY hold.  The PHY
+	 * (global) reset was deasserted at probe.
 	 */
 	val = readl(k1_phy->apmu_base + PCIE_CLK_RES_CTRL);
 	val |= DEVICE_TYPE_RC | PCIE_APP_HOLD_PHY_RST | APMU_CLK_GATE_MASK;
-	val &= ~GLOBAL_PHY_RST;
 	writel(val, k1_phy->apmu_base + PCIE_CLK_RES_CTRL);
 	val &= ~PCIE_APP_HOLD_PHY_RST;
 	writel(val, k1_phy->apmu_base + PCIE_CLK_RES_CTRL);
@@ -384,6 +381,48 @@  static const struct phy_ops k1_pcie_phy_ops = {
 	.exit		= k1_pcie_phy_exit,
 };
 
+/*
+ * Enable the 24 MHz reference clock that feeds the PHY PLL, and
+ * deassert the PHY (global) reset, leaving it deasserted.  This must
+ * happen before any PHY register is accessed.
+ */
+static int k1_pcie_phy_enable_resources(struct udevice *dev,
+					struct k1_pcie_phy *k1_phy)
+{
+	int ret;
+
+	ret = clk_get_by_name(dev, "refclk", &k1_phy->refclk);
+	if (ret) {
+		dev_err(dev, "failed to get refclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_enable(&k1_phy->refclk);
+	if (ret) {
+		dev_err(dev, "failed to enable refclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = reset_get_by_name(dev, "phy", &k1_phy->phy_rst);
+	if (ret) {
+		dev_err(dev, "failed to get phy reset: %d\n", ret);
+		goto err_clk;
+	}
+
+	ret = reset_deassert(&k1_phy->phy_rst);
+	if (ret) {
+		dev_err(dev, "failed to deassert phy reset: %d\n", ret);
+		goto err_clk;
+	}
+
+	return 0;
+
+err_clk:
+	clk_disable(&k1_phy->refclk);
+
+	return ret;
+}
+
 static int k1_pcie_phy_probe(struct udevice *dev)
 {
 	struct k1_pcie_phy *k1_phy = dev_get_priv(dev);
@@ -425,13 +464,9 @@  static int k1_pcie_phy_probe(struct udevice *dev)
 		if (!k1_phy->apmu_base)
 			return -EINVAL;
 
-		ret = clk_get_bulk(dev, &k1_phy->clks);
-		if (ret)
-			dev_warn(dev, "failed to get clocks: %d\n", ret);
-
-		ret = reset_get_bulk(dev, &k1_phy->rst);
+		ret = k1_pcie_phy_enable_resources(dev, k1_phy);
 		if (ret)
-			dev_warn(dev, "failed to get resets: %d\n", ret);
+			return ret;
 
 		ret = k1_pcie_combo_phy_calibrate(dev, k1_phy);
 		if (ret)
@@ -461,13 +496,9 @@  static int k1_pcie_phy_probe(struct udevice *dev)
 			return -ENOENT;
 		}
 
-		ret = clk_get_bulk(dev, &k1_phy->clks);
+		ret = k1_pcie_phy_enable_resources(dev, k1_phy);
 		if (ret)
-			dev_warn(dev, "failed to get clocks: %d\n", ret);
-
-		ret = reset_get_bulk(dev, &k1_phy->rst);
-		if (ret)
-			dev_warn(dev, "failed to get resets: %d\n", ret);
+			return ret;
 	}
 
 	dev_dbg(dev, "probed (combo=%d lanes=%u rterm=0x%02x)\n",