@@ -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",
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(-)