summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2016-12-27 10:56:49 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2019-07-09 12:20:56 +0100
commit3c4b2328bfcf76e150a8154ce118b19d4a594148 (patch)
treef833cb38aaf1ad6811962fe95c201f612bf07d46
parent47e28ad1439e1e77525b121ba1eafdfe6f76c4a8 (diff)
net: marvell: mvpp2x: support for switching protocols
Add support for switching protocols on the serdes lines. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/ethernet/marvell/mvpp2x/mv_pp2x_main.c129
1 files changed, 128 insertions, 1 deletions
diff --git a/drivers/net/ethernet/marvell/mvpp2x/mv_pp2x_main.c b/drivers/net/ethernet/marvell/mvpp2x/mv_pp2x_main.c
index 51cc42432fc7..a9b76eabb787 100644
--- a/drivers/net/ethernet/marvell/mvpp2x/mv_pp2x_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2x/mv_pp2x_main.c
@@ -1695,6 +1695,65 @@ static void mv_pp21_link_event(struct net_device *dev)
}
}
+static bool mv_pp2x_reconfig_port(struct mv_pp2x_port *port,
+ phy_interface_t interface, bool sgmii_hs)
+{
+ struct gop_hw *gop = &port->priv->hw.gop;
+ struct mv_mac_data *mac = &port->mac_data;
+ unsigned int com_mode, old_mode;
+ u64 flags = mac->flags;
+ bool reconfig = false;
+
+ com_mode = old_mode = phy_get_mode(port->comphy);
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_10GKR:
+ com_mode = COMPHY_DEF(COMPHY_SFI_MODE, port->id);
+ flags &= ~MV_EMAC_F_SGMII2_5;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ interface = PHY_INTERFACE_MODE_SGMII;
+ if (sgmii_hs) {
+ com_mode = COMPHY_DEF(COMPHY_HS_SGMII_MODE, port->id);
+ flags |= MV_EMAC_F_SGMII2_5;
+ } else {
+ com_mode = COMPHY_DEF(COMPHY_SGMII_MODE, port->id);
+ flags &= ~MV_EMAC_F_SGMII2_5;
+ }
+ break;
+ default:
+ break;
+ }
+
+ netdev_printk(KERN_DEBUG, port->dev,
+ "reconfig: pm %x->%x cm %x->%x f %llx->%llx\n",
+ mac->phy_mode, interface,
+ old_mode, com_mode, mac->flags, flags);
+
+ if (mac->phy_mode != interface || mac->flags != flags) {
+ netdev_dbg(port->dev, "disabling port\n");
+ mv_gop110_port_events_mask(gop, mac);
+ mv_gop110_port_disable(gop, mac);
+ netdev_dbg(port->dev, "comphy power off\n");
+ phy_power_off(port->comphy);
+
+ netdev_dbg(port->dev, "comphy set mode\n");
+ if (phy_set_mode(port->comphy, com_mode) == 0) {
+ mac->phy_mode = interface;
+ mac->flags = flags;
+ } else {
+ netdev_err(port->dev, "phy_set_mode() failed\n");
+ }
+
+ netdev_dbg(port->dev, "port init\n");
+ mv_gop110_port_init(gop, mac);
+ reconfig = true;
+ }
+ return reconfig;
+}
+
static void mv_pp22_link_event(struct net_device *dev)
{
struct mv_pp2x_port *port = netdev_priv(dev);
@@ -1704,11 +1763,30 @@ static void mv_pp22_link_event(struct net_device *dev)
if (!phydev)
return;
+ netdev_printk(KERN_DEBUG, dev, "%s: phy [link %u speed %d duplex %d] mac [link %u speed %d duplex %d]\n",
+ __func__, phydev->link, phydev->speed, phydev->duplex,
+ port->mac_data.link, port->mac_data.speed, port->mac_data.duplex);
+
if (phydev->link) {
if ((port->mac_data.speed != phydev->speed) ||
(port->mac_data.duplex != phydev->duplex)) {
+ struct gop_hw *gop = &port->priv->hw.gop;
+ struct mv_mac_data *mac = &port->mac_data;
+ bool reconfig;
+
+ reconfig = mv_pp2x_reconfig_port(port, phydev->interface,
+ phydev->speed == SPEED_2500);
+
port->mac_data.duplex = phydev->duplex;
port->mac_data.speed = phydev->speed;
+
+ if (reconfig && port->mac_data.flags & MV_EMAC_F_LINK_UP) {
+ netdev_dbg(port->dev, "enabling port\n");
+ mv_gop110_port_events_unmask(gop, mac);
+ mv_gop110_port_enable(gop, mac);
+ netdev_dbg(port->dev, "comphy power up\n");
+ phy_power_on(port->comphy);
+ }
}
port->mac_data.flags |= MV_EMAC_F_LINK_UP;
}
@@ -1898,6 +1976,11 @@ static void mv_pp22_validate(struct net_device *dev, unsigned long *supported,
__ETHTOOL_LINK_MODE_MASK_NBITS);
bitmap_and(state->advertising, state->advertising, mask,
__ETHTOOL_LINK_MODE_MASK_NBITS);
+
+ /* We can only operate at 2500BaseX or 1000BaseX. If requested
+ * to advertise both, only report advertising at 1000BaseX.
+ */
+ phylink_helper_basex_speed(state);
}
static int mv_pp22_mac_link_state(struct net_device *dev,
@@ -2039,6 +2122,10 @@ static void mv_pp22_mac_config(struct net_device *dev, unsigned int mode,
const struct phylink_link_state *state)
{
struct mv_pp2x_port *port = netdev_priv(dev);
+ bool reconfig;
+
+ reconfig = mv_pp2x_reconfig_port(port, state->interface,
+ state->interface == PHY_INTERFACE_MODE_2500BASEX);
switch (port->mac_data.phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
@@ -2050,6 +2137,16 @@ static void mv_pp22_mac_config(struct net_device *dev, unsigned int mode,
default:
break;
}
+ if (reconfig) {
+ struct gop_hw *gop = &port->priv->hw.gop;
+ struct mv_mac_data *mac = &port->mac_data;
+
+ netdev_dbg(port->dev, "enabling port\n");
+ mv_gop110_port_enable(gop, mac);
+ mv_gop110_port_events_unmask(gop, mac);
+ netdev_dbg(port->dev, "comphy power up\n");
+ phy_power_on(port->comphy);
+ }
}
static void mv_pp22_mac_link_down(struct net_device *dev, unsigned int mode,
@@ -2057,6 +2154,12 @@ static void mv_pp22_mac_link_down(struct net_device *dev, unsigned int mode,
{
struct mv_pp2x_port *port = netdev_priv(dev);
+ port->mac_data.eee_active = false;
+ if (port->mac_data.phy_mode == PHY_INTERFACE_MODE_RGMII ||
+ port->mac_data.phy_mode == PHY_INTERFACE_MODE_SGMII ||
+ port->mac_data.phy_mode == PHY_INTERFACE_MODE_QSGMII)
+ mvgmac_set_eee(&port->gmac, false);
+
port->mac_data.link = 0;
mv_pp2x_ingress_disable(port);
mv_pp2x_egress_disable(port);
@@ -2069,6 +2172,16 @@ static void mv_pp22_mac_link_up(struct net_device *dev, unsigned int mode,
{
struct mv_pp2x_port *port = netdev_priv(dev);
+ if ((port->mac_data.phy_mode == PHY_INTERFACE_MODE_RGMII ||
+ port->mac_data.phy_mode == PHY_INTERFACE_MODE_SGMII ||
+ port->mac_data.phy_mode == PHY_INTERFACE_MODE_QSGMII) &&
+ phy && port->mac_data.eee_enabled) {
+ port->mac_data.eee_active = phy_init_eee(phy, 0) >= 0;
+ mvgmac_set_lpi_ts(&port->gmac, port->mac_data.tx_lpi_timer);
+ mvgmac_set_eee(&port->gmac, port->mac_data.eee_active &&
+ port->mac_data.tx_lpi_enabled);
+ }
+
port->mac_data.link = 1;
mv_gop110_port_events_mask(&port->priv->hw.gop, &port->mac_data);
mv_pp2x_egress_enable(port);
@@ -3560,6 +3673,9 @@ void mv_pp2x_start_dev(struct mv_pp2x_port *port)
struct gop_hw *gop = &port->priv->hw.gop;
struct mv_mac_data *mac = &port->mac_data;
int mac_num = port->mac_data.gop_index;
+
+ netdev_dbg(port->dev, "%s\n", __func__);
+
#ifdef DEV_NETMAP
if (port->flags & MVPP2_F_IFCAP_NETMAP) {
if (mv_pp2x_netmap_rxq_init_buffers(port))
@@ -3598,6 +3714,7 @@ void mv_pp2x_start_dev(struct mv_pp2x_port *port)
mv_pp2x_port_interrupts_enable(port);
if (port->comphy) {
+ netdev_dbg(port->dev, "%s: comphy power on\n", __func__);
mv_gop110_port_disable(gop, mac);
phy_power_on(port->comphy);
}
@@ -3780,7 +3897,17 @@ static int mv_pp2x_phy_connect(struct mv_pp2x_port *port)
dev_err(port->dev->dev.parent, "port ID: %d cannot connect to phy\n", port->id);
return -ENODEV;
}
- phy_dev->supported &= PHY_GBIT_FEATURES;
+ phy_dev->supported &= PHY_10BT_FEATURES |
+ PHY_100BT_FEATURES |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_TP |
+ SUPPORTED_MII | SUPPORTED_FIBRE |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_Backplane |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause |
+ SUPPORTED_2500baseX_Full |
+ SUPPORTED_10000baseKR_Full;
phy_dev->advertising = phy_dev->supported;
port->mac_data.phy_dev = phy_dev;