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 <[email protected]>
---
 drivers/phy/spacemit/phy-k1-pcie.c | 69 ++++++++++++++++++++++--------
 1 file changed, 50 insertions(+), 19 deletions(-)

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",
-- 
2.55.0


Reply via email to