summaryrefslogtreecommitdiff
path: root/drivers/net/pcs
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2021-06-11 23:05:23 +0300
committerDavid S. Miller <davem@davemloft.net>2021-06-11 13:43:55 -0700
commit2031c09e6d5f50d4c337da11efd1deb8279687d6 (patch)
treea3d7e8d974d4f58565127680dd89b485b9f66618 /drivers/net/pcs
parentd4433d5b7b34fa316c473769d51c79b2755953e4 (diff)
net: pcs: xpcs: add support for sgmii with no inband AN
In fixed-link use cases, the XPCS can disable the clause 37 in-band autoneg process, disable the "Automatic Speed Mode Change after CL37 AN" setting, and force operation in a speed dictated by management. Add support for this operating mode. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/pcs')
-rw-r--r--drivers/net/pcs/pcs-xpcs.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 8ca7592b02ec..743b53734eeb 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -690,7 +690,7 @@ int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
}
EXPORT_SYMBOL_GPL(xpcs_config_eee);
-static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs)
+static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
{
int ret;
@@ -726,7 +726,10 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs)
if (ret < 0)
return ret;
- ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ if (phylink_autoneg_inband(mode))
+ ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ else
+ ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
}
@@ -772,7 +775,7 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
}
break;
case DW_AN_C37_SGMII:
- ret = xpcs_config_aneg_c37_sgmii(xpcs);
+ ret = xpcs_config_aneg_c37_sgmii(xpcs, mode);
if (ret)
return ret;
break;
@@ -905,6 +908,36 @@ static void xpcs_get_state(struct phylink_pcs *pcs,
}
}
+static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
+ int speed, int duplex)
+{
+ int val, ret;
+
+ if (phylink_autoneg_inband(mode))
+ return;
+
+ switch (speed) {
+ case SPEED_1000:
+ val = BMCR_SPEED1000;
+ break;
+ case SPEED_100:
+ val = BMCR_SPEED100;
+ break;
+ case SPEED_10:
+ val = BMCR_SPEED10;
+ break;
+ default:
+ return;
+ }
+
+ if (duplex == DUPLEX_FULL)
+ val |= BMCR_FULLDPLX;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
+ if (ret)
+ pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
+}
+
static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface, int speed, int duplex)
{
@@ -912,6 +945,8 @@ static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
if (interface == PHY_INTERFACE_MODE_USXGMII)
return xpcs_config_usxgmii(xpcs, speed);
+ if (interface == PHY_INTERFACE_MODE_SGMII)
+ return xpcs_link_up_sgmii(xpcs, mode, speed, duplex);
}
static u32 xpcs_get_id(struct dw_xpcs *xpcs)