From: Daniel Golle Date: Sat, 11 Mar 2023 03:51:00 +0000 (+0000) Subject: mediatek: simplify MaxLinear GPY PHY driver X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=ad962c90c3b48f6cfa93bbd838526ab855f1c773;p=openwrt%2Fstaging%2Fnbd.git 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 --- 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; + } + }