Commit 7ff82416 authored by Alexander Couzens's avatar Alexander Couzens Committed by Jakub Kicinski

net: mediatek: 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 changes of the SGMII parameters more than once.

Only power down when reconfiguring to avoid bouncing the link when there's
no reason to - based on code from Russell King.

There are cases when the SGMII_PHYA_PWD register contains 0x9 which
prevents SGMII from working. The SGMII still shows link but no traffic
can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was
taken from a good working state of the SGMII interface.

Fixes: 42c03844 ("net-next: mediatek: add support for MediaTek MT7622 SoC")
Suggested-by: default avatarRussell King (Oracle) <linux@armlinux.org.uk>
Signed-off-by: default avatarAlexander Couzens <lynxis@fe80.eu>
[ bmork: rebased and squashed into one patch ]
Reviewed-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Acked-by: default avatarDaniel Golle <daniel@makrotopia.org>
Tested-by: default avatarDaniel Golle <daniel@makrotopia.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent b0de13d3
...@@ -1036,11 +1036,13 @@ struct mtk_soc_data { ...@@ -1036,11 +1036,13 @@ struct mtk_soc_data {
* @regmap: The register map pointing at the range used to setup * @regmap: The register map pointing at the range used to setup
* SGMII modes * SGMII modes
* @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap
* @interface: Currently configured interface mode
* @pcs: Phylink PCS structure * @pcs: Phylink PCS structure
*/ */
struct mtk_pcs { struct mtk_pcs {
struct regmap *regmap; struct regmap *regmap;
u32 ana_rgc3; u32 ana_rgc3;
phy_interface_t interface;
struct phylink_pcs pcs; struct phylink_pcs pcs;
}; };
......
...@@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
int advertise, link_timer; int advertise, link_timer;
bool changed, use_an; bool changed, use_an;
if (interface == PHY_INTERFACE_MODE_2500BASEX)
rgc3 = RG_PHY_SPEED_3_125G;
else
rgc3 = 0;
advertise = phylink_mii_c22_pcs_encode_advertisement(interface, advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
advertising); advertising);
if (advertise < 0) if (advertise < 0)
...@@ -88,10 +83,23 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -88,10 +83,23 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
bmcr = 0; bmcr = 0;
} }
if (mpcs->interface != interface) {
/* PHYA power down */
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
SGMII_PHYA_PWD, SGMII_PHYA_PWD);
if (interface == PHY_INTERFACE_MODE_2500BASEX)
rgc3 = RG_PHY_SPEED_3_125G;
else
rgc3 = 0;
/* Configure the underlying interface speed */ /* Configure the underlying interface speed */
regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
RG_PHY_SPEED_3_125G, rgc3); RG_PHY_SPEED_3_125G, rgc3);
mpcs->interface = interface;
}
/* Update the advertisement, noting whether it has changed */ /* Update the advertisement, noting whether it has changed */
regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
SGMII_ADVERTISE, advertise, &changed); SGMII_ADVERTISE, advertise, &changed);
...@@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr);
/* Release PHYA power down state */ /* Release PHYA power down state
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, * Only removing bit SGMII_PHYA_PWD isn't enough.
SGMII_PHYA_PWD, 0); * There are cases when the SGMII_PHYA_PWD register contains 0x9 which
* prevents SGMII from working. The SGMII still shows link but no traffic
* can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was
* taken from a good working state of the SGMII interface.
* Unknown how much the QPHY needs but it is racy without a sleep.
* Tested on mt7622 & mt7986.
*/
usleep_range(50, 100);
regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
return changed; return changed;
} }
...@@ -171,6 +187,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) ...@@ -171,6 +187,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
return PTR_ERR(ss->pcs[i].regmap); return PTR_ERR(ss->pcs[i].regmap);
ss->pcs[i].pcs.ops = &mtk_pcs_ops; ss->pcs[i].pcs.ops = &mtk_pcs_ops;
ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment