net: pcs: add 2500BASEX support for Intel mGbE controller
authorVoon Weifeng <weifeng.voon@intel.com>
Tue, 8 Jun 2021 03:51:57 +0000 (11:51 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 8 Jun 2021 21:31:43 +0000 (14:31 -0700)
XPCS IP supports 2500BASEX as PHY interface. It is configured as
autonegotiation disable to cater for PHYs that does not supports 2500BASEX
autonegotiation.

v2: Add supported link speed masking.
v3: Restructure to introduce xpcs_config_2500basex() used to configure the
    xpcs for 2.5G speeds. Added 2500BASEX specific information for
    configuration.
v4: Fix indentation error

Signed-off-by: Voon Weifeng <weifeng.voon@intel.com>
Signed-off-by: Michael Sit Wei Hong <michael.wei.hong.sit@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/pcs/pcs-xpcs.c
include/linux/pcs/pcs-xpcs.h

index 34164437c1359781bae296a93115c719f5547767..98c4a3973402679d502613c6ba4c3757a8cb6caa 100644 (file)
 
 /* Clause 37 Defines */
 /* VR MII MMD registers offsets */
+#define DW_VR_MII_MMD_CTRL             0x0000
 #define DW_VR_MII_DIG_CTRL1            0x8000
 #define DW_VR_MII_AN_CTRL              0x8001
 #define DW_VR_MII_AN_INTR_STS          0x8002
+/* Enable 2.5G Mode */
+#define DW_VR_MII_DIG_CTRL1_2G5_EN     BIT(2)
 /* EEE Mode Control Register */
 #define DW_VR_MII_EEE_MCTRL0           0x8006
 #define DW_VR_MII_EEE_MCTRL1           0x800b
 #define DW_VR_MII_C37_ANSGM_SP_1000            0x2
 #define DW_VR_MII_C37_ANSGM_SP_LNKSTS          BIT(4)
 
+/* SR MII MMD Control defines */
+#define AN_CL37_EN             BIT(12) /* Enable Clause 37 auto-nego */
+#define SGMII_SPEED_SS13       BIT(13) /* SGMII speed along with SS6 */
+#define SGMII_SPEED_SS6                BIT(6)  /* SGMII speed along with SS13 */
+
 /* VR MII EEE Control 0 defines */
 #define DW_VR_MII_EEE_LTX_EN           BIT(0)  /* LPI Tx Enable */
 #define DW_VR_MII_EEE_LRX_EN           BIT(1)  /* LPI Rx Enable */
@@ -161,6 +169,14 @@ static const int xpcs_sgmii_features[] = {
        __ETHTOOL_LINK_MODE_MASK_NBITS,
 };
 
+static const int xpcs_2500basex_features[] = {
+       ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+       ETHTOOL_LINK_MODE_Autoneg_BIT,
+       ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+       ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+       __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
 static const phy_interface_t xpcs_usxgmii_interfaces[] = {
        PHY_INTERFACE_MODE_USXGMII,
 };
@@ -177,11 +193,17 @@ static const phy_interface_t xpcs_sgmii_interfaces[] = {
        PHY_INTERFACE_MODE_SGMII,
 };
 
+static const phy_interface_t xpcs_2500basex_interfaces[] = {
+       PHY_INTERFACE_MODE_2500BASEX,
+       PHY_INTERFACE_MODE_MAX,
+};
+
 enum {
        DW_XPCS_USXGMII,
        DW_XPCS_10GKR,
        DW_XPCS_XLGMII,
        DW_XPCS_SGMII,
+       DW_XPCS_2500BASEX,
        DW_XPCS_INTERFACE_MAX,
 };
 
@@ -306,6 +328,7 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs,
                dev = MDIO_MMD_PCS;
                break;
        case DW_AN_C37_SGMII:
+       case DW_2500BASEX:
                dev = MDIO_MMD_VEND2;
                break;
        default:
@@ -804,6 +827,28 @@ static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
        return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
 }
 
+static int xpcs_config_2500basex(struct mdio_xpcs_args *xpcs)
+{
+       int ret;
+
+       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+       if (ret < 0)
+               return ret;
+       ret |= DW_VR_MII_DIG_CTRL1_2G5_EN;
+       ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+       ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
+       if (ret < 0)
+               return ret;
+
+       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
+       if (ret < 0)
+               return ret;
+       ret &= ~AN_CL37_EN;
+       ret |= SGMII_SPEED_SS6;
+       ret &= ~SGMII_SPEED_SS13;
+       return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
+}
+
 static int xpcs_do_config(struct mdio_xpcs_args *xpcs,
                          phy_interface_t interface, unsigned int mode)
 {
@@ -827,6 +872,11 @@ static int xpcs_do_config(struct mdio_xpcs_args *xpcs,
                if (ret)
                        return ret;
                break;
+       case DW_2500BASEX:
+               ret = xpcs_config_2500basex(xpcs);
+               if (ret)
+                       return ret;
+               break;
        default:
                return -1;
        }
@@ -1023,6 +1073,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
                .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
                .an_mode = DW_AN_C37_SGMII,
        },
+       [DW_XPCS_2500BASEX] = {
+               .supported = xpcs_2500basex_features,
+               .interface = xpcs_2500basex_interfaces,
+               .num_interfaces = ARRAY_SIZE(xpcs_2500basex_features),
+               .an_mode = DW_2500BASEX,
+       },
 };
 
 static const struct xpcs_id xpcs_id_list[] = {
index 0860a5b59f10a8120296e9598833e360cd0d62fd..4d815f03b4b2c98908c26aa705c70a7d56ff636d 100644 (file)
@@ -13,6 +13,7 @@
 /* AN mode */
 #define DW_AN_C73                      1
 #define DW_AN_C37_SGMII                        2
+#define DW_2500BASEX                   3
 
 struct xpcs_id;