net: mvpp2: use resolved link config in mac_link_up()
[linux-2.6-microblaze.git] / drivers / net / ethernet / marvell / mvpp2 / mvpp2_main.c
index 72133cb..6b9c7ed 100644 (file)
@@ -58,8 +58,11 @@ static struct {
  */
 static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
                             const struct phylink_link_state *state);
-static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
-                             phy_interface_t interface, struct phy_device *phy);
+static void mvpp2_mac_link_up(struct phylink_config *config,
+                             struct phy_device *phy,
+                             unsigned int mode, phy_interface_t interface,
+                             int speed, int duplex,
+                             bool tx_pause, bool rx_pause);
 
 /* Queue modes */
 #define MVPP2_QDIST_SINGLE_MODE        0
@@ -3473,8 +3476,9 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
                        .interface = port->phy_interface,
                };
                mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
-               mvpp2_mac_link_up(&port->phylink_config, MLO_AN_INBAND,
-                                 port->phy_interface, NULL);
+               mvpp2_mac_link_up(&port->phylink_config, NULL,
+                                 MLO_AN_INBAND, port->phy_interface,
+                                 SPEED_UNKNOWN, DUPLEX_UNKNOWN, false, false);
        }
 
        netif_tx_start_all_queues(port->dev);
@@ -4972,15 +4976,13 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
        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_CONFIG_MII_SPEED | MVPP2_GMAC_CONFIG_GMII_SPEED |
-               MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FC_ADV_EN |
+       an &= ~(MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FC_ADV_EN |
                MVPP2_GMAC_FC_ADV_ASM_EN | MVPP2_GMAC_FLOW_CTRL_AUTONEG |
-               MVPP2_GMAC_CONFIG_FULL_DUPLEX | MVPP2_GMAC_AN_DUPLEX_EN |
-               MVPP2_GMAC_IN_BAND_AUTONEG | MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS);
+               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_PORT_RESET_MASK |
                   MVPP2_GMAC_PCS_ENABLE_MASK);
-       ctrl4 &= ~(MVPP22_CTRL4_RX_FC_EN | MVPP22_CTRL4_TX_FC_EN);
 
        /* Configure port type */
        if (phy_interface_mode_is_8023z(state->interface)) {
@@ -5010,31 +5012,20 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
 
        /* Configure negotiation style */
        if (!phylink_autoneg_inband(mode)) {
-               /* Phy or fixed speed - no in-band AN */
-               if (state->duplex)
-                       an |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
-
-               if (state->speed == SPEED_1000 || state->speed == SPEED_2500)
-                       an |= MVPP2_GMAC_CONFIG_GMII_SPEED;
-               else if (state->speed == SPEED_100)
-                       an |= MVPP2_GMAC_CONFIG_MII_SPEED;
-
-               if (state->pause & MLO_PAUSE_TX)
-                       ctrl4 |= MVPP22_CTRL4_TX_FC_EN;
-               if (state->pause & MLO_PAUSE_RX)
-                       ctrl4 |= MVPP22_CTRL4_RX_FC_EN;
+               /* Phy or fixed speed - no in-band AN, nothing to do, leave the
+                * configured speed, duplex and flow control as-is.
+                */
        } 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_FORCE_LINK_DOWN | MVPP2_GMAC_FORCE_LINK_PASS);
+               an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN |
+                       MVPP2_GMAC_FORCE_LINK_PASS |
+                       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;
-
-               if (state->pause & MLO_PAUSE_TX)
-                       ctrl4 |= MVPP22_CTRL4_TX_FC_EN;
-               if (state->pause & MLO_PAUSE_RX)
-                       ctrl4 |= MVPP22_CTRL4_RX_FC_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
@@ -5042,19 +5033,17 @@ 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_FORCE_LINK_DOWN | MVPP2_GMAC_FORCE_LINK_PASS);
+               an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN |
+                       MVPP2_GMAC_FORCE_LINK_PASS |
+                       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) {
+               if (state->pause & MLO_PAUSE_AN && state->an_enabled)
                        an |= MVPP2_GMAC_FLOW_CTRL_AUTONEG;
-               } else {
-                       if (state->pause & MLO_PAUSE_TX)
-                               ctrl4 |= MVPP22_CTRL4_TX_FC_EN;
-                       if (state->pause & MLO_PAUSE_RX)
-                               ctrl4 |= MVPP22_CTRL4_RX_FC_EN;
-               }
        }
 
 /* Some fields of the auto-negotiation register require the port to be down when
@@ -5141,25 +5130,54 @@ static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
        mvpp2_port_enable(port);
 }
 
-static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
-                             phy_interface_t interface, struct phy_device *phy)
+static void mvpp2_mac_link_up(struct phylink_config *config,
+                             struct phy_device *phy,
+                             unsigned int mode, phy_interface_t interface,
+                             int speed, int duplex,
+                             bool tx_pause, bool rx_pause)
 {
        struct net_device *dev = to_net_dev(config->dev);
        struct mvpp2_port *port = netdev_priv(dev);
        u32 val;
 
-       if (!phylink_autoneg_inband(mode)) {
-               if (mvpp2_is_xlg(interface)) {
+       if (mvpp2_is_xlg(interface)) {
+               if (!phylink_autoneg_inband(mode)) {
                        val = readl(port->base + MVPP22_XLG_CTRL0_REG);
                        val &= ~MVPP22_XLG_CTRL0_FORCE_LINK_DOWN;
                        val |= MVPP22_XLG_CTRL0_FORCE_LINK_PASS;
                        writel(val, port->base + MVPP22_XLG_CTRL0_REG);
-               } else {
+               }
+       } else {
+               if (!phylink_autoneg_inband(mode)) {
                        val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
-                       val &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
+                       val &= ~(MVPP2_GMAC_FORCE_LINK_DOWN |
+                                MVPP2_GMAC_CONFIG_MII_SPEED |
+                                MVPP2_GMAC_CONFIG_GMII_SPEED |
+                                MVPP2_GMAC_CONFIG_FULL_DUPLEX);
                        val |= MVPP2_GMAC_FORCE_LINK_PASS;
+
+                       if (speed == SPEED_1000 || speed == SPEED_2500)
+                               val |= MVPP2_GMAC_CONFIG_GMII_SPEED;
+                       else if (speed == SPEED_100)
+                               val |= MVPP2_GMAC_CONFIG_MII_SPEED;
+
+                       if (duplex == DUPLEX_FULL)
+                               val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
+
                        writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
                }
+
+               /* We can always update the flow control enable bits;
+                * these will only be effective if flow control AN
+                * (MVPP2_GMAC_FLOW_CTRL_AUTONEG) is disabled.
+                */
+               val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
+               val &= ~(MVPP22_CTRL4_RX_FC_EN | MVPP22_CTRL4_TX_FC_EN);
+               if (tx_pause)
+                       val |= MVPP22_CTRL4_TX_FC_EN;
+               if (rx_pause)
+                       val |= MVPP22_CTRL4_RX_FC_EN;
+               writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
        }
 
        mvpp2_port_enable(port);