summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2020-07-09 15:38:58 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2020-07-09 17:40:55 +0100
commit2dded950df454fd3d9333754e4e8da0f03b06a64 (patch)
tree017453ba07adfa661de6ff33ad473e38a89b0e24
parentc4af6df619fafe9d96f5afc7f9070e3a830984d8 (diff)
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 <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c53
1 files 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;
}