amd-xgbe: Update the BelFuse quirk to support SGMII
authorTom Lendacky <thomas.lendacky@amd.com>
Wed, 23 May 2018 16:39:39 +0000 (11:39 -0500)
committerDavid S. Miller <davem@davemloft.net>
Wed, 23 May 2018 20:33:01 +0000 (16:33 -0400)
Instead of using a quirk to make the BelFuse 1GBT-SFP06 part look like
a 1000baseX part, program the SFP PHY to support SGMII and 10/100/1000
baseT.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c

index dd747f6..194a569 100644 (file)
@@ -860,6 +860,9 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        unsigned int phy_id = phy_data->phydev->phy_id;
 
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        unsigned int phy_id = phy_data->phydev->phy_id;
 
+       if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
+               return false;
+
        if ((phy_id & 0xfffffff0) != 0x01ff0cc0)
                return false;
 
        if ((phy_id & 0xfffffff0) != 0x01ff0cc0)
                return false;
 
@@ -885,8 +888,80 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
        return true;
 }
 
        return true;
 }
 
+static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+       struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
+       unsigned int phy_id = phy_data->phydev->phy_id;
+       int reg;
+
+       if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
+               return false;
+
+       if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
+                  XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
+               return false;
+
+       if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
+                  XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
+               return false;
+
+       if ((phy_id & 0xfffffff0) != 0x03625d10)
+               return false;
+
+       /* Disable RGMII mode */
+       phy_write(phy_data->phydev, 0x18, 0x7007);
+       reg = phy_read(phy_data->phydev, 0x18);
+       phy_write(phy_data->phydev, 0x18, reg & ~0x0080);
+
+       /* Enable fiber register bank */
+       phy_write(phy_data->phydev, 0x1c, 0x7c00);
+       reg = phy_read(phy_data->phydev, 0x1c);
+       reg &= 0x03ff;
+       reg &= ~0x0001;
+       phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0001);
+
+       /* Power down SerDes */
+       reg = phy_read(phy_data->phydev, 0x00);
+       phy_write(phy_data->phydev, 0x00, reg | 0x00800);
+
+       /* Configure SGMII-to-Copper mode */
+       phy_write(phy_data->phydev, 0x1c, 0x7c00);
+       reg = phy_read(phy_data->phydev, 0x1c);
+       reg &= 0x03ff;
+       reg &= ~0x0006;
+       phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0004);
+
+       /* Power up SerDes */
+       reg = phy_read(phy_data->phydev, 0x00);
+       phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
+
+       /* Enable copper register bank */
+       phy_write(phy_data->phydev, 0x1c, 0x7c00);
+       reg = phy_read(phy_data->phydev, 0x1c);
+       reg &= 0x03ff;
+       reg &= ~0x0001;
+       phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg);
+
+       /* Power up SerDes */
+       reg = phy_read(phy_data->phydev, 0x00);
+       phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
+
+       phy_data->phydev->supported = PHY_GBIT_FEATURES;
+       phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+       phy_data->phydev->advertising = phy_data->phydev->supported;
+
+       netif_dbg(pdata, drv, pdata->netdev,
+                 "BelFuse PHY quirk in place\n");
+
+       return true;
+}
+
 static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
 {
 static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
 {
+       if (xgbe_phy_belfuse_phy_quirks(pdata))
+               return;
+
        if (xgbe_phy_finisar_phy_quirks(pdata))
                return;
 }
        if (xgbe_phy_finisar_phy_quirks(pdata))
                return;
 }
@@ -1027,37 +1102,6 @@ static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
        return false;
 }
 
        return false;
 }
 
-static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata)
-{
-       struct xgbe_phy_data *phy_data = pdata->phy_data;
-       struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
-
-       if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
-                  XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
-               return false;
-
-       if (!memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
-                   XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN)) {
-               phy_data->sfp_base = XGBE_SFP_BASE_1000_SX;
-               phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE;
-               phy_data->sfp_speed = XGBE_SFP_SPEED_1000;
-               if (phy_data->sfp_changed)
-                       netif_dbg(pdata, drv, pdata->netdev,
-                                 "Bel-Fuse SFP quirk in place\n");
-               return true;
-       }
-
-       return false;
-}
-
-static bool xgbe_phy_sfp_parse_quirks(struct xgbe_prv_data *pdata)
-{
-       if (xgbe_phy_belfuse_parse_quirks(pdata))
-               return true;
-
-       return false;
-}
-
 static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
 static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -1076,9 +1120,6 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
        phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
        phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
 
        phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
        phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
 
-       if (xgbe_phy_sfp_parse_quirks(pdata))
-               return;
-
        /* Assume ACTIVE cable unless told it is PASSIVE */
        if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
                phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;
        /* Assume ACTIVE cable unless told it is PASSIVE */
        if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
                phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;