kernel: 5.10: backport QCA83x PHY resume fix, DAC amplitude preferred master, debug...
[openwrt/openwrt.git] / target / linux / generic / backport-5.10 / 796-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch
diff --git a/target/linux/generic/backport-5.10/796-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch b/target/linux/generic/backport-5.10/796-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch
new file mode 100644 (file)
index 0000000..5dfe27d
--- /dev/null
@@ -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)
+@@ -1220,6 +1225,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 */
+@@ -1329,8 +1386,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,
+@@ -1344,8 +1401,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,
+@@ -1359,8 +1416,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);