[openwrt/openwrt] mediatek: simplify MaxLinear GPY PHY driver

LEDE Commits lede-commits at lists.infradead.org
Mon Mar 27 16:58:30 PDT 2023


dangole pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/ad962c90c3b48f6cfa93bbd838526ab855f1c773

commit ad962c90c3b48f6cfa93bbd838526ab855f1c773
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Sat Mar 11 03:51:00 2023 +0000

    mediatek: simplify MaxLinear GPY PHY driver
    
    The mxl-gpy driver apparently was built in the assumption that SGMII
    auto-negotiation is always switched on at the MAC. This may be true for
    few rather recent drivers (why?), but certainly isn't for most drivers
    unless 'managed = "in-band-status"' is set in device tree. Add patch to
    the mediatek target which reduces mxl-gpy to behave more like an
    ordinary PHY driver using out-of-band status.
    
    This allows to use these PHYs without rate-adaptation which seems to be
    at least partially broken/racy in some revisions of the PHY and/or
    internal PHY firmware.
    
    Signed-off-by: Daniel Golle <daniel at makrotopia.org>
---
 ...731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch | 166 +++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch b/target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch
new file mode 100644
index 0000000000..2e39ca3c26
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch
@@ -0,0 +1,166 @@
+--- a/drivers/net/phy/mxl-gpy.c
++++ b/drivers/net/phy/mxl-gpy.c
+@@ -126,6 +126,12 @@ static int gpy_config_init(struct phy_de
+ 	if (ret < 0)
+ 		return ret;
+ 
++	/* Disable SGMII auto-negotiation */
++	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
++			     VSPEC1_SGMII_CTRL_ANEN, 0);
++	if (ret < 0)
++		return ret;
++
+ 	return gpy_led_write(phydev);
+ }
+ 
+@@ -151,65 +157,6 @@ static int gpy_probe(struct phy_device *
+ 	return 0;
+ }
+ 
+-static bool gpy_sgmii_need_reaneg(struct phy_device *phydev)
+-{
+-	int fw_ver, fw_type, fw_minor;
+-	size_t i;
+-
+-	fw_ver = phy_read(phydev, PHY_FWV);
+-	if (fw_ver < 0)
+-		return true;
+-
+-	fw_type = FIELD_GET(PHY_FWV_TYPE_MASK, fw_ver);
+-	fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_ver);
+-
+-	for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) {
+-		if (fw_type != ver_need_sgmii_reaneg[i].type)
+-			continue;
+-		if (fw_minor < ver_need_sgmii_reaneg[i].minor)
+-			return true;
+-		break;
+-	}
+-
+-	return false;
+-}
+-
+-static bool gpy_2500basex_chk(struct phy_device *phydev)
+-{
+-	int ret;
+-
+-	ret = phy_read(phydev, PHY_MIISTAT);
+-	if (ret < 0) {
+-		phydev_err(phydev, "Error: MDIO register access failed: %d\n",
+-			   ret);
+-		return false;
+-	}
+-
+-	if (!(ret & PHY_MIISTAT_LS) ||
+-	    FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500)
+-		return false;
+-
+-	phydev->speed = SPEED_2500;
+-	phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
+-		       VSPEC1_SGMII_CTRL_ANEN, 0);
+-	return true;
+-}
+-
+-static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
+-{
+-	int ret;
+-
+-	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL);
+-	if (ret < 0) {
+-		phydev_err(phydev, "Error: MMD register access failed: %d\n",
+-			   ret);
+-		return true;
+-	}
+-
+-	return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
+-}
+-
+ static int gpy_config_aneg(struct phy_device *phydev)
+ {
+ 	bool changed = false;
+@@ -248,53 +195,11 @@ static int gpy_config_aneg(struct phy_de
+ 	    phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
+ 		return 0;
+ 
+-	/* No need to trigger re-ANEG if link speed is 2.5G or SGMII ANEG is
+-	 * disabled.
+-	 */
+-	if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) ||
+-	    !gpy_sgmii_aneg_en(phydev))
+-		return 0;
+-
+-	/* There is a design constraint in GPY2xx device where SGMII AN is
+-	 * only triggered when there is change of speed. If, PHY link
+-	 * partner`s speed is still same even after PHY TPI is down and up
+-	 * again, SGMII AN is not triggered and hence no new in-band message
+-	 * from GPY to MAC side SGMII.
+-	 * This could cause an issue during power up, when PHY is up prior to
+-	 * MAC. At this condition, once MAC side SGMII is up, MAC side SGMII
+-	 * wouldn`t receive new in-band message from GPY with correct link
+-	 * status, speed and duplex info.
+-	 *
+-	 * 1) If PHY is already up and TPI link status is still down (such as
+-	 *    hard reboot), TPI link status is polled for 4 seconds before
+-	 *    retriggerring SGMII AN.
+-	 * 2) If PHY is already up and TPI link status is also up (such as soft
+-	 *    reboot), polling of TPI link status is not needed and SGMII AN is
+-	 *    immediately retriggered.
+-	 * 3) Other conditions such as PHY is down, speed change etc, skip
+-	 *    retriggering SGMII AN. Note: in case of speed change, GPY FW will
+-	 *    initiate SGMII AN.
+-	 */
+-
+-	if (phydev->state != PHY_UP)
+-		return 0;
+-
+-	ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS,
+-				    20000, 4000000, false);
+-	if (ret == -ETIMEDOUT)
+-		return 0;
+-	else if (ret < 0)
+-		return ret;
+-
+-	/* Trigger SGMII AN. */
+-	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
+-			      VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
++	return 0;
+ }
+ 
+ static void gpy_update_interface(struct phy_device *phydev)
+ {
+-	int ret;
+-
+ 	/* Interface mode is fixed for USXGMII and integrated PHY */
+ 	if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
+ 	    phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
+@@ -306,29 +211,11 @@ static void gpy_update_interface(struct
+ 	switch (phydev->speed) {
+ 	case SPEED_2500:
+ 		phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+-		ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
+-				     VSPEC1_SGMII_CTRL_ANEN, 0);
+-		if (ret < 0)
+-			phydev_err(phydev,
+-				   "Error: Disable of SGMII ANEG failed: %d\n",
+-				   ret);
+ 		break;
+ 	case SPEED_1000:
+ 	case SPEED_100:
+ 	case SPEED_10:
+ 		phydev->interface = PHY_INTERFACE_MODE_SGMII;
+-		if (gpy_sgmii_aneg_en(phydev))
+-			break;
+-		/* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed
+-		 * if ANEG is disabled (in 2500-BaseX mode).
+-		 */
+-		ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
+-				     VSPEC1_SGMII_ANEN_ANRS,
+-				     VSPEC1_SGMII_ANEN_ANRS);
+-		if (ret < 0)
+-			phydev_err(phydev,
+-				   "Error: Enable of SGMII ANEG failed: %d\n",
+-				   ret);
+ 		break;
+ 	}
+ }




More information about the lede-commits mailing list