[][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(ð->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(ð->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),