The SJA1105 'PMA' code is actually PCS code to adapt to a custom PMA as present in NXP SJA1105, that wants opposite differential lane polarity in the TX direction, to account for an internal quirk. We should write to the DW_VR_MII_DIG_CTRL2 PCS register from PCS code, especially since the XPCS is about to gain more freeform support to alter the lane polarity in the RX and TX directions. The compat->pma_config() interface is kept for SJA1110, but is now wrapped around a xpcs_pma_config() that handles SJA1105 as a quirk implemented in common code. Signed-off-by: Vladimir Oltean --- drivers/net/pcs/pcs-xpcs-nxp.c | 11 ---------- drivers/net/pcs/pcs-xpcs.c | 37 ++++++++++++++++++++++++++-------- drivers/net/pcs/pcs-xpcs.h | 2 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs-nxp.c b/drivers/net/pcs/pcs-xpcs-nxp.c index e8efe94cf4ec..37708b28a7aa 100644 --- a/drivers/net/pcs/pcs-xpcs-nxp.c +++ b/drivers/net/pcs/pcs-xpcs-nxp.c @@ -64,17 +64,6 @@ /* RX_CDR_CTLE register */ #define SJA1110_RX_CDR_CTLE 0x8042 -/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane - * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain - * normal non-inverted behavior, the TX lane polarity must be inverted in the - * PCS, via the DIGITAL_CONTROL_2 register. - */ -int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs) -{ - return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2, - DW_VR_MII_DIG_CTRL2_TX_POL_INV); -} - static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs, u16 txpll_fbdiv, u16 txpll_refdiv, u16 rxpll_fbdiv, u16 rxpll_refdiv, diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 3d1bd5aac093..670441186cc6 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -808,6 +808,26 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs) BMCR_SPEED1000); } +static int xpcs_pma_config(struct dw_xpcs *xpcs, const struct dw_xpcs_compat *compat) +{ + int ret; + + if (xpcs->need_opposite_tx_polarity) { + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2, + DW_VR_MII_DIG_CTRL2_TX_POL_INV); + if (ret) + return ret; + } + + if (compat->pma_config) { + ret = compat->pma_config(xpcs); + if (ret) + return ret; + } + + return 0; +} + static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, const unsigned long *advertising, unsigned int neg_mode) @@ -859,13 +879,7 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, return -EINVAL; } - if (compat->pma_config) { - ret = compat->pma_config(xpcs); - if (ret) - return ret; - } - - return 0; + return xpcs_pma_config(xpcs, compat); } static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, @@ -1341,7 +1355,6 @@ static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = { .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, .an_mode = DW_AN_C37_SGMII, - .pma_config = nxp_sja1105_sgmii_pma_config, }, { } }; @@ -1500,6 +1513,14 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev) else xpcs->need_reset = true; + /* In NXP SJA1105, the PCS is integrated with a PMA that has the TX + * lane polarity inverted by default (PLUS is MINUS, MINUS is PLUS). + * To obtain normal non-inverted behavior, the TX lane polarity must be + * inverted in the PCS, via the DIGITAL_CONTROL_2 register. + */ + if (xpcs->desc->compat == nxp_sja1105_xpcs_compat) + xpcs->need_opposite_tx_polarity = true; + return xpcs; out_clear_clks: diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h index 929fa238445e..2a92e101da1b 100644 --- a/drivers/net/pcs/pcs-xpcs.h +++ b/drivers/net/pcs/pcs-xpcs.h @@ -113,6 +113,7 @@ struct dw_xpcs { struct phylink_pcs pcs; phy_interface_t interface; bool need_reset; + bool need_opposite_tx_polarity; u8 eee_mult_fact; }; @@ -121,7 +122,6 @@ int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val); int xpcs_modify(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set); int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg); int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val); -int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs); int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface); -- 2.34.1