diff options
Diffstat (limited to 'drivers/net/pcs/pcs-mtk-lynxi.c')
| -rw-r--r-- | drivers/net/pcs/pcs-mtk-lynxi.c | 72 |
1 files changed, 48 insertions, 24 deletions
diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 888452325edc..149ddf51d785 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -88,7 +88,24 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) return container_of(pcs, struct mtk_pcs_lynxi, pcs); } +static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_SGMII: + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + case PHY_INTERFACE_MODE_2500BASEX: + return LINK_INBAND_DISABLE; + + default: + return 0; + } +} + static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, + unsigned int neg_mode, struct phylink_link_state *state) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); @@ -98,17 +115,18 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); - phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), + phylink_mii_c22_pcs_decode_state(state, neg_mode, + FIELD_GET(SGMII_BMSR, bm), FIELD_GET(SGMII_LPA, adv)); } -static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, +static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); - bool mode_changed = false, changed, use_an; + bool mode_changed = false, changed; unsigned int rgc3, sgm_mode, bmcr; int advertise, link_timer; @@ -121,30 +139,21 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, * we assume that fixes it's speed at bitrate = line rate (in * other words, 1000Mbps or 2500Mbps). */ - if (interface == PHY_INTERFACE_MODE_SGMII) { + if (interface == PHY_INTERFACE_MODE_SGMII) sgm_mode = SGMII_IF_MODE_SGMII; - if (phylink_autoneg_inband(mode)) { - sgm_mode |= SGMII_REMOTE_FAULT_DIS | - SGMII_SPEED_DUPLEX_AN; - use_an = true; - } else { - use_an = false; - } - } else if (phylink_autoneg_inband(mode)) { - /* 1000base-X or 2500base-X autoneg */ - sgm_mode = SGMII_REMOTE_FAULT_DIS; - use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - advertising); - } else { - /* 1000base-X or 2500base-X without autoneg */ + else sgm_mode = 0; - use_an = false; - } - if (use_an) + if (neg_mode & PHYLINK_PCS_NEG_INBAND) + sgm_mode |= SGMII_REMOTE_FAULT_DIS; + + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + if (interface == PHY_INTERFACE_MODE_SGMII) + sgm_mode |= SGMII_SPEED_DUPLEX_AN; bmcr = BMCR_ANENABLE; - else + } else { bmcr = 0; + } if (mpcs->interface != interface) { link_timer = phylink_get_link_timer_ns(interface); @@ -216,14 +225,15 @@ static void mtk_pcs_lynxi_restart_an(struct phylink_pcs *pcs) regmap_set_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, BMCR_ANRESTART); } -static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, unsigned int mode, +static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, + unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); unsigned int sgm_mode; - if (!phylink_autoneg_inband(mode)) { + if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) { /* Force the speed and duplex setting */ if (speed == SPEED_10) sgm_mode = SGMII_SPEED_10; @@ -241,11 +251,20 @@ static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, unsigned int mode, } } +static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs) +{ + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); + + mpcs->interface = PHY_INTERFACE_MODE_NA; +} + static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { + .pcs_inband_caps = mtk_pcs_lynxi_inband_caps, .pcs_get_state = mtk_pcs_lynxi_get_state, .pcs_config = mtk_pcs_lynxi_config, .pcs_an_restart = mtk_pcs_lynxi_restart_an, .pcs_link_up = mtk_pcs_lynxi_link_up, + .pcs_disable = mtk_pcs_lynxi_disable, }; struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, @@ -289,6 +308,10 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, mpcs->pcs.poll = true; mpcs->interface = PHY_INTERFACE_MODE_NA; + __set_bit(PHY_INTERFACE_MODE_SGMII, mpcs->pcs.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, mpcs->pcs.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, mpcs->pcs.supported_interfaces); + return &mpcs->pcs; } EXPORT_SYMBOL(mtk_pcs_lynxi_create); @@ -302,4 +325,5 @@ void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); +MODULE_DESCRIPTION("MediaTek SGMII library for LynxI"); MODULE_LICENSE("GPL"); |
