]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
net: phy: at803x: fix resume for QCA8327 phy
authorAnsuel Smith <ansuelsmth@gmail.com>
Sat, 9 Oct 2021 22:46:15 +0000 (00:46 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 10 Oct 2021 10:27:42 +0000 (11:27 +0100)
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

index ae7e1f1c59f039cce05e96dea3cf075782bd7dc8..0b506af51a50577bb6db581bd6264d3f30437478 100644 (file)
 #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)
@@ -1315,6 +1320,58 @@ static int qca83xx_config_init(struct phy_device *phydev)
        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 */
@@ -1439,8 +1496,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,
@@ -1454,8 +1511,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,
@@ -1469,8 +1526,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);