diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig index ecbc3530e780..e417fd66f660 100644 --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig @@ -20,6 +20,7 @@ config PCS_LYNX config PCS_MTK_LYNXI tristate + select PHY_COMMON_PROPS select REGMAP help This module provides helpers to phylink for managing the LynxI PCS diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 7f719da5812e..74dbce205f71 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -62,8 +63,9 @@ /* Register to QPHY wrapper control */ #define SGMSYS_QPHY_WRAP_CTRL 0xec -#define SGMII_PN_SWAP_MASK GENMASK(1, 0) -#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) +#define SGMII_PN_SWAP_RX BIT(1) +#define SGMII_PN_SWAP_TX BIT(0) + /* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated * data @@ -121,6 +123,42 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, FIELD_GET(SGMII_LPA, adv)); } +static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs, + phy_interface_t interface) +{ + struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode; + unsigned int pol, default_pol = PHY_POL_NORMAL; + unsigned int val = 0; + int ret; + + if (fwnode_property_read_bool(fwnode, "mediatek,pnswap")) + default_pol = PHY_POL_INVERT; + + pcs_fwnode = fwnode_get_named_child_node(fwnode, "pcs"); + + ret = phy_get_rx_polarity(pcs_fwnode, phy_modes(interface), + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + default_pol, &pol); + if (ret) { + fwnode_handle_put(pcs_fwnode); + return ret; + } + if (pol == PHY_POL_INVERT) + val |= SGMII_PN_SWAP_RX; + + ret = phy_get_tx_polarity(pcs_fwnode, phy_modes(interface), + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + default_pol, &pol); + fwnode_handle_put(pcs_fwnode); + if (ret) + return ret; + if (pol == PHY_POL_INVERT) + val |= SGMII_PN_SWAP_TX; + + return regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, + SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX, val); +} + static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, @@ -130,6 +168,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, bool mode_changed = false, changed; unsigned int rgc3, sgm_mode, bmcr; int advertise, link_timer; + int ret; advertise = phylink_mii_c22_pcs_encode_advertisement(interface, advertising); @@ -169,10 +208,9 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0, SGMII_SW_RESET); - if (fwnode_property_read_bool(mpcs->fwnode, "mediatek,pnswap")) - regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, - SGMII_PN_SWAP_MASK, - SGMII_PN_SWAP_TX_RX); + ret = mtk_pcs_config_polarity(mpcs, interface); + if (ret) + return ret; if (interface == PHY_INTERFACE_MODE_2500BASEX) rgc3 = SGMII_PHY_SPEED_3_125G;