[][kernel][common][eth][Add EEE support for GDM]

[Description]
Add EEE support for GDM.
  - ethtool --set-eee eth1 tx-lpi on tx-timer 1
  - ethtool --show-eee eth1

If without this patch, user can't use ethtool to enable
MAC/PHY EEE capability.

[Release-log]
N/A


Change-Id: I624fbefba33fa2d75bc10efec0531b96f7d8034a
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6829459
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index af4893c..6f3b918 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -292,6 +292,44 @@
 	mtk_w32(eth, val, MTK_GSW_CFG);
 }
 
+static void mtk_setup_eee(struct mtk_mac *mac, bool enable)
+{
+	struct mtk_eth *eth = mac->hw;
+	u32 mcr, mcr_cur;
+	u32 val;
+
+	mcr = mcr_cur = mtk_r32(eth, MTK_MAC_MCR(mac->id));
+	mcr &= ~(MAC_MCR_FORCE_EEE100 | MAC_MCR_FORCE_EEE1000);
+
+	if (enable) {
+		mac->tx_lpi_enabled = 1;
+
+		val = FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 19) |
+		      FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 33) |
+		      FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD,
+				 mac->tx_lpi_timer) |
+		      FIELD_PREP(MAC_EEE_RESV0, 14);
+		mtk_w32(eth, val, MTK_MAC_EEE(mac->id));
+
+		switch (mac->speed) {
+		case SPEED_1000:
+			mcr |= MAC_MCR_FORCE_EEE1000;
+			break;
+		case SPEED_100:
+			mcr |= MAC_MCR_FORCE_EEE100;
+			break;
+		};
+	} else {
+		mac->tx_lpi_enabled = 0;
+
+		mtk_w32(eth, 0x00000002, MTK_MAC_EEE(mac->id));
+	}
+
+	/* Only update control register when needed! */
+	if (mcr != mcr_cur)
+		mtk_w32(eth, mcr, MTK_MAC_MCR(mac->id));
+}
+
 static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
 			   const struct phylink_link_state *state)
 {
@@ -629,6 +667,8 @@
 					   phylink_config);
 	u32 mcr, mcr_cur;
 
+	mac->speed = speed;
+
 	if (mac->type == MTK_GDM_TYPE) {
 		mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
 		mcr = mcr_cur;
@@ -666,6 +706,9 @@
 		/* Only update control register when needed! */
 		if (mcr != mcr_cur)
 			mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+
+		if (mode == MLO_AN_PHY && phy)
+			mtk_setup_eee(mac, phy_init_eee(phy, false) >= 0);
 	} else if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
 		mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
 
@@ -3936,6 +3979,39 @@
 	return phylink_ethtool_set_pauseparam(mac->phylink, pause);
 }
 
+static int mtk_get_eee(struct net_device *dev, struct ethtool_eee *eee)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	u32 val;
+
+	if (mac->type == MTK_GDM_TYPE) {
+		val = mtk_r32(eth, MTK_MAC_EEE(mac->id));
+
+		eee->tx_lpi_enabled = mac->tx_lpi_enabled;
+		eee->tx_lpi_timer = FIELD_GET(MAC_EEE_LPI_TXIDLE_THD, val);
+	}
+
+	return phylink_ethtool_get_eee(mac->phylink, eee);
+}
+
+static int mtk_set_eee(struct net_device *dev, struct ethtool_eee *eee)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+
+	if (mac->type == MTK_GDM_TYPE) {
+		if (eee->tx_lpi_enabled && eee->tx_lpi_timer > 255)
+			return -EINVAL;
+
+		mac->tx_lpi_timer = eee->tx_lpi_timer;
+
+		mtk_setup_eee(mac, eee->eee_enabled && eee->tx_lpi_timer);
+	}
+
+	return phylink_ethtool_set_eee(mac->phylink, eee);
+}
+
 static const struct ethtool_ops mtk_ethtool_ops = {
 	.get_link_ksettings	= mtk_get_link_ksettings,
 	.set_link_ksettings	= mtk_set_link_ksettings,
@@ -3951,6 +4027,8 @@
 	.set_rxnfc              = mtk_set_rxnfc,
 	.get_pauseparam		= mtk_get_pauseparam,
 	.set_pauseparam		= mtk_set_pauseparam,
+	.get_eee		= mtk_get_eee,
+	.set_eee		= mtk_set_eee,
 };
 
 static const struct net_device_ops mtk_netdev_ops = {
@@ -4037,6 +4115,8 @@
 	mac->mode = MLO_AN_PHY;
 	mac->speed = SPEED_UNKNOWN;
 
+	mac->tx_lpi_timer = 1;
+
 	mac->phylink_config.dev = &eth->netdev[id]->dev;
 	mac->phylink_config.type = PHYLINK_NETDEV;
 
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index a594d0b..f0b3a24 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -662,6 +662,8 @@
 #define MAC_MCR_RX_EN		BIT(13)
 #define MAC_MCR_BACKOFF_EN	BIT(9)
 #define MAC_MCR_BACKPR_EN	BIT(8)
+#define MAC_MCR_FORCE_EEE1000	BIT(7)
+#define MAC_MCR_FORCE_EEE100	BIT(6)
 #define MAC_MCR_FORCE_RX_FC	BIT(5)
 #define MAC_MCR_FORCE_TX_FC	BIT(4)
 #define MAC_MCR_SPEED_1000	BIT(3)
@@ -676,6 +678,17 @@
 #define XMAC_MCR_FORCE_TX_FC	BIT(5)
 #define XMAC_MCR_FORCE_RX_FC	BIT(4)
 
+/* Mac EEE control registers */
+#define MTK_MAC_EEE(x)		(0x10104 + (x * 0x100))
+#define MAC_EEE_WAKEUP_TIME_1000	GENMASK(31, 24)
+#define MAC_EEE_WAKEUP_TIME_100	GENMASK(23, 16)
+#define MAC_EEE_LPI_TXIDLE_THD	GENMASK(15, 8)
+#define MAC_EEE_RESV0		GENMASK(7, 4)
+#define MAC_EEE_CKG_TXILDE	BIT(3)
+#define MAC_EEE_CKG_RXLPI	BIT(2)
+#define MAC_EEE_TX_DOWN_REQ	BIT(1)
+#define MAC_EEE_LPI_MODE	BIT(0)
+
 /* Mac status registers */
 #define MTK_MAC_MSR(x)		(0x10108 + (x * 0x100))
 #define MAC_MSR_EEE1G		BIT(7)
@@ -1659,6 +1672,8 @@
 	struct mtk_hw_stats		*hw_stats;
 	__be32				hwlro_ip[MTK_MAX_LRO_IP_CNT];
 	int				hwlro_ip_cnt;
+	bool				tx_lpi_enabled;
+	u32				tx_lpi_timer;
 };
 
 /* the struct describing the SoC. these are declared in the soc_xyz.c files */