From 2dded950df454fd3d9333754e4e8da0f03b06a64 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 9 Jul 2020 15:38:58 +0100 Subject: net: mvpp2: ensure the port is forced down while changing modes Ensure that the port is forced down while reconfiguring, controlling this via mac_prepare() and mac_finish() so that it is down while we are configuring our (future) PCS. Signed-off-by: Russell King --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 53 ++++++++++++++++++++----- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index b3feb52fe7e1..831cefa694a0 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -5014,9 +5014,7 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode, } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { /* SGMII in-band mode receives the speed and duplex from * the PHY. Flow control information is not received. */ - an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | - MVPP2_GMAC_FORCE_LINK_PASS | - MVPP2_GMAC_CONFIG_MII_SPEED | + an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED | MVPP2_GMAC_CONFIG_GMII_SPEED | MVPP2_GMAC_CONFIG_FULL_DUPLEX); an |= MVPP2_GMAC_IN_BAND_AUTONEG | @@ -5029,9 +5027,7 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode, * speed and full duplex here. */ ctrl0 |= MVPP2_GMAC_PORT_TYPE_MASK; - an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | - MVPP2_GMAC_FORCE_LINK_PASS | - MVPP2_GMAC_CONFIG_MII_SPEED | + an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED | MVPP2_GMAC_CONFIG_GMII_SPEED | MVPP2_GMAC_CONFIG_FULL_DUPLEX); an |= MVPP2_GMAC_IN_BAND_AUTONEG | @@ -5055,11 +5051,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode, if ((old_ctrl0 ^ ctrl0) & MVPP2_GMAC_PORT_TYPE_MASK || (old_ctrl2 ^ ctrl2) & MVPP2_GMAC_INBAND_AN_MASK || (old_an ^ an) & MVPP2_GMAC_AN_PORT_DOWN_MASK) { - /* Force link down */ - old_an &= ~MVPP2_GMAC_FORCE_LINK_PASS; - old_an |= MVPP2_GMAC_FORCE_LINK_DOWN; - writel(old_an, port->base + MVPP2_GMAC_AUTONEG_CONFIG); - /* Set the GMAC in a reset state - do this in a way that * ensures we clear it below. */ @@ -5087,6 +5078,7 @@ static int mvpp2_mac_prepare(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { struct mvpp2_port *port = mvpp2_phylink_to_port(config); + u32 val; /* Check for invalid configuration */ if (mvpp2_is_xlg(interface) && port->gop_id != 0) { @@ -5094,6 +5086,27 @@ static int mvpp2_mac_prepare(struct phylink_config *config, unsigned int mode, return -EINVAL; } + if (port->phy_interface != interface || + phylink_autoneg_inband(mode)) { + /* Force the link down when changing the interface or if in + * in-band mode to ensure we do not change the configuration + * while the hardware is indicating link is up. We force both + * XLG and GMAC down to ensure that they're both in a known + * state. + */ + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG); + val &= ~MVPP2_GMAC_FORCE_LINK_PASS; + val |= MVPP2_GMAC_FORCE_LINK_DOWN; + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); + + if (mvpp2_port_supports_xlg(port)) { + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + val &= ~MVPP22_XLG_CTRL0_FORCE_LINK_PASS; + val |= MVPP22_XLG_CTRL0_FORCE_LINK_DOWN; + writel(val, port->base + MVPP22_XLG_CTRL0_REG); + } + } + /* Make sure the port is disabled when reconfiguring the mode */ mvpp2_port_disable(port); @@ -5128,6 +5141,7 @@ static int mvpp2_mac_finish(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { struct mvpp2_port *port = mvpp2_phylink_to_port(config); + u32 val; if (port->priv->hw_version == MVPP22 && port->phy_interface != interface) { @@ -5142,6 +5156,23 @@ static int mvpp2_mac_finish(struct phylink_config *config, unsigned int mode, mvpp2_port_enable(port); + /* Allow the link to come up if in in-band mode, otherwise the + * link is forced via mac_link_down()/mac_link_up() + */ + if (phylink_autoneg_inband(mode)) { + if (mvpp2_is_xlg(interface)) { + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + val &= ~(MVPP22_XLG_CTRL0_FORCE_LINK_PASS | + MVPP22_XLG_CTRL0_FORCE_LINK_DOWN); + writel(val, port->base + MVPP22_XLG_CTRL0_REG); + } else { + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG); + val &= ~(MVPP2_GMAC_FORCE_LINK_PASS | + MVPP2_GMAC_FORCE_LINK_DOWN); + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); + } + } + return 0; } -- cgit