net: pcs: xpcs: add 1000BASE-X AN interrupt support
authorJiawen Wu <jiawenwu@trustnetic.com>
Wed, 23 Aug 2023 06:19:30 +0000 (14:19 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 25 Aug 2023 06:42:58 +0000 (07:42 +0100)
Enable CL37 AN complete interrupt for DW XPCS. It requires to clear the
bit(0) [CL37_ANCMPLT_INTR] of VR_MII_AN_INTR_STS after AN completed.

And there is a quirk for Wangxun devices to enable CL37 AN in backplane
configurations because of the special hardware design.

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

index 4cd0114..b806a9b 100644 (file)
@@ -755,6 +755,9 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
        int ret, mdio_ctrl, adv;
        bool changed = 0;
 
+       if (xpcs->dev_flag == DW_DEV_TXGBE)
+               xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
+
        /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
         * be disabled first:-
         * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
@@ -776,6 +779,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
                return ret;
 
        ret &= ~DW_VR_MII_PCS_MODE_MASK;
+       if (!xpcs->pcs.poll)
+               ret |= DW_VR_MII_AN_INTR_EN;
        ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
        if (ret < 0)
                return ret;
@@ -1029,6 +1034,17 @@ static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
                if (bmsr < 0)
                        return bmsr;
 
+               /* Clear AN complete interrupt */
+               if (!xpcs->pcs.poll) {
+                       int an_intr;
+
+                       an_intr = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
+                       if (an_intr & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+                               an_intr &= ~DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
+                               xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, an_intr);
+                       }
+               }
+
                phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
        }
 
@@ -1319,9 +1335,10 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
 
                xpcs->pcs.ops = &xpcs_phylink_ops;
                xpcs->pcs.neg_mode = true;
-               xpcs->pcs.poll = true;
 
                if (xpcs->dev_flag != DW_DEV_TXGBE) {
+                       xpcs->pcs.poll = true;
+
                        ret = xpcs_soft_reset(xpcs, compat);
                        if (ret)
                                goto out;
index da61ad3..ff04f6b 100644 (file)
@@ -18,6 +18,7 @@
 #define DW_VR_XS_PCS_DIG_CTRL1         0x0000
 #define DW_VR_RST                      BIT(15)
 #define DW_EN_VSMMD1                   BIT(13)
+#define DW_CL37_BP                     BIT(12)
 #define DW_VR_XS_PCS_DIG_STS           0x0010
 #define DW_RXFIFO_ERR                  GENMASK(6, 5)
 #define DW_PSEQ_ST                     GENMASK(4, 2)
 #define DW_VR_MII_PCS_MODE_MASK                        GENMASK(2, 1)
 #define DW_VR_MII_PCS_MODE_C37_1000BASEX       0x0
 #define DW_VR_MII_PCS_MODE_C37_SGMII           0x2
+#define DW_VR_MII_AN_INTR_EN                   BIT(0)
 
 /* VR_MII_AN_INTR_STS */
+#define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR      BIT(0)
 #define DW_VR_MII_AN_STS_C37_ANSGM_FD          BIT(1)
 #define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT    2
 #define DW_VR_MII_AN_STS_C37_ANSGM_SP          GENMASK(3, 2)