forked from coolsnowwolf/lede
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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@makrotopia.org>
- Loading branch information
Showing
1 changed file
with
166 additions
and
0 deletions.
There are no files selected for viewing
166 changes: 166 additions & 0 deletions
166
target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |