net: pcs: xpcs: adapt Wangxun NICs for SGMII mode
authorJiawen Wu <jiawenwu@trustnetic.com>
Wed, 23 Aug 2023 06:19:31 +0000 (14:19 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 25 Aug 2023 06:42:59 +0000 (07:42 +0100)
Wangxun NICs support the connection with SFP to RJ45 module. In this case,
PCS need to be configured in SGMII mode.

According to chapter 6.11.1 "SGMII Auto-Negitiation" of DesignWare Cores
Ethernet PCS (version 3.20a) and custom design manual, do the following
configuration when the interface mode is SGMII.

1. program VR_MII_AN_CTRL bit(3) [TX_CONFIG] = 1b (PHY side SGMII)
2. program VR_MII_AN_CTRL bit(8) [MII_CTRL] = 1b (8-bit MII)
3. program VR_MII_DIG_CTRL1 bit(0) [PHY_MODE_CTRL] = 1b

Also CL37 AN in backplane configurations need to be enabled because of the
special hardware design. Another thing to note is that PMA needs to be
reconfigured before each CL37 AN configuration for SGMII, otherwise AN will
fail, although we don't know why.

On this device, CL37_ANSGM_STS (bit[4:1] of VR_MII_AN_INTR_STS) indicates
the status received from remote link during the auto-negotiation, and
self-clear after the auto-negotiation is complete.
Meanwhile, CL37_ANCMPLT_INTR will be set to 1, to indicate CL37 AN is
complete. So add another way to get the state for CL37 SGMII.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/pcs/pcs-xpcs-wx.c
drivers/net/pcs/pcs-xpcs.c
drivers/net/pcs/pcs-xpcs.h

index 1f228d5..19c7588 100644 (file)
@@ -162,8 +162,9 @@ static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
        /* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
        ret &= MDIO_PCS_CTRL2_TYPE;
-       if (ret == MDIO_PCS_CTRL2_10GBR &&
-           xpcs->interface != PHY_INTERFACE_MODE_10GBASER)
+       if ((ret == MDIO_PCS_CTRL2_10GBR &&
+            xpcs->interface != PHY_INTERFACE_MODE_10GBASER) ||
+           xpcs->interface == PHY_INTERFACE_MODE_SGMII)
                return true;
 
        return false;
index b806a9b..4dbc21f 100644 (file)
@@ -683,7 +683,10 @@ EXPORT_SYMBOL_GPL(xpcs_config_eee);
 static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
                                      unsigned int neg_mode)
 {
-       int ret, mdio_ctrl;
+       int ret, mdio_ctrl, tx_conf;
+
+       if (xpcs->dev_flag == DW_DEV_TXGBE)
+               xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
 
        /* For AN for C37 SGMII mode, the settings are :-
         * 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
@@ -720,9 +723,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
        ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
                DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
                DW_VR_MII_PCS_MODE_MASK);
-       ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
-               DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
-               DW_VR_MII_TX_CONFIG_MASK);
+       if (xpcs->dev_flag == DW_DEV_TXGBE) {
+               ret |= DW_VR_MII_AN_CTRL_8BIT;
+               /* Hardware requires it to be PHY side SGMII */
+               tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
+       } else {
+               tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII;
+       }
+       ret |= tx_conf << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
+               DW_VR_MII_TX_CONFIG_MASK;
        ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
        if (ret < 0)
                return ret;
@@ -736,6 +745,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
        else
                ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
 
+       if (xpcs->dev_flag == DW_DEV_TXGBE)
+               ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
+
        ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
        if (ret < 0)
                return ret;
@@ -1011,6 +1023,33 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
                        state->duplex = DUPLEX_FULL;
                else
                        state->duplex = DUPLEX_HALF;
+       } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+               int speed, duplex;
+
+               state->link = true;
+
+               speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+               if (speed < 0)
+                       return speed;
+
+               speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
+               if (speed == SGMII_SPEED_SS6)
+                       state->speed = SPEED_1000;
+               else if (speed == SGMII_SPEED_SS13)
+                       state->speed = SPEED_100;
+               else if (speed == 0)
+                       state->speed = SPEED_10;
+
+               duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
+               if (duplex < 0)
+                       return duplex;
+
+               if (duplex & DW_FULL_DUPLEX)
+                       state->duplex = DUPLEX_FULL;
+               else if (duplex & DW_HALF_DUPLEX)
+                       state->duplex = DUPLEX_HALF;
+
+               xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
        }
 
        return 0;
index ff04f6b..39a9041 100644 (file)
 
 /* VR_MII_DIG_CTRL1 */
 #define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW                BIT(9)
+#define DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL      BIT(0)
 
 /* VR_MII_DIG_CTRL2 */
 #define DW_VR_MII_DIG_CTRL2_TX_POL_INV         BIT(4)
 #define DW_VR_MII_DIG_CTRL2_RX_POL_INV         BIT(0)
 
 /* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_8BIT                 BIT(8)
 #define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT      3
 #define DW_VR_MII_TX_CONFIG_MASK               BIT(3)
 #define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII     0x1
 #define SGMII_SPEED_SS13               BIT(13) /* SGMII speed along with SS6 */
 #define SGMII_SPEED_SS6                        BIT(6)  /* SGMII speed along with SS13 */
 
+/* SR MII MMD AN Advertisement defines */
+#define DW_HALF_DUPLEX                 BIT(6)
+#define DW_FULL_DUPLEX                 BIT(5)
+
 /* 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 */