[][kernel][mt7988][eth][Add 10G interface dyanmically change support fo ESP-T5-R SFP+ modules]

[Description]
Add 10G interface dyanmically change support for ESP-T5-R SFP+ modules.
    - Support ETU ESP-T5-R module

Note: This feature backport from Linux-6.1.
https://elixir.bootlin.com/linux/v6.1/source/drivers/net/phy/phylink.c

[Release-log]
N/A


Change-Id: Ic15fa31f5ae7539c20a5009e74ab4ecb5c7a9621
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7123798
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c
index 3144511..cc4b1d5 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c
@@ -162,21 +162,6 @@
 		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
 				   SYSCFG0_SGMII_MASK, val);
 
-	/* Enable GDM/XGDM Path */
-	if (eth->mac[mac_id]->type == MTK_GDM_TYPE) {
-		val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac_id));
-		mtk_w32(eth, val & ~MTK_GDMA_XGDM_SEL,
-			MTK_GDMA_EG_CTRL(mac_id));
-	} else if (eth->mac[mac_id]->type == MTK_XGDM_TYPE) {
-		val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac_id));
-		mtk_w32(eth, val | MTK_GDMA_XGDM_SEL,
-			MTK_GDMA_EG_CTRL(mac_id));
-
-		val = mtk_r32(eth, MTK_XGMAC_STS(mac_id));
-		mtk_w32(eth, val | (MTK_XGMAC_FORCE_LINK << 16),
-			MTK_XGMAC_STS(mac_id));
-	}
-
 	spin_unlock(&eth->syscfg0_lock);
 
 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
@@ -271,11 +256,6 @@
 		}
 	}
 
-	/* Enable XGDM Path */
-	val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac_id));
-	val |= MTK_GDMA_XGDM_SEL;
-	mtk_w32(eth, val, MTK_GDMA_EG_CTRL(mac_id));
-
 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
 		mtk_eth_path_name(path), __func__, updated);
 
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 6f3b918..042916f 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
@@ -39,6 +39,7 @@
 static int mtk_msg_level = -1;
 atomic_t reset_lock = ATOMIC_INIT(0);
 atomic_t force = ATOMIC_INIT(0);
+atomic_t reset_pending = ATOMIC_INIT(0);
 
 module_param_named(msg_level, mtk_msg_level, int, 0);
 MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
@@ -338,6 +339,7 @@
 	struct mtk_eth *eth = mac->hw;
 	u32 sid, i;
 	int val = 0, ge_mode, err = 0;
+	unsigned int mac_type = mac->type;
 
 	/* MT76x8 has no hardware settings between for the MAC */
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
@@ -358,6 +360,7 @@
 		case PHY_INTERFACE_MODE_MII:
 		case PHY_INTERFACE_MODE_REVMII:
 		case PHY_INTERFACE_MODE_RMII:
+			mac->type = MTK_GDM_TYPE;
 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) {
 				err = mtk_gmac_rgmii_path_setup(eth, mac->id);
 				if (err)
@@ -367,6 +370,7 @@
 		case PHY_INTERFACE_MODE_1000BASEX:
 		case PHY_INTERFACE_MODE_2500BASEX:
 		case PHY_INTERFACE_MODE_SGMII:
+			mac->type = MTK_GDM_TYPE;
 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
 				err = mtk_gmac_sgmii_path_setup(eth, mac->id);
 				if (err)
@@ -374,6 +378,7 @@
 			}
 			break;
 		case PHY_INTERFACE_MODE_GMII:
+			mac->type = MTK_GDM_TYPE;
 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) {
 				err = mtk_gmac_gephy_path_setup(eth, mac->id);
 				if (err)
@@ -381,6 +386,7 @@
 			}
 			break;
 		case PHY_INTERFACE_MODE_XGMII:
+			mac->type = MTK_XGDM_TYPE;
 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_XGMII)) {
 				err = mtk_gmac_xgmii_path_setup(eth, mac->id);
 				if (err)
@@ -390,6 +396,7 @@
 		case PHY_INTERFACE_MODE_USXGMII:
 		case PHY_INTERFACE_MODE_10GKR:
 		case PHY_INTERFACE_MODE_5GBASER:
+			mac->type = MTK_XGDM_TYPE;
 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) {
 				err = mtk_gmac_usxgmii_path_setup(eth, mac->id);
 				if (err)
@@ -528,6 +535,29 @@
 				break;
 			}
 		}
+	} else if (mac->type == MTK_GDM_TYPE) {
+		val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac->id));
+		mtk_w32(eth, val & ~MTK_GDMA_XGDM_SEL,
+			MTK_GDMA_EG_CTRL(mac->id));
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+			switch (mac->id) {
+			case MTK_GMAC3_ID:
+				val = mtk_r32(eth, MTK_XGMAC_STS(mac->id));
+				mtk_w32(eth, val & ~MTK_XGMAC_FORCE_LINK,
+					MTK_XGMAC_STS(mac->id));
+				break;
+			}
+		}
+
+		if (mac->type != mac_type) {
+			if (atomic_read(&reset_pending) == 0) {
+				atomic_inc(&force);
+				schedule_work(&eth->pending_work);
+				atomic_inc(&reset_pending);
+			} else
+				atomic_dec(&reset_pending);
+		}
 	}
 
 	return;
@@ -571,6 +601,7 @@
 			break;
 		}
 
+		state->interface = mac->interface;
 		state->link = FIELD_GET(MTK_USXGMII_PCS_LINK, sts);
 	} else if (mac->type == MTK_GDM_TYPE) {
 		struct mtk_eth *eth = mac->hw;
@@ -581,6 +612,7 @@
 
 		regmap_read(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, &val);
 
+		state->interface = mac->interface;
 		state->link = FIELD_GET(SGMII_LINK_STATYS, val);
 
 		if (FIELD_GET(SGMII_AN_ENABLE, val)) {
diff --git a/target/linux/mediatek/patches-5.4/754-net-phy-add-5GBASER.patch b/target/linux/mediatek/patches-5.4/754-net-phy-add-5GBASER.patch
index a449bcc..8165303 100644
--- a/target/linux/mediatek/patches-5.4/754-net-phy-add-5GBASER.patch
+++ b/target/linux/mediatek/patches-5.4/754-net-phy-add-5GBASER.patch
@@ -1,3 +1,25 @@
+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
+index daed73a..7d080d5 100644
+--- a/drivers/net/phy/marvell10g.c
++++ b/drivers/net/phy/marvell10g.c
+@@ -516,6 +516,7 @@ static void mv3310_update_interface(struct phy_device *phydev)
+ 
+ 	if ((phydev->interface == PHY_INTERFACE_MODE_SGMII ||
+ 	     phydev->interface == PHY_INTERFACE_MODE_2500BASEX ||
++	     phydev->interface == PHY_INTERFACE_MODE_5GBASER ||
+ 	     phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) {
+ 		/* The PHY automatically switches its serdes interface (and
+ 		 * active PHYXS instance) between Cisco SGMII, 10GBase-KR and
+@@ -527,6 +528,9 @@ static void mv3310_update_interface(struct phy_device *phydev)
+ 		case SPEED_10000:
+ 			phydev->interface = PHY_INTERFACE_MODE_10GKR;
+ 			break;
++		case SPEED_5000:
++			phydev->interface = PHY_INTERFACE_MODE_5GBASER;
++			break;
+ 		case SPEED_2500:
+ 			phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+ 			break;
 diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
 index b3f25a9..6a38a1c 100644
 --- a/drivers/net/phy/phylink.c
diff --git a/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch b/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
index ee68b4e..6233046 100644
--- a/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
+++ b/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
@@ -370,6 +370,140 @@
 +			       enum mdio_i2c_proto protocol);
  
  #endif
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index f360d92..67f34ed 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -483,62 +483,105 @@ static void phylink_resolve(struct work_struct *w)
+ 	struct phylink *pl = container_of(w, struct phylink, resolve);
+ 	struct phylink_link_state link_state;
+ 	struct net_device *ndev = pl->netdev;
+-	int link_changed;
++	bool mac_config = false;
++	bool retrigger = false;
++	bool cur_link_state;
+ 
+ 	mutex_lock(&pl->state_mutex);
++	if (pl->netdev)
++		cur_link_state = netif_carrier_ok(ndev);
++	else
++		cur_link_state = pl->old_link_state;
++
+ 	if (pl->phylink_disable_state) {
+ 		pl->mac_link_dropped = false;
+ 		link_state.link = false;
+ 	} else if (pl->mac_link_dropped) {
+ 		link_state.link = false;
++		retrigger = true;
+ 	} else {
+ 		switch (pl->cur_link_an_mode) {
+ 		case MLO_AN_PHY:
+ 			link_state = pl->phy_state;
+ 			phylink_resolve_flow(pl, &link_state);
+-			phylink_mac_config_up(pl, &link_state);
++			mac_config = link_state.link;
+ 			break;
+ 
+ 		case MLO_AN_FIXED:
+ 			phylink_get_fixed_state(pl, &link_state);
+-			phylink_mac_config_up(pl, &link_state);
++			mac_config = link_state.link;
+ 			break;
+ 
+ 		case MLO_AN_INBAND:
+ 			phylink_get_mac_state(pl, &link_state);
+ 
++			/* The PCS may have a latching link-fail indicator.
++			 * If the link was up, bring the link down and
++			 * re-trigger the resolve. Otherwise, re-read the
++			 * PCS state to get the current status of the link.
++			 */
++			if (!link_state.link) {
++				if (cur_link_state)
++					retrigger = true;
++				else
++					phylink_get_mac_state(pl,
++							      &link_state);
++			}
++
+ 			/* If we have a phy, the "up" state is the union of
+-			 * both the PHY and the MAC */
++			 * both the PHY and the MAC
++			 */
+ 			if (pl->phydev)
+ 				link_state.link &= pl->phy_state.link;
+ 
+ 			/* Only update if the PHY link is up */
+ 			if (pl->phydev && pl->phy_state.link) {
++				/* If the interface has changed, force a
++				 * link down event if the link isn't already
++				 * down, and re-resolve.
++				 */
++				if (link_state.interface !=
++				    pl->phy_state.interface) {
++					retrigger = true;
++					link_state.link = false;
++				}
+ 				link_state.interface = pl->phy_state.interface;
+ 
+ 				/* If we have a PHY, we need to update with
+-				 * the pause mode bits. */
+-				link_state.pause |= pl->phy_state.pause;
+-				phylink_resolve_flow(pl, &link_state);
+-				phylink_mac_config(pl, &link_state);
++				 * the PHY flow control bits.
++				 */
++				link_state.pause = pl->phy_state.pause;
++				mac_config = true;
+ 			}
++			phylink_resolve_flow(pl, &link_state);
+ 			break;
+ 		}
+ 	}
+ 
+-	if (pl->netdev)
+-		link_changed = (link_state.link != netif_carrier_ok(ndev));
+-	else
+-		link_changed = (link_state.link != pl->old_link_state);
++	if (mac_config) {
++		if (link_state.interface != pl->link_config.interface) {
++			/* The interface has changed, force the link down and
++			 * then reconfigure.
++			 */
++			if (cur_link_state) {
++				phylink_mac_link_down(pl);
++				cur_link_state = false;
++			}
++			phylink_mac_config(pl, &link_state);
++			pl->link_config.interface = link_state.interface;
++		} else {
++			phylink_mac_config(pl, &link_state);
++		}
++	}
+ 
+-	if (link_changed) {
++	if (link_state.link != cur_link_state) {
+ 		pl->old_link_state = link_state.link;
+ 		if (!link_state.link)
+ 			phylink_mac_link_down(pl);
+ 		else
+ 			phylink_mac_link_up(pl, link_state);
+ 	}
+-	if (!link_state.link && pl->mac_link_dropped) {
++	if (!link_state.link && retrigger) {
+ 		pl->mac_link_dropped = false;
+ 		queue_work(system_power_efficient_wq, &pl->resolve);
+ 	}
+@@ -1014,7 +1057,8 @@ void phylink_start(struct phylink *pl)
+ 		if (irq <= 0)
+ 			mod_timer(&pl->link_poll, jiffies + HZ);
+ 	}
+-	if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
++	if ((pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ||
++	    (pl->cfg_link_an_mode == MLO_AN_INBAND))
+ 		mod_timer(&pl->link_poll, jiffies + HZ);
+ 	if (pl->phydev)
+ 		phy_start(pl->phydev);
 diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
 index 42f0441..0d5ac2a 100644
 --- a/drivers/net/phy/sfp-bus.c
@@ -552,7 +686,7 @@
  
  #if IS_ENABLED(CONFIG_HWMON)
  	struct sfp_diag diag;
-@@ -303,6 +313,135 @@ static const struct of_device_id sfp_of_match[] = {
+@@ -303,6 +313,136 @@ static const struct of_device_id sfp_of_match[] = {
  };
  MODULE_DEVICE_TABLE(of, sfp_of_match);
  
@@ -636,6 +770,7 @@
 +
 +	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
 +
++	SFP_QUIRK_F("ETU", "ESP-T5-R", sfp_fixup_rollball_cc),
 +	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
 +	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
 +	SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),