amd-xgbe: Add support for 10 Mbps speed
authorRaju Rangoju <Raju.Rangoju@amd.com>
Mon, 9 Jan 2023 10:18:19 +0000 (15:48 +0530)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 10 Jan 2023 10:20:30 +0000 (11:20 +0100)
Add the necessary changes to support 10 Mbps speed for BaseT and SFP
port modes. This is supported in MAC ver >= 30H.

Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com>
Link: https://lore.kernel.org/r/20230109101819.747572-1-Raju.Rangoju@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
drivers/net/ethernet/amd/xgbe/xgbe.h

index 3936543..e033d6c 100644 (file)
@@ -807,6 +807,9 @@ static int xgbe_set_speed(struct xgbe_prv_data *pdata, int speed)
        unsigned int ss;
 
        switch (speed) {
+       case SPEED_10:
+               ss = 0x07;
+               break;
        case SPEED_1000:
                ss = 0x03;
                break;
index 0c5c1b1..cde0f86 100644 (file)
@@ -274,6 +274,15 @@ static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
        pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
 }
 
+static void xgbe_sgmii_10_mode(struct xgbe_prv_data *pdata)
+{
+       /* Set MAC to 10M speed */
+       pdata->hw_if.set_speed(pdata, SPEED_10);
+
+       /* Call PHY implementation support to complete rate change */
+       pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_10);
+}
+
 static void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
 {
        /* Set MAC to 1G speed */
@@ -306,6 +315,9 @@ static void xgbe_change_mode(struct xgbe_prv_data *pdata,
        case XGBE_MODE_KR:
                xgbe_kr_mode(pdata);
                break;
+       case XGBE_MODE_SGMII_10:
+               xgbe_sgmii_10_mode(pdata);
+               break;
        case XGBE_MODE_SGMII_100:
                xgbe_sgmii_100_mode(pdata);
                break;
@@ -1074,6 +1086,8 @@ static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
 static const char *xgbe_phy_speed_string(int speed)
 {
        switch (speed) {
+       case SPEED_10:
+               return "10Mbps";
        case SPEED_100:
                return "100Mbps";
        case SPEED_1000:
@@ -1161,6 +1175,7 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
        case XGBE_MODE_KX_1000:
        case XGBE_MODE_KX_2500:
        case XGBE_MODE_KR:
+       case XGBE_MODE_SGMII_10:
        case XGBE_MODE_SGMII_100:
        case XGBE_MODE_SGMII_1000:
        case XGBE_MODE_X:
@@ -1222,6 +1237,8 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
                        xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
                } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
                        xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
+               } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_10)) {
+                       xgbe_set_mode(pdata, XGBE_MODE_SGMII_10);
                } else {
                        enable_irq(pdata->an_irq);
                        ret = -EINVAL;
@@ -1301,6 +1318,9 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
                mode = xgbe_phy_status_aneg(pdata);
 
        switch (mode) {
+       case XGBE_MODE_SGMII_10:
+               pdata->phy.speed = SPEED_10;
+               break;
        case XGBE_MODE_SGMII_100:
                pdata->phy.speed = SPEED_100;
                break;
@@ -1443,6 +1463,8 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
                xgbe_sgmii_1000_mode(pdata);
        } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
                xgbe_sgmii_100_mode(pdata);
+       } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_10)) {
+               xgbe_sgmii_10_mode(pdata);
        } else {
                ret = -EINVAL;
                goto err_irq;
@@ -1540,6 +1562,8 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
                return SPEED_1000;
        else if (XGBE_ADV(lks, 100baseT_Full))
                return SPEED_100;
+       else if (XGBE_ADV(lks, 10baseT_Full))
+               return SPEED_10;
 
        return SPEED_UNKNOWN;
 }
index c731a04..de7118c 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
+#define XGBE_PHY_PORT_SPEED_10         BIT(0)
 #define XGBE_PHY_PORT_SPEED_100                BIT(1)
 #define XGBE_PHY_PORT_SPEED_1000       BIT(2)
 #define XGBE_PHY_PORT_SPEED_2500       BIT(3)
@@ -759,6 +760,8 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
                XGBE_SET_SUP(lks, Pause);
                XGBE_SET_SUP(lks, Asym_Pause);
                if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) {
+                       if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)
+                               XGBE_SET_SUP(lks, 10baseT_Full);
                        if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
                                XGBE_SET_SUP(lks, 100baseT_Full);
                        if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
@@ -1542,6 +1545,16 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
                xgbe_phy_phydev_flowctrl(pdata);
 
        switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) {
+       case XGBE_SGMII_AN_LINK_SPEED_10:
+               if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
+                       XGBE_SET_LP_ADV(lks, 10baseT_Full);
+                       mode = XGBE_MODE_SGMII_10;
+               } else {
+                       /* Half-duplex not supported */
+                       XGBE_SET_LP_ADV(lks, 10baseT_Half);
+                       mode = XGBE_MODE_UNKNOWN;
+               }
+               break;
        case XGBE_SGMII_AN_LINK_SPEED_100:
                if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
                        XGBE_SET_LP_ADV(lks, 100baseT_Full);
@@ -1658,7 +1671,10 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
                        switch (phy_data->sfp_base) {
                        case XGBE_SFP_BASE_1000_T:
                                if (phy_data->phydev &&
-                                   (phy_data->phydev->speed == SPEED_100))
+                                   (phy_data->phydev->speed == SPEED_10))
+                                       mode = XGBE_MODE_SGMII_10;
+                               else if (phy_data->phydev &&
+                                        (phy_data->phydev->speed == SPEED_100))
                                        mode = XGBE_MODE_SGMII_100;
                                else
                                        mode = XGBE_MODE_SGMII_1000;
@@ -1673,7 +1689,10 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
                        break;
                default:
                        if (phy_data->phydev &&
-                           (phy_data->phydev->speed == SPEED_100))
+                           (phy_data->phydev->speed == SPEED_10))
+                               mode = XGBE_MODE_SGMII_10;
+                       else if (phy_data->phydev &&
+                                (phy_data->phydev->speed == SPEED_100))
                                mode = XGBE_MODE_SGMII_100;
                        else
                                mode = XGBE_MODE_SGMII_1000;
@@ -2127,6 +2146,20 @@ static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata)
        netif_dbg(pdata, link, pdata->netdev, "100MbE SGMII mode set\n");
 }
 
+static void xgbe_phy_sgmii_10_mode(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       xgbe_phy_set_redrv_mode(pdata);
+
+       /* 10M/SGMII */
+       xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_10MBITS);
+
+       phy_data->cur_mode = XGBE_MODE_SGMII_10;
+
+       netif_dbg(pdata, link, pdata->netdev, "10MbE SGMII mode set\n");
+}
+
 static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -2185,6 +2218,7 @@ static enum xgbe_mode xgbe_phy_switch_baset_mode(struct xgbe_prv_data *pdata)
                return xgbe_phy_cur_mode(pdata);
 
        switch (xgbe_phy_cur_mode(pdata)) {
+       case XGBE_MODE_SGMII_10:
        case XGBE_MODE_SGMII_100:
        case XGBE_MODE_SGMII_1000:
                return XGBE_MODE_KR;
@@ -2252,6 +2286,8 @@ static enum xgbe_mode xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data,
                                              int speed)
 {
        switch (speed) {
+       case SPEED_10:
+               return XGBE_MODE_SGMII_10;
        case SPEED_100:
                return XGBE_MODE_SGMII_100;
        case SPEED_1000:
@@ -2269,6 +2305,8 @@ static enum xgbe_mode xgbe_phy_get_sfp_mode(struct xgbe_phy_data *phy_data,
                                            int speed)
 {
        switch (speed) {
+       case SPEED_10:
+               return XGBE_MODE_SGMII_10;
        case SPEED_100:
                return XGBE_MODE_SGMII_100;
        case SPEED_1000:
@@ -2343,6 +2381,9 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
        case XGBE_MODE_KR:
                xgbe_phy_kr_mode(pdata);
                break;
+       case XGBE_MODE_SGMII_10:
+               xgbe_phy_sgmii_10_mode(pdata);
+               break;
        case XGBE_MODE_SGMII_100:
                xgbe_phy_sgmii_100_mode(pdata);
                break;
@@ -2399,6 +2440,9 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
        struct ethtool_link_ksettings *lks = &pdata->phy.lks;
 
        switch (mode) {
+       case XGBE_MODE_SGMII_10:
+               return xgbe_phy_check_mode(pdata, mode,
+                                          XGBE_ADV(lks, 10baseT_Full));
        case XGBE_MODE_SGMII_100:
                return xgbe_phy_check_mode(pdata, mode,
                                           XGBE_ADV(lks, 100baseT_Full));
@@ -2428,6 +2472,11 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
                        return false;
                return xgbe_phy_check_mode(pdata, mode,
                                           XGBE_ADV(lks, 1000baseX_Full));
+       case XGBE_MODE_SGMII_10:
+               if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
+                       return false;
+               return xgbe_phy_check_mode(pdata, mode,
+                                          XGBE_ADV(lks, 10baseT_Full));
        case XGBE_MODE_SGMII_100:
                if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
                        return false;
@@ -2520,10 +2569,17 @@ static bool xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data *phy_data,
        }
 }
 
-static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data,
+static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_prv_data *pdata,
                                            int speed)
 {
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int ver;
+
        switch (speed) {
+       case SPEED_10:
+               /* Supported in ver >= 30H */
+               ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
+               return (ver >= 0x30) ? true : false;
        case SPEED_100:
        case SPEED_1000:
                return true;
@@ -2536,10 +2592,17 @@ static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data,
        }
 }
 
-static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data *phy_data,
+static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_prv_data *pdata,
                                          int speed)
 {
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int ver;
+
        switch (speed) {
+       case SPEED_10:
+               /* Supported in ver >= 30H */
+               ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
+               return (ver >= 0x30) && (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000);
        case SPEED_100:
                return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000);
        case SPEED_1000:
@@ -2586,12 +2649,12 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
        case XGBE_PORT_MODE_1000BASE_T:
        case XGBE_PORT_MODE_NBASE_T:
        case XGBE_PORT_MODE_10GBASE_T:
-               return xgbe_phy_valid_speed_baset_mode(phy_data, speed);
+               return xgbe_phy_valid_speed_baset_mode(pdata, speed);
        case XGBE_PORT_MODE_1000BASE_X:
        case XGBE_PORT_MODE_10GBASE_R:
                return xgbe_phy_valid_speed_basex_mode(phy_data, speed);
        case XGBE_PORT_MODE_SFP:
-               return xgbe_phy_valid_speed_sfp_mode(phy_data, speed);
+               return xgbe_phy_valid_speed_sfp_mode(pdata, speed);
        default:
                return false;
        }
@@ -2862,6 +2925,12 @@ static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
 static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int ver;
+
+       /* 10 Mbps speed is not supported in ver < 30H */
+       ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
+       if (ver < 0x30 && (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10))
+               return true;
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
@@ -2875,7 +2944,8 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
                        return false;
                break;
        case XGBE_PORT_MODE_1000BASE_T:
-               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
+               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
+                   (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000))
                        return false;
                break;
@@ -2884,13 +2954,15 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
                        return false;
                break;
        case XGBE_PORT_MODE_NBASE_T:
-               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
+               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
+                   (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500))
                        return false;
                break;
        case XGBE_PORT_MODE_10GBASE_T:
-               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
+               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
+                   (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
                        return false;
@@ -2900,7 +2972,8 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
                        return false;
                break;
        case XGBE_PORT_MODE_SFP:
-               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
+               if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
+                   (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
                        return false;
@@ -3269,6 +3342,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
                XGBE_SET_SUP(lks, Pause);
                XGBE_SET_SUP(lks, Asym_Pause);
                XGBE_SET_SUP(lks, TP);
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) {
+                       XGBE_SET_SUP(lks, 10baseT_Full);
+                       phy_data->start_mode = XGBE_MODE_SGMII_10;
+               }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
                        XGBE_SET_SUP(lks, 100baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
@@ -3299,6 +3376,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
                XGBE_SET_SUP(lks, Pause);
                XGBE_SET_SUP(lks, Asym_Pause);
                XGBE_SET_SUP(lks, TP);
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) {
+                       XGBE_SET_SUP(lks, 10baseT_Full);
+                       phy_data->start_mode = XGBE_MODE_SGMII_10;
+               }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
                        XGBE_SET_SUP(lks, 100baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
@@ -3321,6 +3402,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
                XGBE_SET_SUP(lks, Pause);
                XGBE_SET_SUP(lks, Asym_Pause);
                XGBE_SET_SUP(lks, TP);
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) {
+                       XGBE_SET_SUP(lks, 10baseT_Full);
+                       phy_data->start_mode = XGBE_MODE_SGMII_10;
+               }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
                        XGBE_SET_SUP(lks, 100baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
@@ -3361,6 +3446,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
                XGBE_SET_SUP(lks, Asym_Pause);
                XGBE_SET_SUP(lks, TP);
                XGBE_SET_SUP(lks, FIBRE);
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)
+                       phy_data->start_mode = XGBE_MODE_SGMII_10;
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
index 71f24cb..da37476 100644 (file)
 
 #define XGBE_SGMII_AN_LINK_STATUS      BIT(1)
 #define XGBE_SGMII_AN_LINK_SPEED       (BIT(2) | BIT(3))
+#define XGBE_SGMII_AN_LINK_SPEED_10    0x00
 #define XGBE_SGMII_AN_LINK_SPEED_100   0x04
 #define XGBE_SGMII_AN_LINK_SPEED_1000  0x08
 #define XGBE_SGMII_AN_LINK_DUPLEX      BIT(4)
@@ -594,6 +595,7 @@ enum xgbe_mode {
        XGBE_MODE_KX_2500,
        XGBE_MODE_KR,
        XGBE_MODE_X,
+       XGBE_MODE_SGMII_10,
        XGBE_MODE_SGMII_100,
        XGBE_MODE_SGMII_1000,
        XGBE_MODE_SFI,