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
