net: phy: aquantia: add support for auto-negotiation configuration
authorAndrew Lunn <andrew@lunn.ch>
Fri, 22 Feb 2019 22:49:54 +0000 (23:49 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sat, 23 Feb 2019 22:12:09 +0000 (14:12 -0800)
Make use of the generic c45 code, plus code specific to the Aquantia
phy for 1000BaseT negotiation.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/aquantia.c

index 9661ef4b40b0002ca54905494585c7dc70083d8f..a1846daa33886fc54e7df6fc61fd1af11c9ea641 100644 (file)
 #define PHY_ID_AQCS109 0x03a1b5c2
 #define PHY_ID_AQR405  0x03a1b4b0
 
+#define MDIO_AN_VEND_PROV                      0xc400
+#define MDIO_AN_VEND_PROV_1000BASET_FULL       BIT(15)
+#define MDIO_AN_VEND_PROV_1000BASET_HALF       BIT(14)
+
 #define MDIO_AN_TX_VEND_STATUS1                        0xc800
 #define MDIO_AN_TX_VEND_STATUS1_10BASET                (0x0 << 1)
 #define MDIO_AN_TX_VEND_STATUS1_100BASETX      (0x1 << 1)
 
 static int aqr_config_aneg(struct phy_device *phydev)
 {
-       linkmode_copy(phydev->supported, phy_10gbit_features);
-       linkmode_copy(phydev->advertising, phydev->supported);
+       bool changed = false;
+       u16 reg;
+       int ret;
 
-       return 0;
+       if (phydev->autoneg == AUTONEG_DISABLE)
+               return genphy_c45_pma_setup_forced(phydev);
+
+       ret = genphy_c45_an_config_aneg(phydev);
+       if (ret < 0)
+               return ret;
+       if (ret > 0)
+               changed = true;
+
+       /* Clause 45 has no standardized support for 1000BaseT, therefore
+        * use vendor registers for this mode.
+        */
+       reg = 0;
+       if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                             phydev->advertising))
+               reg |= MDIO_AN_VEND_PROV_1000BASET_FULL;
+
+       if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+                             phydev->advertising))
+               reg |= MDIO_AN_VEND_PROV_1000BASET_HALF;
+
+       ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
+                                    MDIO_AN_VEND_PROV_1000BASET_HALF |
+                                    MDIO_AN_VEND_PROV_1000BASET_FULL, reg);
+       if (ret < 0)
+               return ret;
+       if (ret > 0)
+               changed = true;
+
+       return genphy_c45_check_and_restart_aneg(phydev, changed);
 }
 
 static int aqr_config_intr(struct phy_device *phydev)