CLKSEL in PCIE_RC_CAL_REG2 selects the input clock of the lane's RC
calibration. It is set only on lane 0, so the second lane of ports B
and C keeps its reset value, and it is OR'd in, so a value already in
the field is merged with CLKSEL_24M rather than replaced.

Linux's k1_pcie_phy_init_pcie() sets CLKSEL to 24 MHz on every lane,
before toggling RC_CAL_TOGGLE on that lane. Do the same, clearing the
field before writing it. (Linux masks with "val &= CLKSEL", which also
clears every other field of the register; this keeps the other fields,
as this driver did before.)

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

diff --git a/drivers/phy/spacemit/phy-k1-pcie.c 
b/drivers/phy/spacemit/phy-k1-pcie.c
index ab8349f7d1..0e18f29024 100644
--- a/drivers/phy/spacemit/phy-k1-pcie.c
+++ b/drivers/phy/spacemit/phy-k1-pcie.c
@@ -265,10 +265,13 @@ static int k1_pcie_phy_init(struct phy *phy)
                writel(val, regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
        }
 
-       /* Set CLKSEL_24M on lane0 */
-       val = readl(regs + PCIE_RC_CAL_REG2);
-       val |= FIELD_PREP(CLKSEL, CLKSEL_24M);
-       writel(val, regs + PCIE_RC_CAL_REG2);
+       /* Select the 24 MHz input clock for all lanes */
+       for (i = 0; i < lane; i++) {
+               val = readl(regs + PCIE_RC_CAL_REG2 + PHY_LANE_OFFSET * i);
+               val &= ~CLKSEL;
+               val |= FIELD_PREP(CLKSEL, CLKSEL_24M);
+               writel(val, regs + PCIE_RC_CAL_REG2 + PHY_LANE_OFFSET * i);
+       }
 
        /* Toggle RC_CAL_TOGGLE for all lanes */
        for (i = 0; i < lane; i++) {
-- 
2.55.0


Reply via email to