kernel: add pending mtk_sgmii and phy improvements from @lynxis

Add pending patches from Alexander 'lynxis' Couzens which are required
for RealTek NBase-T PHYs or SFP+ cages to work when connected to the
SGMII interface provided by recent MediaTek SoCs [1].
The patches for MT753x fix link speed limitation on CPU ports observed
by many users which is due to reset being carried out wrongly [2].

[1]: https://patchwork.kernel.org/project/netdevbpf/list/?series=669488&state=*
[2]: https://patchwork.kernel.org/project/netdevbpf/list/?series=669486&state=*

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2022-08-15 18:50:10 +02:00
parent aab466f422
commit e504fdae4e
10 changed files with 467 additions and 0 deletions

View File

@ -0,0 +1,101 @@
From ace6abaa0f9203083fe4c0a6a74da2d96410b625 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Sat, 13 Aug 2022 12:49:33 +0200
Subject: [PATCH 01/10] net: phy: realtek: rtl8221: allow to configure SERDES
mode
The rtl8221 supports multiple SERDES modes:
- SGMII
- 2500base-x
- HiSGMII
Further it supports rate adaption on SERDES links to allow
slow ethernet speeds (10/100/1000mbit) to work on 2500base-x/HiSGMII
links without reducing the SERDES speed.
When operating without rate adapters the SERDES link will follow the
ethernet speed.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/phy/realtek.c | 48 +++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -53,6 +53,15 @@
RTL8201F_ISR_LINK)
#define RTL8201F_IER 0x13
+#define RTL8221B_MMD_SERDES_CTRL MDIO_MMD_VEND1
+#define RTL8221B_MMD_PHY_CTRL MDIO_MMD_VEND2
+#define RTL8221B_SERDES_OPTION 0x697a
+#define RTL8221B_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII 0
+#define RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII 1
+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX 2
+#define RTL8221B_SERDES_OPTION_MODE_HISGMII 3
+
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -841,6 +850,43 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
+static int rtl8221b_config_init(struct phy_device *phydev)
+{
+ u16 option_mode;
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII;
+ break;
+ default:
+ return 0;
+ }
+
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL,
+ 0x75f3, 0);
+
+ phy_modify_mmd_changed(phydev, RTL8221B_MMD_SERDES_CTRL,
+ RTL8221B_SERDES_OPTION,
+ RTL8221B_SERDES_OPTION_MODE_MASK, option_mode);
+ switch (option_mode) {
+ case RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII:
+ case RTL8221B_SERDES_OPTION_MODE_2500BASEX:
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd455);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020);
+ break;
+ case RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII:
+ case RTL8221B_SERDES_OPTION_MODE_HISGMII:
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd433);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020);
+ break;
+ }
+
+ return 0;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -981,6 +1027,7 @@ static struct phy_driver realtek_drvs[]
PHY_ID_MATCH_EXACT(0x001cc849),
.name = "RTL8221B-VB-CG 2.5Gbps PHY",
.get_features = rtl822x_get_features,
+ .config_init = rtl8221b_config_init,
.config_aneg = rtl822x_config_aneg,
.read_status = rtl822x_read_status,
.suspend = genphy_suspend,
@@ -992,6 +1039,7 @@ static struct phy_driver realtek_drvs[]
.name = "RTL8221B-VM-CG 2.5Gbps PHY",
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
+ .config_init = rtl8221b_config_init,
.read_status = rtl822x_read_status,
.suspend = genphy_suspend,
.resume = rtlgen_resume,

View File

@ -0,0 +1,67 @@
From 9fec662b54fc956b776df15c704e996c61292850 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Sat, 13 Aug 2022 13:05:09 +0200
Subject: [PATCH 02/10] net: mt7531: only do PLL once after the reset
Move the PLL init of the switch out of the pad configuration of the port
6 (usally cpu port).
Fix a unidirectional 100 mbit limitation on 1 gbit or 2.5 gbit links for
outbound traffic on port 5 or port 6.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/dsa/mt7530.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -506,14 +506,19 @@ static bool mt7531_dual_sgmii_supported(
static int
mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
{
- struct mt7530_priv *priv = ds->priv;
+ return 0;
+}
+
+static void
+mt7531_pll_setup(struct mt7530_priv *priv)
+{
u32 top_sig;
u32 hwstrap;
u32 xtal;
u32 val;
if (mt7531_dual_sgmii_supported(priv))
- return 0;
+ return;
val = mt7530_read(priv, MT7531_CREV);
top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
@@ -592,8 +597,6 @@ mt7531_pad_setup(struct dsa_switch *ds,
val |= EN_COREPLL;
mt7530_write(priv, MT7531_PLLGP_EN, val);
usleep_range(25, 35);
-
- return 0;
}
static void
@@ -2326,6 +2329,8 @@ mt7531_setup(struct dsa_switch *ds)
SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
SYS_CTRL_REG_RST);
+ mt7531_pll_setup(priv);
+
if (mt7531_dual_sgmii_supported(priv)) {
priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
@@ -2882,8 +2887,6 @@ mt7531_cpu_port_config(struct dsa_switch
case 6:
interface = PHY_INTERFACE_MODE_2500BASEX;
- mt7531_pad_setup(ds, interface);
-
priv->p6_interface = interface;
break;
default:

View File

@ -0,0 +1,28 @@
From 3fb8841513c4ec3a2e5d366df86230c45f239a57 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Sat, 13 Aug 2022 13:08:22 +0200
Subject: [PATCH 03/10] net: mt7531: ensure all MACs are powered down before
reset
The datasheet [1] explicit describes it as requirement for a reset.
[1] MT7531 Reference Manual for Development Board rev 1.0, page 735
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/dsa/mt7530.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2324,6 +2324,10 @@ mt7531_setup(struct dsa_switch *ds)
return -ENODEV;
}
+ /* all MACs must be forced link-down before sw reset */
+ for (i = 0; i < MT7530_NUM_PORTS; i++)
+ mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
+
/* Reset the switch through internal reset */
mt7530_write(priv, MT7530_SYS_CTRL,
SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |

View File

@ -0,0 +1,44 @@
From cbfed00575d15eafd85efd9619b7ecc0836a4aa7 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Sat, 13 Aug 2022 14:42:12 +0200
Subject: [PATCH 04/10] net: mtk_sgmii: implement mtk_pcs_ops
Implement mtk_pcs_ops for the SGMII pcs to read the current state
of the hardware.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
[added DUPLEX_FULL]
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -122,10 +122,26 @@ static void mtk_pcs_link_up(struct phyli
regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
}
+static void mtk_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state)
+{
+ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
+ unsigned int val;
+
+ regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
+ state->speed = val & RG_PHY_SPEED_3_125G ? SPEED_2500 : SPEED_1000;
+
+ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
+ state->an_complete = !!(val & SGMII_AN_COMPLETE);
+ state->link = !!(val & SGMII_LINK_STATYS);
+ state->duplex = DUPLEX_FULL;
+ state->pause = 0;
+}
+
static const struct phylink_pcs_ops mtk_pcs_ops = {
.pcs_config = mtk_pcs_config,
.pcs_an_restart = mtk_pcs_restart_an,
.pcs_link_up = mtk_pcs_link_up,
+ .pcs_get_state = mtk_pcs_get_state,
};
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)

View File

@ -0,0 +1,39 @@
From 7f75f43fe2159123baa101fcc8c6faa0b0a4c598 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Sat, 13 Aug 2022 14:48:51 +0200
Subject: [PATCH 05/10] net: mtk_sgmii: fix powering up the SGMII phy
There are certain race condition when the SGMII_PHYA_PWD register still
contains 0x9 which prevents the SGMII from working properly.
The SGMII still shows link but no traffic can flow.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -36,9 +36,7 @@ static int mtk_pcs_setup_mode_an(struct
val |= SGMII_AN_RESTART;
regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
- val &= ~SGMII_PHYA_PWD;
- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val);
+ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
return 0;
@@ -70,9 +68,7 @@ static int mtk_pcs_setup_mode_force(stru
regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
/* Release PHYA power down state */
- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
- val &= ~SGMII_PHYA_PWD;
- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val);
+ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
return 0;
}

View File

@ -0,0 +1,65 @@
From 9daea9b71d060d93d7394ac465b2e5ee0b7e7bca Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Mon, 15 Aug 2022 16:02:01 +0200
Subject: [PATCH 06/10] net: mtk_sgmii: ensure the SGMII PHY is powered down on
configuration
The code expect the PHY to be in power down (which is only true after reset).
Allow the changes of SGMII parameters more than once.
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -7,6 +7,7 @@
*
*/
+#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/phylink.h>
@@ -24,6 +25,9 @@ static int mtk_pcs_setup_mode_an(struct
{
unsigned int val;
+ /* PHYA power down */
+ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
+
/* Setup the link timer and QPHY power up inside SGMIISYS */
regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
SGMII_LINK_TIMER_DEFAULT);
@@ -36,6 +40,10 @@ static int mtk_pcs_setup_mode_an(struct
val |= SGMII_AN_RESTART;
regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
+ /* Release PHYA power down state
+ * unknown how much the QPHY needs but it is racy without a sleep
+ */
+ usleep_range(50, 100);
regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
return 0;
@@ -50,6 +58,9 @@ static int mtk_pcs_setup_mode_force(stru
{
unsigned int val;
+ /* PHYA power down */
+ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
+
regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
val &= ~RG_PHY_SPEED_MASK;
if (interface == PHY_INTERFACE_MODE_2500BASEX)
@@ -67,7 +78,10 @@ static int mtk_pcs_setup_mode_force(stru
val |= SGMII_SPEED_1000;
regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
- /* Release PHYA power down state */
+ /* Release PHYA power down state
+ * unknown how much the QPHY needs but it is racy without a sleep
+ */
+ usleep_range(50, 100);
regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
return 0;

View File

@ -0,0 +1,31 @@
From e4dca7affb8c03438b63bdb5fddefd6ad2431cfd Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Mon, 15 Aug 2022 14:59:29 +0200
Subject: [PATCH 07/10] net: mtk_sgmii: mtk_pcs_setup_mode_an: don't rely on
register defaults
Ensure autonegotiation is enabled.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -32,12 +32,13 @@ static int mtk_pcs_setup_mode_an(struct
regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
SGMII_LINK_TIMER_DEFAULT);
+ /* disable remote fault & enable auto neg */
regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
- val |= SGMII_REMOTE_FAULT_DIS;
+ val |= SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN;
regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
- val |= SGMII_AN_RESTART;
+ val |= SGMII_AN_RESTART | SGMII_AN_ENABLE;
regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
/* Release PHYA power down state

View File

@ -0,0 +1,47 @@
From 952b64575613d26163a5afa5ff8bfdb57840091b Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Mon, 15 Aug 2022 15:00:14 +0200
Subject: [PATCH 08/10] net: mtk_sgmii: set the speed according to the phy
interface in AN
The non auto-negotioting code path is setting the correct speed for the
interface. Ensure auto-negotiation code path is doing it as well.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -21,13 +21,20 @@ static struct mtk_pcs *pcs_to_mtk_pcs(st
}
/* For SGMII interface mode */
-static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs)
+static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs, phy_interface_t interface)
{
unsigned int val;
/* PHYA power down */
regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
+ /* Set SGMII phy speed */
+ regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
+ val &= ~RG_PHY_SPEED_MASK;
+ if (interface == PHY_INTERFACE_MODE_2500BASEX)
+ val |= RG_PHY_SPEED_3_125G;
+ regmap_write(mpcs->regmap, mpcs->ana_rgc3, val);
+
/* Setup the link timer and QPHY power up inside SGMIISYS */
regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
SGMII_LINK_TIMER_DEFAULT);
@@ -100,7 +107,7 @@ static int mtk_pcs_config(struct phylink
if (interface != PHY_INTERFACE_MODE_SGMII)
err = mtk_pcs_setup_mode_force(mpcs, interface);
else if (phylink_autoneg_inband(mode))
- err = mtk_pcs_setup_mode_an(mpcs);
+ err = mtk_pcs_setup_mode_an(mpcs, interface);
return err;
}

View File

@ -0,0 +1,22 @@
From 06773f19cffd6c9d34dcbc8320169afef5ab60ba Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Mon, 15 Aug 2022 13:58:07 +0200
Subject: [PATCH 09/10] net: mtk_eth_soc: improve comment
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -80,7 +80,8 @@ static int mtk_pcs_setup_mode_force(stru
val &= ~SGMII_AN_ENABLE;
regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
- /* Set the speed etc but leave the duplex unchanged */
+ /* Set the speed etc but leave the duplex unchanged.
+ * The SGMII mode for 2.5gbit is the same as for 1gbit, expect the speed in ANA_RGC3 */
regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK;
val |= SGMII_SPEED_1000;

View File

@ -0,0 +1,23 @@
From 95dcd0f223d7cab6e25bc19088016e5eb4ca1804 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Tue, 16 Aug 2022 00:22:11 +0200
Subject: [PATCH 10/10] mtk_sgmii: enable PCS polling to allow SFP work
Currently there is no IRQ handling (even the SGMII supports it).
Enable polling to support SFP ports.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/ethernet/mediatek/mtk_sgmii.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -180,6 +180,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss,
return PTR_ERR(ss->pcs[i].regmap);
ss->pcs[i].pcs.ops = &mtk_pcs_ops;
+ ss->pcs[i].pcs.poll = 1;
}
return 0;