summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
diff options
context:
space:
mode:
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2023-05-31 17:17:11 +0100
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2024-04-27 16:54:55 +0100
commit50a12e80ff88a7837d3c01ea69f38f6f45f3f703 (patch)
tree027d410e4a82ba42c7dc3ba26e36302a73501cdf /drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
parent64217ea1ab69399d1263047cf76562760017a585 (diff)
net: mvpp2: add EEE implementation
Add EEE support for mvpp2, using phylink's EEE implementation, which means we just need to implement the two methods for LPI control, and with the initial configuration. Only the GMAC is supported, so only 100M, 1G and 2.5G speeds. Disabling LPI requires clearing a single bit. Enabling LPI needs a full configuration of several values, as the timer values are dependent on the MAC operating speed. Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c')
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 19253a0fb4fe..dd58009c3770 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -5727,6 +5727,28 @@ static int mvpp2_ethtool_set_rxfh(struct net_device *dev,
return ret;
}
+static int mvpp2_ethtool_get_eee(struct net_device *dev,
+ struct ethtool_eee *eee)
+{
+ struct mvpp2_port *port = netdev_priv(dev);
+
+ if (!port->phylink)
+ return -EOPNOTSUPP;
+
+ return phylink_ethtool_get_eee(port->phylink, eee);
+}
+
+static int mvpp2_ethtool_set_eee(struct net_device *dev,
+ struct ethtool_eee *eee)
+{
+ struct mvpp2_port *port = netdev_priv(dev);
+
+ if (!port->phylink)
+ return -EOPNOTSUPP;
+
+ return phylink_ethtool_set_eee(port->phylink, eee);
+}
+
/* Device ops */
static const struct net_device_ops mvpp2_netdev_ops = {
@@ -5769,6 +5791,8 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
.get_rxfh_indir_size = mvpp2_ethtool_get_rxfh_indir_size,
.get_rxfh = mvpp2_ethtool_get_rxfh,
.set_rxfh = mvpp2_ethtool_set_rxfh,
+ .get_eee = mvpp2_ethtool_get_eee,
+ .set_eee = mvpp2_ethtool_set_eee,
};
/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
@@ -6632,6 +6656,57 @@ static void mvpp2_mac_link_down(struct phylink_config *config,
mvpp2_port_disable(port);
}
+static void mvpp2_mac_disable_tx_lpi(struct phylink_config *config)
+{
+ struct mvpp2_port *port = mvpp2_phylink_to_port(config);
+
+ mvpp2_modify(port->base + MVPP2_GMAC_LPI_CTRL1,
+ MVPP2_GMAC_LPI_CTRL1_REQ_EN, 0);
+}
+
+static void mvpp2_mac_enable_tx_lpi(struct phylink_config *config, u32 timer)
+{
+ struct mvpp2_port *port = mvpp2_phylink_to_port(config);
+ u32 ts, tw, lpi0, lpi1, status;
+
+ status = readl(port->base + MVPP2_GMAC_STATUS0);
+ if (status & MVPP2_GMAC_STATUS0_GMII_SPEED) {
+ /* At 1G speeds, the timer resolution are 1us, and
+ * 802.3 says tw is 16.5us. Round up to 17us.
+ */
+ tw = 17;
+ ts = timer;
+ } else {
+ /* At 100M speeds, the timer resolutions are 10us, and
+ * 802.3 says tw is 30us.
+ */
+ tw = 3;
+ ts = DIV_ROUND_UP(timer, 10);
+ }
+
+ if (ts > 255)
+ ts = 255;
+
+ /* Ensure LPI generation is disabled */
+ lpi1 = readl(port->base + MVPP2_GMAC_LPI_CTRL1);
+ writel(lpi1 & ~MVPP2_GMAC_LPI_CTRL1_REQ_EN,
+ port->base + MVPP2_GMAC_LPI_CTRL1);
+
+ /* Configure ts */
+ lpi0 = readl(port->base + MVPP2_GMAC_LPI_CTRL0);
+ lpi0 &= ~MVPP2_GMAC_LPI_CTRL0_TS_MASK;
+ lpi0 |= FIELD_PREP(MVPP2_GMAC_LPI_CTRL0_TS_MASK, ts);
+ writel(lpi0, port->base + MVPP2_GMAC_LPI_CTRL0);
+
+ /* Configure tw */
+ lpi1 &= ~MVPP2_GMAC_LPI_CTRL1_TW_MASK;
+ lpi1 |= FIELD_PREP(MVPP2_GMAC_LPI_CTRL1_TW_MASK, tw);
+
+ /* Enable LPI generation */
+ writel(lpi1 | MVPP2_GMAC_LPI_CTRL1_REQ_EN,
+ port->base + MVPP2_GMAC_LPI_CTRL1);
+}
+
static const struct phylink_mac_ops mvpp2_phylink_ops = {
.mac_select_pcs = mvpp2_select_pcs,
.mac_prepare = mvpp2_mac_prepare,
@@ -6639,6 +6714,8 @@ static const struct phylink_mac_ops mvpp2_phylink_ops = {
.mac_finish = mvpp2_mac_finish,
.mac_link_up = mvpp2_mac_link_up,
.mac_link_down = mvpp2_mac_link_down,
+ .mac_enable_tx_lpi = mvpp2_mac_enable_tx_lpi,
+ .mac_disable_tx_lpi = mvpp2_mac_disable_tx_lpi,
};
/* Work-around for ACPI */
@@ -6915,6 +6992,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
port->phylink_config.type = PHYLINK_NETDEV;
port->phylink_config.mac_capabilities =
MAC_2500FD | MAC_1000FD | MAC_100 | MAC_10;
+ port->phylink_config.lpi_capabilities =
+ MAC_2500FD | MAC_1000FD | MAC_100FD;
+ port->phylink_config.lpi_timer_limit_us = 255;
if (port->priv->global_tx_fc)
port->phylink_config.mac_capabilities |=
@@ -6983,6 +7063,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
port->phylink_config.supported_interfaces);
}
+ /* Setup EEE. Choose 250us idle. */
+ port->phylink_config.eee.eee_enabled = true;
+ port->phylink_config.eee.tx_lpi_enabled = true;
+ port->phylink_config.eee.tx_lpi_timer = 250;
+
phylink = phylink_create(&port->phylink_config, port_fwnode,
phy_mode, &mvpp2_phylink_ops);
if (IS_ERR(phylink)) {