net: pcs: Introducing support for DWC xpcs Energy Efficient Ethernet
authorMichael Sit Wei Hong <michael.wei.hong.sit@intel.com>
Mon, 17 May 2021 09:43:31 +0000 (17:43 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 May 2021 22:53:58 +0000 (15:53 -0700)
Add DWC xpcs EEE support callbacks.The callback function is used to
set EEE registers on xpcs.

xpcs transparent mode is enabled to allow PHY to detect MAC EEE status.

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 944ba105cac16598865f3d245801a9b142cf0dc8..aa985a5aae8d699be267852512a8dac07d95fd30 100644 (file)
@@ -63,6 +63,9 @@
 #define DW_VR_MII_DIG_CTRL1            0x8000
 #define DW_VR_MII_AN_CTRL              0x8001
 #define DW_VR_MII_AN_INTR_STS          0x8002
+/* EEE Mode Control Register */
+#define DW_VR_MII_EEE_MCTRL0           0x8006
+#define DW_VR_MII_EEE_MCTRL1           0x800b
 
 /* VR_MII_DIG_CTRL1 */
 #define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW                BIT(9)
 #define DW_VR_MII_C37_ANSGM_SP_1000            0x2
 #define DW_VR_MII_C37_ANSGM_SP_LNKSTS          BIT(4)
 
+/* 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 */
+#define DW_VR_MII_EEE_TX_QUIET_EN              BIT(2)  /* Tx Quiet Enable */
+#define DW_VR_MII_EEE_RX_QUIET_EN              BIT(3)  /* Rx Quiet Enable */
+#define DW_VR_MII_EEE_TX_EN_CTRL               BIT(4)  /* Tx Control Enable */
+#define DW_VR_MII_EEE_RX_EN_CTRL               BIT(7)  /* Rx Control Enable */
+
+#define DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT    8
+#define DW_VR_MII_EEE_MULT_FACT_100NS          GENMASK(11, 8)
+
+/* VR MII EEE Control 1 defines */
+#define DW_VR_MII_EEE_TRN_LPI          BIT(0)  /* Transparent Mode Enable */
+
 static const int xpcs_usxgmii_features[] = {
        ETHTOOL_LINK_MODE_Pause_BIT,
        ETHTOOL_LINK_MODE_Asym_Pause_BIT,
@@ -650,6 +667,39 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs,
        return 0;
 }
 
+static int xpcs_config_eee(struct mdio_xpcs_args *xpcs, int mult_fact_100ns,
+                          int enable)
+{
+       int ret;
+
+       if (enable) {
+       /* Enable EEE */
+               ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+                     DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+                     DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+                     mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT;
+       } else {
+               ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0);
+               if (ret < 0)
+                       return ret;
+               ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+                      DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+                      DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+                      DW_VR_MII_EEE_MULT_FACT_100NS);
+       }
+
+       ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret);
+       if (ret < 0)
+               return ret;
+
+       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1);
+       if (ret < 0)
+               return ret;
+
+       ret |= DW_VR_MII_EEE_TRN_LPI;
+       return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret);
+}
+
 static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
 {
        int ret;
@@ -908,6 +958,7 @@ static struct mdio_xpcs_ops xpcs_ops = {
        .get_state = xpcs_get_state,
        .link_up = xpcs_link_up,
        .probe = xpcs_probe,
+       .config_eee = xpcs_config_eee,
 };
 
 struct mdio_xpcs_ops *mdio_xpcs_get_ops(void)
index 2cb5188a7ef13900582ee89ffce15847e6555349..5938ced805f47e314154373a5b88d18426e56299 100644 (file)
@@ -32,6 +32,8 @@ struct mdio_xpcs_ops {
        int (*link_up)(struct mdio_xpcs_args *xpcs, int speed,
                       phy_interface_t interface);
        int (*probe)(struct mdio_xpcs_args *xpcs, phy_interface_t interface);
+       int (*config_eee)(struct mdio_xpcs_args *xpcs, int mult_fact_100ns,
+                         int enable);
 };
 
 #if IS_ENABLED(CONFIG_PCS_XPCS)