The RX and TX termination values measured by the combo PHY are OR'd
into AFE_RTERM_REG (PCIE_RX_REG1) and TX_RTERM_REG (PCIE_TX_REG1)
without clearing those fields first, so any bit already set there,
by reset or by an earlier stage, ends up in the result. EN_RTERM,
which enables the refclock receiver termination, is never set.

Linux's k1_pcie_phy_init_pcie() clears each field before writing
the calibrated value and sets EN_RTERM, on every lane. Do the same.

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

diff --git a/drivers/phy/spacemit/phy-k1-pcie.c 
b/drivers/phy/spacemit/phy-k1-pcie.c
index 308f7dec79..ab8349f7d1 100644
--- a/drivers/phy/spacemit/phy-k1-pcie.c
+++ b/drivers/phy/spacemit/phy-k1-pcie.c
@@ -231,10 +231,15 @@ static int k1_pcie_phy_init(struct phy *phy)
 
        lane = (k1_phy->pcie_lanes == 1) ? 1 : 2;
 
-       /* Apply rterm calibration value: LSB to RX_REG1 */
+       /*
+        * Apply rterm calibration value: LSB to RX_REG1, and enable
+        * refclock receiver termination
+        */
        for (i = 0; i < lane; i++) {
                val = readl(regs + PCIE_RX_REG1 + PHY_LANE_OFFSET * i);
+               val &= ~AFE_RTERM_REG;
                val |= FIELD_PREP(AFE_RTERM_REG, k1_phy_rterm_rx());
+               val |= EN_RTERM;
                writel(val, regs + PCIE_RX_REG1 + PHY_LANE_OFFSET * i);
        }
 
@@ -248,6 +253,7 @@ static int k1_pcie_phy_init(struct phy *phy)
        /* Apply rterm MSB to TX_REG1 */
        for (i = 0; i < lane; i++) {
                val = readl(regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
+               val &= ~TX_RTERM_REG;
                val |= FIELD_PREP(TX_RTERM_REG, k1_phy_rterm_tx());
                writel(val, regs + PCIE_TX_REG1 + PHY_LANE_OFFSET * i);
        }
-- 
2.55.0


Reply via email to