From 8e18c5fef75debfae3531fbd6901f3bf317d91ed Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 9 Sep 2022 04:28:43 +0100 Subject: [PATCH] net: dsa: mt7530: add support for in-band link status To: linux-mediatek@lists.infradead.org, netdev@vger.kernel.org Cc: Russell King , Sean Wang , Landen Chao , DENG Qingfang , Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , David S. Miller , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Matthias Brugger , Philipp Zabel Read link status from SGMII PCS for in-band managed 2500Base-X and 1000Base-X connection on a MAC port of the MT7531. This is needed to get the SFP cage working which is connected to SGMII interface of port 5 of the MT7531 switch IC on the Bananapi BPi-R3 board. Signed-off-by: Daniel Golle --- drivers/net/dsa/mt7530.c | 48 +++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2703,9 +2703,6 @@ mt7531_mac_config(struct dsa_switch *ds, case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: - if (phylink_autoneg_inband(mode)) - return -EINVAL; - return mt7531_sgmii_setup_mode_force(priv, port, interface); default: return -EINVAL; @@ -2781,13 +2778,6 @@ unsupported: return; } - if (phylink_autoneg_inband(mode) && - state->interface != PHY_INTERFACE_MODE_SGMII) { - dev_err(ds->dev, "%s: in-band negotiation unsupported\n", - __func__); - return; - } - mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); mcr_new = mcr_cur; mcr_new &= ~PMCR_LINK_SETTINGS_MASK; @@ -2924,6 +2914,9 @@ static void mt753x_phylink_get_caps(stru config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; + if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port)) + config->mac_capabilities |= MAC_2500FD; + /* This driver does not make use of the speed, duplex, pause or the * advertisement in its mac_config, so it is safe to mark this driver * as non-legacy. @@ -3019,16 +3012,43 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 return 0; } +static void +mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, + struct phylink_link_state *state) +{ + unsigned int val; + + val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); + state->link = !!(val & MT7531_SGMII_LINK_STATUS); + if (!state->link) + return; + + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) + state->speed = SPEED_2500; + else + state->speed = SPEED_1000; + + state->duplex = DUPLEX_FULL; + state->pause = 0; +} + static void mt7531_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) { struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; int port = pcs_to_mt753x_pcs(pcs)->port; + unsigned int val; - if (state->interface == PHY_INTERFACE_MODE_SGMII) + if (state->interface == PHY_INTERFACE_MODE_SGMII) { mt7531_sgmii_pcs_get_state_an(priv, port, state); - else - state->link = false; + return; + } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || + (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { + mt7531_sgmii_pcs_get_state_inband(priv, port, state); + return; + } + + state->link = false; } static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, @@ -3069,6 +3089,8 @@ mt753x_setup(struct dsa_switch *ds) priv->pcs[i].pcs.ops = priv->info->pcs_ops; priv->pcs[i].priv = priv; priv->pcs[i].port = i; + if (mt753x_is_mac_port(i)) + priv->pcs[i].pcs.poll = 1; } ret = priv->info->sw_setup(ds);