net: mvpp2: convert to phylink pcs operations
authorRussell King <rmk+kernel@armlinux.org.uk>
Tue, 1 Sep 2020 13:48:32 +0000 (14:48 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Sep 2020 21:52:33 +0000 (14:52 -0700)
Convert mvpp2 to phylink's new pcs support.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/mvpp2/mvpp2.h
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c

index 32753cc..ecb5f46 100644 (file)
@@ -967,6 +967,7 @@ struct mvpp2_port {
        phy_interface_t phy_interface;
        struct phylink *phylink;
        struct phylink_config phylink_config;
+       struct phylink_pcs phylink_pcs;
        struct phy *comphy;
 
        struct mvpp2_bm_pool *pool_long;
index 58df720..6d3d84d 100644 (file)
@@ -1479,8 +1479,8 @@ static void mvpp2_port_loopback_set(struct mvpp2_port *port,
        else
                val &= ~MVPP2_GMAC_GMII_LB_EN_MASK;
 
-       if (phy_interface_mode_is_8023z(port->phy_interface) ||
-           port->phy_interface == PHY_INTERFACE_MODE_SGMII)
+       if (phy_interface_mode_is_8023z(state->interface) ||
+           state->interface == PHY_INTERFACE_MODE_SGMII)
                val |= MVPP2_GMAC_PCS_LB_EN_MASK;
        else
                val &= ~MVPP2_GMAC_PCS_LB_EN_MASK;
@@ -5376,6 +5376,174 @@ static struct mvpp2_port *mvpp2_phylink_to_port(struct phylink_config *config)
        return container_of(config, struct mvpp2_port, phylink_config);
 }
 
+static struct mvpp2_port *mvpp2_pcs_to_port(struct phylink_pcs *pcs)
+{
+       return container_of(pcs, struct mvpp2_port, phylink_pcs);
+}
+
+static void mvpp22_xlg_pcs_get_state(struct mvpp2_port *port,
+                                    struct phylink_link_state *state)
+{
+       u32 val;
+
+       state->speed = SPEED_10000;
+       state->duplex = 1;
+       state->an_complete = 1;
+
+       val = readl(port->base + MVPP22_XLG_STATUS);
+       state->link = !!(val & MVPP22_XLG_STATUS_LINK_UP);
+
+       state->pause = 0;
+       val = readl(port->base + MVPP22_XLG_CTRL0_REG);
+       if (val & MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN)
+               state->pause |= MLO_PAUSE_TX;
+       if (val & MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN)
+               state->pause |= MLO_PAUSE_RX;
+}
+
+static void mvpp2_gmac_pcs_get_state(struct mvpp2_port *port,
+                                    struct phylink_link_state *state)
+{
+       u32 val;
+
+       val = readl(port->base + MVPP2_GMAC_STATUS0);
+
+       state->an_complete = !!(val & MVPP2_GMAC_STATUS0_AN_COMPLETE);
+       state->link = !!(val & MVPP2_GMAC_STATUS0_LINK_UP);
+       state->duplex = !!(val & MVPP2_GMAC_STATUS0_FULL_DUPLEX);
+
+       switch (port->phy_interface) {
+       case PHY_INTERFACE_MODE_1000BASEX:
+               state->speed = SPEED_1000;
+               break;
+       case PHY_INTERFACE_MODE_2500BASEX:
+               state->speed = SPEED_2500;
+               break;
+       default:
+               if (val & MVPP2_GMAC_STATUS0_GMII_SPEED)
+                       state->speed = SPEED_1000;
+               else if (val & MVPP2_GMAC_STATUS0_MII_SPEED)
+                       state->speed = SPEED_100;
+               else
+                       state->speed = SPEED_10;
+       }
+
+       state->pause = 0;
+       if (val & MVPP2_GMAC_STATUS0_RX_PAUSE)
+               state->pause |= MLO_PAUSE_RX;
+       if (val & MVPP2_GMAC_STATUS0_TX_PAUSE)
+               state->pause |= MLO_PAUSE_TX;
+}
+
+static void mvpp2_phylink_pcs_get_state(struct phylink_pcs *pcs,
+                                       struct phylink_link_state *state)
+{
+       struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
+
+       if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
+               u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
+               mode &= MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+
+               if (mode == MVPP22_XLG_CTRL3_MACMODESELECT_10G) {
+                       mvpp22_xlg_pcs_get_state(port, state);
+                       return;
+               }
+       }
+
+       mvpp2_gmac_pcs_get_state(port, state);
+}
+
+static int mvpp2_gmac_pcs_config(struct mvpp2_port *port, unsigned int mode,
+                                phy_interface_t interface,
+                                const unsigned long *advertising,
+                                bool permit_pause_to_mac)
+{
+       u32 mask, val, an, old_an, changed;
+
+       mask = MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS |
+              MVPP2_GMAC_IN_BAND_AUTONEG |
+              MVPP2_GMAC_AN_SPEED_EN |
+              MVPP2_GMAC_FLOW_CTRL_AUTONEG |
+              MVPP2_GMAC_AN_DUPLEX_EN;
+
+       if (phylink_autoneg_inband(mode)) {
+               mask |= MVPP2_GMAC_CONFIG_MII_SPEED |
+                       MVPP2_GMAC_CONFIG_GMII_SPEED |
+                       MVPP2_GMAC_CONFIG_FULL_DUPLEX;
+               val = MVPP2_GMAC_IN_BAND_AUTONEG;
+
+               if (interface == PHY_INTERFACE_MODE_SGMII) {
+                       /* SGMII mode receives the speed and duplex from PHY */
+                       val |= MVPP2_GMAC_AN_SPEED_EN |
+                              MVPP2_GMAC_AN_DUPLEX_EN;
+               } else {
+                       /* 802.3z mode has fixed speed and duplex */
+                       val |= MVPP2_GMAC_CONFIG_GMII_SPEED |
+                              MVPP2_GMAC_CONFIG_FULL_DUPLEX;
+
+                       /* The FLOW_CTRL_AUTONEG bit selects either the hardware
+                        * automatically or the bits in MVPP22_GMAC_CTRL_4_REG
+                        * manually controls the GMAC pause modes.
+                        */
+                       if (permit_pause_to_mac)
+                               val |= MVPP2_GMAC_FLOW_CTRL_AUTONEG;
+
+                       /* Configure advertisement bits */
+                       mask |= MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN;
+                       if (phylink_test(advertising, Pause))
+                               val |= MVPP2_GMAC_FC_ADV_EN;
+                       if (phylink_test(advertising, Asym_Pause))
+                               val |= MVPP2_GMAC_FC_ADV_ASM_EN;
+               }
+       } else {
+               val = 0;
+       }
+
+       old_an = an = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+       an = (an & ~mask) | val;
+       changed = an ^ old_an;
+       if (changed)
+               writel(an, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+
+       /* We are only interested in the advertisement bits changing */
+       return changed & (MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN);
+}
+
+static int mvpp2_phylink_pcs_config(struct phylink_pcs *pcs,
+                                   unsigned int mode,
+                                   phy_interface_t interface,
+                                   const unsigned long *advertising,
+                                   bool permit_pause_to_mac)
+{
+       struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
+       int ret;
+
+       if (mvpp2_is_xlg(interface))
+               ret = 0;
+       else
+               ret = mvpp2_gmac_pcs_config(port, mode, interface, advertising,
+                                           permit_pause_to_mac);
+
+       return ret;
+}
+
+static void mvpp2_phylink_pcs_an_restart(struct phylink_pcs *pcs)
+{
+       struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
+       u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+
+       writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
+              port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+       writel(val & ~MVPP2_GMAC_IN_BAND_RESTART_AN,
+              port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+}
+
+static const struct phylink_pcs_ops mvpp2_phylink_pcs_ops = {
+       .pcs_get_state = mvpp2_phylink_pcs_get_state,
+       .pcs_config = mvpp2_phylink_pcs_config,
+       .pcs_an_restart = mvpp2_phylink_pcs_an_restart,
+};
+
 static void mvpp2_phylink_validate(struct phylink_config *config,
                                   unsigned long *supported,
                                   struct phylink_link_state *state)
@@ -5464,89 +5632,6 @@ empty_set:
        bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
 }
 
-static void mvpp22_xlg_pcs_get_state(struct mvpp2_port *port,
-                                    struct phylink_link_state *state)
-{
-       u32 val;
-
-       state->speed = SPEED_10000;
-       state->duplex = 1;
-       state->an_complete = 1;
-
-       val = readl(port->base + MVPP22_XLG_STATUS);
-       state->link = !!(val & MVPP22_XLG_STATUS_LINK_UP);
-
-       state->pause = 0;
-       val = readl(port->base + MVPP22_XLG_CTRL0_REG);
-       if (val & MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN)
-               state->pause |= MLO_PAUSE_TX;
-       if (val & MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN)
-               state->pause |= MLO_PAUSE_RX;
-}
-
-static void mvpp2_gmac_pcs_get_state(struct mvpp2_port *port,
-                                    struct phylink_link_state *state)
-{
-       u32 val;
-
-       val = readl(port->base + MVPP2_GMAC_STATUS0);
-
-       state->an_complete = !!(val & MVPP2_GMAC_STATUS0_AN_COMPLETE);
-       state->link = !!(val & MVPP2_GMAC_STATUS0_LINK_UP);
-       state->duplex = !!(val & MVPP2_GMAC_STATUS0_FULL_DUPLEX);
-
-       switch (port->phy_interface) {
-       case PHY_INTERFACE_MODE_1000BASEX:
-               state->speed = SPEED_1000;
-               break;
-       case PHY_INTERFACE_MODE_2500BASEX:
-               state->speed = SPEED_2500;
-               break;
-       default:
-               if (val & MVPP2_GMAC_STATUS0_GMII_SPEED)
-                       state->speed = SPEED_1000;
-               else if (val & MVPP2_GMAC_STATUS0_MII_SPEED)
-                       state->speed = SPEED_100;
-               else
-                       state->speed = SPEED_10;
-       }
-
-       state->pause = 0;
-       if (val & MVPP2_GMAC_STATUS0_RX_PAUSE)
-               state->pause |= MLO_PAUSE_RX;
-       if (val & MVPP2_GMAC_STATUS0_TX_PAUSE)
-               state->pause |= MLO_PAUSE_TX;
-}
-
-static void mvpp2_phylink_mac_pcs_get_state(struct phylink_config *config,
-                                           struct phylink_link_state *state)
-{
-       struct mvpp2_port *port = mvpp2_phylink_to_port(config);
-
-       if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
-               u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
-               mode &= MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
-
-               if (mode == MVPP22_XLG_CTRL3_MACMODESELECT_10G) {
-                       mvpp22_xlg_pcs_get_state(port, state);
-                       return;
-               }
-       }
-
-       mvpp2_gmac_pcs_get_state(port, state);
-}
-
-static void mvpp2_mac_an_restart(struct phylink_config *config)
-{
-       struct mvpp2_port *port = mvpp2_phylink_to_port(config);
-       u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
-
-       writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
-              port->base + MVPP2_GMAC_AUTONEG_CONFIG);
-       writel(val & ~MVPP2_GMAC_IN_BAND_RESTART_AN,
-              port->base + MVPP2_GMAC_AUTONEG_CONFIG);
-}
-
 static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode,
                             const struct phylink_link_state *state)
 {
@@ -5570,20 +5655,14 @@ static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode,
 static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
                              const struct phylink_link_state *state)
 {
-       u32 old_an, an;
        u32 old_ctrl0, ctrl0;
        u32 old_ctrl2, ctrl2;
        u32 old_ctrl4, ctrl4;
 
-       old_an = an = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
        old_ctrl0 = ctrl0 = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
        old_ctrl2 = ctrl2 = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
        old_ctrl4 = ctrl4 = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
 
-       an &= ~(MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FC_ADV_EN |
-               MVPP2_GMAC_FC_ADV_ASM_EN | MVPP2_GMAC_FLOW_CTRL_AUTONEG |
-               MVPP2_GMAC_AN_DUPLEX_EN | MVPP2_GMAC_IN_BAND_AUTONEG |
-               MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS);
        ctrl0 &= ~MVPP2_GMAC_PORT_TYPE_MASK;
        ctrl2 &= ~(MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PCS_ENABLE_MASK);
 
@@ -5607,12 +5686,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
                         MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
        }
 
-       /* Configure advertisement bits */
-       if (phylink_test(state->advertising, Pause))
-               an |= MVPP2_GMAC_FC_ADV_EN;
-       if (phylink_test(state->advertising, Asym_Pause))
-               an |= MVPP2_GMAC_FC_ADV_ASM_EN;
-
        /* Configure negotiation style */
        if (!phylink_autoneg_inband(mode)) {
                /* Phy or fixed speed - no in-band AN, nothing to do, leave the
@@ -5621,12 +5694,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
        } else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
                /* SGMII in-band mode receives the speed and duplex from
                 * the PHY. Flow control information is not received. */
-               an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
-                       MVPP2_GMAC_CONFIG_GMII_SPEED |
-                       MVPP2_GMAC_CONFIG_FULL_DUPLEX);
-               an |= MVPP2_GMAC_IN_BAND_AUTONEG |
-                     MVPP2_GMAC_AN_SPEED_EN |
-                     MVPP2_GMAC_AN_DUPLEX_EN;
        } else if (phy_interface_mode_is_8023z(state->interface)) {
                /* 1000BaseX and 2500BaseX ports cannot negotiate speed nor can
                 * they negotiate duplex: they are always operating with a fixed
@@ -5634,15 +5701,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
                 * speed and full duplex here.
                 */
                ctrl0 |= MVPP2_GMAC_PORT_TYPE_MASK;
-               an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
-                       MVPP2_GMAC_CONFIG_GMII_SPEED |
-                       MVPP2_GMAC_CONFIG_FULL_DUPLEX);
-               an |= MVPP2_GMAC_IN_BAND_AUTONEG |
-                     MVPP2_GMAC_CONFIG_GMII_SPEED |
-                     MVPP2_GMAC_CONFIG_FULL_DUPLEX;
-
-               if (state->pause & MLO_PAUSE_AN && state->an_enabled)
-                       an |= MVPP2_GMAC_FLOW_CTRL_AUTONEG;
        }
 
        if (old_ctrl0 != ctrl0)
@@ -5651,8 +5709,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
                writel(ctrl2, port->base + MVPP2_GMAC_CTRL_2_REG);
        if (old_ctrl4 != ctrl4)
                writel(ctrl4, port->base + MVPP22_GMAC_CTRL_4_REG);
-       if (old_an != an)
-               writel(an, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
 }
 
 static int mvpp2_mac_prepare(struct phylink_config *config, unsigned int mode,
@@ -5861,8 +5917,6 @@ static void mvpp2_mac_link_down(struct phylink_config *config,
 
 static const struct phylink_mac_ops mvpp2_phylink_ops = {
        .validate = mvpp2_phylink_validate,
-       .mac_pcs_get_state = mvpp2_phylink_mac_pcs_get_state,
-       .mac_an_restart = mvpp2_mac_an_restart,
        .mac_prepare = mvpp2_mac_prepare,
        .mac_config = mvpp2_mac_config,
        .mac_finish = mvpp2_mac_finish,
@@ -5883,6 +5937,9 @@ static void mvpp2_acpi_start(struct mvpp2_port *port)
        mvpp2_mac_prepare(&port->phylink_config, MLO_AN_INBAND,
                          port->phy_interface);
        mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
+       mvpp2_phylink_pcs_config(&port->phylink_pcs, MLO_AN_INBAND,
+                                port->phy_interface, state.advertising,
+                                false);
        mvpp2_mac_finish(&port->phylink_config, MLO_AN_INBAND,
                         port->phy_interface);
        mvpp2_mac_link_up(&port->phylink_config, NULL,
@@ -6114,6 +6171,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
                        goto err_free_port_pcpu;
                }
                port->phylink = phylink;
+
+               port->phylink_pcs.ops = &mvpp2_phylink_pcs_ops;
+               phylink_set_pcs(phylink, &port->phylink_pcs);
        } else {
                port->phylink = NULL;
        }