To start the PHY PLL, init writes 0xb78 over the whole of
PCIE_PU_ADDR_CLK_CFG, and CFG_FORCE_RCV_RETRY over the whole of
PCIE_RC_DONE_STATUS, clearing every other field of both. 0xb78 is
CFG_SW_PHY_INIT_DONE, CFG_INTERNAL_TIMER_ADJ = 6 (PCIe) and four
undocumented low bits. The lane 1 register is written even when the
PHY has only one lane, as the combo PHY always does.

Linux's PLL prepare sets CFG_INTERNAL_TIMER_ADJ to TIMER_ADJ_PCIE on
each lane in use, sets CFG_FORCE_RCV_RETRY, clears REF_100_WSSC along
with selecting the 24 MHz reference in PCIE_PU_PLL_1, and only then
sets CFG_SW_PHY_INIT_DONE on each lane to start the PLL, all with
read-modify-write. Do the same here, using the existing named fields
instead of the magic value.

Signed-off-by: Dave Klotz <[email protected]>
---
 drivers/phy/spacemit/phy-k1-pcie.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/phy/spacemit/phy-k1-pcie.c 
b/drivers/phy/spacemit/phy-k1-pcie.c
index 0e18f29024..c3d29d6a2a 100644
--- a/drivers/phy/spacemit/phy-k1-pcie.c
+++ b/drivers/phy/spacemit/phy-k1-pcie.c
@@ -311,9 +311,9 @@ static int k1_pcie_phy_init(struct phy *phy)
        val |= FIELD_PREP(CFG_REFCLK_MODE, RFCLK_MODE_DRIVER);
        writel(val, regs + PHY_LANE_OFFSET + PCIE_LTSSM_DIS_ENTRY);
 
-       /* Configure PLL: select 24MHz reference */
+       /* Configure PLL: select 24MHz reference, no 100MHz SSC input */
        val = readl(regs + PCIE_PU_PLL_1);
-       val &= ~FREF_SEL;
+       val &= ~(FREF_SEL | REF_100_WSSC);
        writel(val, regs + PCIE_PU_PLL_1);
 
        val = readl(regs + PCIE_PU_PLL_1);
@@ -330,15 +330,26 @@ static int k1_pcie_phy_init(struct phy *phy)
        val &= ~SSC_DEP_SEL;
        writel(val, regs + PCIE_PU_PLL_1);
 
-       /* Set PU_ADDR_CLK_CFG for both lanes */
-       val = 0x00000B78;
-       writel(val, regs + PCIE_PU_ADDR_CLK_CFG);
-       writel(val, regs + PHY_LANE_OFFSET + PCIE_PU_ADDR_CLK_CFG);
+       /* Set the PCIe internal timer adjustment for all lanes */
+       for (i = 0; i < lane; i++) {
+               val = readl(regs + PCIE_PU_ADDR_CLK_CFG + PHY_LANE_OFFSET * i);
+               val &= ~CFG_INTERNAL_TIMER_ADJ;
+               val |= FIELD_PREP(CFG_INTERNAL_TIMER_ADJ, TIMER_ADJ_PCIE);
+               writel(val, regs + PCIE_PU_ADDR_CLK_CFG + PHY_LANE_OFFSET * i);
+       }
 
-       /* Force receiver done */
-       val = CFG_FORCE_RCV_RETRY;
+       /* Force receiver retry */
+       val = readl(regs + PCIE_RC_DONE_STATUS);
+       val |= CFG_FORCE_RCV_RETRY;
        writel(val, regs + PCIE_RC_DONE_STATUS);
 
+       /* PLL configuration is done; start the PLL on all lanes */
+       for (i = 0; i < lane; i++) {
+               val = readl(regs + PCIE_PU_ADDR_CLK_CFG + PHY_LANE_OFFSET * i);
+               val |= CFG_SW_PHY_INIT_DONE;
+               writel(val, regs + PCIE_PU_ADDR_CLK_CFG + PHY_LANE_OFFSET * i);
+       }
+
        /* Wait for PLL lock */
        ret = readl_poll_timeout(regs + PCIE_PU_ADDR_CLK_CFG, val,
                                 val & PLL_READY, PLL_TIMEOUT_US);
-- 
2.55.0


Reply via email to