Skip to content

Commit

Permalink
kernel: 5.10: backport QCA83x PHY resume fix, DAC amplitude preferred…
Browse files Browse the repository at this point in the history
… master, debug reg names

Backport workaround for QCA8327 PHY resume, which does not properly support
genphy_suspend/resume. Also add DAC amplitude fix for the QCA8327 PHY,
set port to preferred master and add proper names to debug regs.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
  • Loading branch information
clayface authored and hauke committed Oct 24, 2021
1 parent dee8192 commit d888ef5
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 2 deletions.
@@ -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);
@@ -0,0 +1,91 @@
From 1ca8311949aec5c9447645731ef1c6bc5bd71350 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 10 Oct 2021 00:46:16 +0200
Subject: net: phy: at803x: add DAC amplitude fix for 8327 phy

QCA8327 internal phy require DAC amplitude adjustement set to +6% with
100m speed. Also add additional define to report a change of the same
reg in QCA8337. (different scope it does set 1000m voltage)
Add link_change_notify function to set the proper amplitude adjustement
on PHY_RUNNING state and disable on any other state.

Fixes: b4df02b562f4 ("net: phy: at803x: add support for qca 8327 A variant internal phy")
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -87,6 +87,8 @@
#define AT803X_PSSR_MR_AN_COMPLETE 0x0200

#define AT803X_DEBUG_REG_0 0x00
+#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
+#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)

#define AT803X_DEBUG_REG_5 0x05
@@ -1222,9 +1224,37 @@ static int qca83xx_config_init(struct ph
break;
}

+ /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
+ * Disable on init and enable only with 100m speed following
+ * qca original source code.
+ */
+ if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
+ phydev->drv->phy_id == QCA8327_B_PHY_ID)
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
+
return 0;
}

+static void qca83xx_link_change_notify(struct phy_device *phydev)
+{
+ /* QCA8337 doesn't require DAC Amplitude adjustement */
+ if (phydev->drv->phy_id == QCA8337_PHY_ID)
+ return;
+
+ /* Set DAC Amplitude adjustment to +6% for 100m on link running */
+ if (phydev->state == PHY_RUNNING) {
+ if (phydev->speed == SPEED_100)
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ QCA8327_DEBUG_MANU_CTRL_EN,
+ QCA8327_DEBUG_MANU_CTRL_EN);
+ } else {
+ /* Reset DAC Amplitude adjustment */
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
+ }
+}
+
static int qca83xx_resume(struct phy_device *phydev)
{
int ret, val;
@@ -1379,6 +1409,7 @@ static struct phy_driver at803x_driver[]
.phy_id_mask = QCA8K_PHY_ID_MASK,
.name = "Qualcomm Atheros 8337 internal PHY",
/* PHY_GBIT_FEATURES */
+ .link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
@@ -1394,6 +1425,7 @@ static struct phy_driver at803x_driver[]
.phy_id_mask = QCA8K_PHY_ID_MASK,
.name = "Qualcomm Atheros 8327-A internal PHY",
/* PHY_GBIT_FEATURES */
+ .link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
@@ -1409,6 +1441,7 @@ static struct phy_driver at803x_driver[]
.phy_id_mask = QCA8K_PHY_ID_MASK,
.name = "Qualcomm Atheros 8327-B internal PHY",
/* PHY_GBIT_FEATURES */
+ .link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
@@ -0,0 +1,27 @@
From 9d1c29b4028557a496be9c5eb2b4b86063700636 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 10 Oct 2021 00:46:17 +0200
Subject: net: phy: at803x: enable prefer master for 83xx internal phy

From original QCA source code the port was set to prefer master as port
type in 1000BASE-T mode. Apply the same settings also here.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 3 +++
1 file changed, 3 insertions(+)

--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -1233,6 +1233,9 @@ static int qca83xx_config_init(struct ph
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
QCA8327_DEBUG_MANU_CTRL_EN, 0);

+ /* Following original QCA sourcecode set port to prefer master */
+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
+
return 0;
}

@@ -0,0 +1,127 @@
From 67999555ff42e91de7654488d9a7735bd9e84555 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 10 Oct 2021 00:46:18 +0200
Subject: net: phy: at803x: better describe debug regs

Give a name to known debug regs from Documentation instead of using
unknown hex values.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)

--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -86,12 +86,12 @@
#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
#define AT803X_PSSR_MR_AN_COMPLETE 0x0200

-#define AT803X_DEBUG_REG_0 0x00
+#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)

-#define AT803X_DEBUG_REG_5 0x05
+#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)

#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
@@ -100,7 +100,7 @@

#define AT803X_DEBUG_REG_3C 0x3C

-#define AT803X_DEBUG_REG_3D 0x3D
+#define AT803X_DEBUG_REG_GREEN 0x3D
#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)

#define AT803X_DEBUG_REG_1F 0x1F
@@ -274,25 +274,25 @@ static int at803x_read_page(struct phy_d

static int at803x_enable_rx_delay(struct phy_device *phydev)
{
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0,
AT803X_DEBUG_RX_CLK_DLY_EN);
}

static int at803x_enable_tx_delay(struct phy_device *phydev)
{
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0,
AT803X_DEBUG_TX_CLK_DLY_EN);
}

static int at803x_disable_rx_delay(struct phy_device *phydev)
{
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
AT803X_DEBUG_RX_CLK_DLY_EN, 0);
}

static int at803x_disable_tx_delay(struct phy_device *phydev)
{
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE,
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
}

@@ -1208,9 +1208,9 @@ static int qca83xx_config_init(struct ph
switch (switch_revision) {
case 1:
/* For 100M waveform */
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
/* Turn on Gigabit clock */
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
break;

case 2:
@@ -1218,8 +1218,8 @@ static int qca83xx_config_init(struct ph
fallthrough;
case 4:
phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
break;
}
@@ -1230,7 +1230,7 @@ static int qca83xx_config_init(struct ph
*/
if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
phydev->drv->phy_id == QCA8327_B_PHY_ID)
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
QCA8327_DEBUG_MANU_CTRL_EN, 0);

/* Following original QCA sourcecode set port to prefer master */
@@ -1248,12 +1248,12 @@ static void qca83xx_link_change_notify(s
/* Set DAC Amplitude adjustment to +6% for 100m on link running */
if (phydev->state == PHY_RUNNING) {
if (phydev->speed == SPEED_100)
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
QCA8327_DEBUG_MANU_CTRL_EN,
QCA8327_DEBUG_MANU_CTRL_EN);
} else {
/* Reset DAC Amplitude adjustment */
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
QCA8327_DEBUG_MANU_CTRL_EN, 0);
}
}
@@ -1300,7 +1300,7 @@ static int qca83xx_suspend(struct phy_de
phy_modify(phydev, MII_BMCR, mask, 0);
}

- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D,
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
AT803X_DEBUG_GATE_CLK_IN1000, 0);

at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
Expand Up @@ -20,7 +20,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>

--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -1025,6 +1025,34 @@ static int at803x_set_tunable(struct phy
@@ -1032,6 +1032,34 @@ static int at803x_set_tunable(struct phy
}
}

Expand Down Expand Up @@ -55,7 +55,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
static int at803x_cable_test_result_trans(u16 status)
{
switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
@@ -1274,7 +1302,7 @@ static struct phy_driver at803x_driver[]
@@ -1364,7 +1392,7 @@ static struct phy_driver at803x_driver[]
.resume = at803x_resume,
.read_page = at803x_read_page,
.write_page = at803x_write_page,
Expand Down

0 comments on commit d888ef5

Please sign in to comment.