aboutsummaryrefslogtreecommitdiff
path: root/pkgs/patches-linux-5.15/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/patches-linux-5.15/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch')
-rw-r--r--pkgs/patches-linux-5.15/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch131
1 files changed, 131 insertions, 0 deletions
diff --git a/pkgs/patches-linux-5.15/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch b/pkgs/patches-linux-5.15/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch
new file mode 100644
index 0000000..09797ae
--- /dev/null
+++ b/pkgs/patches-linux-5.15/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch
@@ -0,0 +1,131 @@
+From ba3c01ee02ed0d821c9f241f179bbc9457542b8f Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Sun, 10 Oct 2021 00:46:15 +0200
+Subject: net: phy: at803x: fix resume for QCA8327 phy
+
+From Documentation phy resume triggers phy reset and restart
+auto-negotiation. Add a dedicated function to wait reset to finish as
+it was notice a regression where port sometime are not reliable after a
+suspend/resume session. The reset wait logic is copied from phy_poll_reset.
+Add dedicated suspend function to use genphy_suspend only with QCA8337
+phy and set only additional debug settings for QCA8327. With more test
+it was reported that QCA8327 doesn't proprely support this mode and
+using this cause the unreliability of the switch ports, especially the
+malfunction of the port0.
+
+Fixes: 15b9df4ece17 ("net: phy: at803x: add resume/suspend function to qca83xx phy")
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/at803x.c | 69 +++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 63 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -92,9 +92,14 @@
+ #define AT803X_DEBUG_REG_5 0x05
+ #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
+
++#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
++#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
++#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
++
+ #define AT803X_DEBUG_REG_3C 0x3C
+
+ #define AT803X_DEBUG_REG_3D 0x3D
++#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
+
+ #define AT803X_DEBUG_REG_1F 0x1F
+ #define AT803X_DEBUG_PLL_ON BIT(2)
+@@ -1304,6 +1309,58 @@ static int qca83xx_config_init(struct ph
+ return 0;
+ }
+
++static int qca83xx_resume(struct phy_device *phydev)
++{
++ int ret, val;
++
++ /* Skip reset if not suspended */
++ if (!phydev->suspended)
++ return 0;
++
++ /* Reinit the port, reset values set by suspend */
++ qca83xx_config_init(phydev);
++
++ /* Reset the port on port resume */
++ phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
++
++ /* On resume from suspend the switch execute a reset and
++ * restart auto-negotiation. Wait for reset to complete.
++ */
++ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
++ 50000, 600000, true);
++ if (ret)
++ return ret;
++
++ msleep(1);
++
++ return 0;
++}
++
++static int qca83xx_suspend(struct phy_device *phydev)
++{
++ u16 mask = 0;
++
++ /* Only QCA8337 support actual suspend.
++ * QCA8327 cause port unreliability when phy suspend
++ * is set.
++ */
++ if (phydev->drv->phy_id == QCA8337_PHY_ID) {
++ genphy_suspend(phydev);
++ } else {
++ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
++ phy_modify(phydev, MII_BMCR, mask, 0);
++ }
++
++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D,
++ AT803X_DEBUG_GATE_CLK_IN1000, 0);
++
++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
++ AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
++ AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
++
++ return 0;
++}
++
+ static struct phy_driver at803x_driver[] = {
+ {
+ /* Qualcomm Atheros AR8035 */
+@@ -1413,8 +1470,8 @@ static struct phy_driver at803x_driver[]
+ .get_sset_count = at803x_get_sset_count,
+ .get_strings = at803x_get_strings,
+ .get_stats = at803x_get_stats,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
++ .suspend = qca83xx_suspend,
++ .resume = qca83xx_resume,
+ }, {
+ /* QCA8327-A from switch QCA8327-AL1A */
+ .phy_id = QCA8327_A_PHY_ID,
+@@ -1428,8 +1485,8 @@ static struct phy_driver at803x_driver[]
+ .get_sset_count = at803x_get_sset_count,
+ .get_strings = at803x_get_strings,
+ .get_stats = at803x_get_stats,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
++ .suspend = qca83xx_suspend,
++ .resume = qca83xx_resume,
+ }, {
+ /* QCA8327-B from switch QCA8327-BL1A */
+ .phy_id = QCA8327_B_PHY_ID,
+@@ -1443,8 +1500,8 @@ static struct phy_driver at803x_driver[]
+ .get_sset_count = at803x_get_sset_count,
+ .get_strings = at803x_get_strings,
+ .get_stats = at803x_get_stats,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
++ .suspend = qca83xx_suspend,
++ .resume = qca83xx_resume,
+ }, };
+
+ module_phy_driver(at803x_driver);