From e9f03a6a879bffea0ee51af87ac7a0c77716dda6 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:53:39 +0000 Subject: [PATCH 1/8] net: phylink: add support for notifying PCS about EEE There are hooks in the stmmac driver into XPCS to control the EEE settings when LPI is configured at the MAC. This bypasses the layering. To allow this to be removed from the stmmac driver, add two new methods for PCS to inform them when the LPI/EEE enablement state changes at the MAC. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQ3-003w6u-RH@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 25 ++++++++++++++++++++++--- include/linux/phylink.h | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 74693307dfbf..046ec8dda159 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1073,6 +1073,18 @@ static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex); } +static void phylink_pcs_disable_eee(struct phylink_pcs *pcs) +{ + if (pcs && pcs->ops->pcs_disable_eee) + pcs->ops->pcs_disable_eee(pcs); +} + +static void phylink_pcs_enable_eee(struct phylink_pcs *pcs) +{ + if (pcs && pcs->ops->pcs_enable_eee) + pcs->ops->pcs_enable_eee(pcs); +} + /* Query inband for a specific interface mode, asking the MAC for the * PCS which will be used to handle the interface mode. */ @@ -1601,6 +1613,8 @@ static void phylink_deactivate_lpi(struct phylink *pl) phylink_dbg(pl, "disabling LPI\n"); pl->mac_ops->mac_disable_tx_lpi(pl->config); + + phylink_pcs_disable_eee(pl->pcs); } } @@ -1617,13 +1631,18 @@ static void phylink_activate_lpi(struct phylink *pl) phylink_dbg(pl, "LPI timer %uus, tx clock stop %u\n", pl->mac_tx_lpi_timer, pl->mac_tx_clk_stop); + phylink_pcs_enable_eee(pl->pcs); + err = pl->mac_ops->mac_enable_tx_lpi(pl->config, pl->mac_tx_lpi_timer, pl->mac_tx_clk_stop); - if (!err) - pl->mac_enable_tx_lpi = true; - else + if (err) { + phylink_pcs_disable_eee(pl->pcs); phylink_err(pl, "%ps() failed: %pe\n", pl->mac_ops->mac_enable_tx_lpi, ERR_PTR(err)); + return; + } + + pl->mac_enable_tx_lpi = true; } static void phylink_link_up(struct phylink *pl, diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 0de78673172d..41ab85e591ad 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -477,6 +477,10 @@ struct phylink_pcs { * @pcs_an_restart: restart 802.3z BaseX autonegotiation. * @pcs_link_up: program the PCS for the resolved link configuration * (where necessary). + * @pcs_disable_eee: optional notification to PCS that EEE has been disabled + * at the MAC. + * @pcs_enable_eee: optional notification to PCS that EEE will be enabled at + * the MAC. * @pcs_pre_init: configure PCS components necessary for MAC hardware * initialization e.g. RX clock for stmmac. */ @@ -500,6 +504,8 @@ struct phylink_pcs_ops { void (*pcs_an_restart)(struct phylink_pcs *pcs); void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex); + void (*pcs_disable_eee)(struct phylink_pcs *pcs); + void (*pcs_enable_eee)(struct phylink_pcs *pcs); int (*pcs_pre_init)(struct phylink_pcs *pcs); }; @@ -625,6 +631,22 @@ void pcs_an_restart(struct phylink_pcs *pcs); void pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex); +/** + * pcs_disable_eee() - Disable EEE at the PCS + * @pcs: a pointer to a &struct phylink_pcs + * + * Optional method informing the PCS that EEE has been disabled at the MAC. + */ +void pcs_disable_eee(struct phylink_pcs *pcs); + +/** + * pcs_enable_eee() - Enable EEE at the PCS + * @pcs: a pointer to a &struct phylink_pcs + * + * Optional method informing the PCS that EEE is about to be enabled at the MAC. + */ +void pcs_enable_eee(struct phylink_pcs *pcs); + /** * pcs_pre_init() - Configure PCS components necessary for MAC initialization * @pcs: a pointer to a &struct phylink_pcs. From 8c841486674a43df9db08210232987cf039b8942 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:53:44 +0000 Subject: [PATCH 2/8] net: xpcs: add function to configure EEE clock multiplying factor Add a function to separate out the EEE clock multiplying factor. This will be called by the stmmac driver to configure this value. It would have been better had the driver used the CLK API to retrieve this clock, get its rate and calculate the appropriate multiplier, but that door has closed. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQ8-003w70-VT@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 14 ++++++++++++++ drivers/net/pcs/pcs-xpcs.h | 1 + include/linux/pcs/pcs-xpcs.h | 1 + 3 files changed, 16 insertions(+) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 1faa37f0e7b9..91ce4b13df32 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1193,6 +1193,20 @@ static void xpcs_an_restart(struct phylink_pcs *pcs) BMCR_ANRESTART); } +/** + * xpcs_config_eee_mult_fact() - set the EEE clock multiplying factor + * @xpcs: pointer to a &struct dw_xpcs instance + * @mult_fact: the multiplying factor + * + * Configure the EEE clock multiplying factor. This value should be such that + * clk_eee_time_period * (mult_fact + 1) is within the range 80 to 120ns. + */ +void xpcs_config_eee_mult_fact(struct dw_xpcs *xpcs, u8 mult_fact) +{ + xpcs->eee_mult_fact = mult_fact; +} +EXPORT_SYMBOL_GPL(xpcs_config_eee_mult_fact); + static int xpcs_read_ids(struct dw_xpcs *xpcs) { int ret; diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h index adc5a0b3c883..39d3f517b557 100644 --- a/drivers/net/pcs/pcs-xpcs.h +++ b/drivers/net/pcs/pcs-xpcs.h @@ -122,6 +122,7 @@ struct dw_xpcs { struct phylink_pcs pcs; phy_interface_t interface; bool need_reset; + u8 eee_mult_fact; }; int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg); diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 733f4ddd2ef1..749d40a9a086 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -52,6 +52,7 @@ struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs); int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface); int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable); +void xpcs_config_eee_mult_fact(struct dw_xpcs *xpcs, u8 mult_fact); struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr); struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode); void xpcs_destroy(struct dw_xpcs *xpcs); From 060fb27060e89c7d31c1c9542a6d1fb058573ff5 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:53:50 +0000 Subject: [PATCH 3/8] net: stmmac: call xpcs_config_eee_mult_fact() Arrange for stmmac to call the new xpcs_config_eee_mult_fact() function to configure the EEE clock multiplying factor. This will allow the removal of the xpcs_config_eee() calls in the next patch. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQE-003w76-3C@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 0c7d81ddd440..7c0a4046bbe3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -524,6 +524,8 @@ int stmmac_pcs_setup(struct net_device *ndev) if (ret) return dev_err_probe(priv->device, ret, "No xPCS found\n"); + xpcs_config_eee_mult_fact(xpcs, priv->plat->mult_fact_100ns); + priv->hw->xpcs = xpcs; return 0; From 5a12b2cf29c12d9d1467ec3e03746cd43dbb6251 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:53:55 +0000 Subject: [PATCH 4/8] net: xpcs: convert to phylink managed EEE Convert XPCS to use the new pcs_disable_eee() and pcs_enable_eee() methods. Since stmmac is the only user of xpcs_config_eee(), we can make this a no-op along with this change. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQJ-003w7C-6v@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 91ce4b13df32..1f312b5589a3 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -602,7 +602,8 @@ static void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) __set_bit(compat->interface, interfaces); } -int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) +static int __xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, + int enable) { u16 mask, val; int ret; @@ -630,6 +631,11 @@ int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) DW_VR_MII_EEE_TRN_LPI, enable ? DW_VR_MII_EEE_TRN_LPI : 0); } + +int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) +{ + return 0; +} EXPORT_SYMBOL_GPL(xpcs_config_eee); static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) @@ -1193,6 +1199,20 @@ static void xpcs_an_restart(struct phylink_pcs *pcs) BMCR_ANRESTART); } +static void xpcs_disable_eee(struct phylink_pcs *pcs) +{ + struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); + + __xpcs_config_eee(xpcs, 0, false); +} + +static void xpcs_enable_eee(struct phylink_pcs *pcs) +{ + struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); + + __xpcs_config_eee(xpcs, xpcs->eee_mult_fact, true); +} + /** * xpcs_config_eee_mult_fact() - set the EEE clock multiplying factor * @xpcs: pointer to a &struct dw_xpcs instance @@ -1355,6 +1375,8 @@ static const struct phylink_pcs_ops xpcs_phylink_ops = { .pcs_get_state = xpcs_get_state, .pcs_an_restart = xpcs_an_restart, .pcs_link_up = xpcs_link_up, + .pcs_disable_eee = xpcs_disable_eee, + .pcs_enable_eee = xpcs_enable_eee, }; static int xpcs_identify(struct dw_xpcs *xpcs) From dba7441b3916d145e24329fbef761b7349ba631c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:54:00 +0000 Subject: [PATCH 5/8] net: stmmac: remove calls to xpcs_config_eee() Remove the explicit calls to xpcs_config_eee() from the stmmac driver, preferring instead for phylink to manage the EEE configuration at the PCS. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQO-003w7I-Ap@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d99ff4146512..fd8ca1524e43 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1046,10 +1046,6 @@ static void stmmac_mac_disable_tx_lpi(struct phylink_config *config) priv->tx_path_in_lpi_mode = false; stmmac_set_eee_timer(priv, priv->hw, 0, STMMAC_DEFAULT_TWT_LS); - if (priv->hw->xpcs) - xpcs_config_eee(priv->hw->xpcs, priv->plat->mult_fact_100ns, - false); - mutex_unlock(&priv->lock); } @@ -1068,9 +1064,6 @@ static int stmmac_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, stmmac_set_eee_timer(priv, priv->hw, STMMAC_DEFAULT_LIT_LS, STMMAC_DEFAULT_TWT_LS); - if (priv->hw->xpcs) - xpcs_config_eee(priv->hw->xpcs, priv->plat->mult_fact_100ns, - true); /* Try to cnfigure the hardware timer. */ ret = stmmac_set_lpi_mode(priv, priv->hw, STMMAC_LPI_TIMER, From 55faeb89968aab5a32f0de93cd97fc1c4169d0f7 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:54:05 +0000 Subject: [PATCH 6/8] net: xpcs: remove xpcs_config_eee() from global scope Make xpcs_config_eee() private to the XPCS driver, called only from the phylink pcs_disable_eee() and pcs_enable_eee() methods. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQT-003w7O-Ec@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 14 ++++---------- include/linux/pcs/pcs-xpcs.h | 2 -- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 1f312b5589a3..6a28a4eae21c 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -602,8 +602,8 @@ static void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) __set_bit(compat->interface, interfaces); } -static int __xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, - int enable) +static int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, + int enable) { u16 mask, val; int ret; @@ -632,12 +632,6 @@ static int __xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, enable ? DW_VR_MII_EEE_TRN_LPI : 0); } -int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) -{ - return 0; -} -EXPORT_SYMBOL_GPL(xpcs_config_eee); - static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); @@ -1203,14 +1197,14 @@ static void xpcs_disable_eee(struct phylink_pcs *pcs) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - __xpcs_config_eee(xpcs, 0, false); + xpcs_config_eee(xpcs, 0, false); } static void xpcs_enable_eee(struct phylink_pcs *pcs) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - __xpcs_config_eee(xpcs, xpcs->eee_mult_fact, true); + xpcs_config_eee(xpcs, xpcs->eee_mult_fact, true); } /** diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 749d40a9a086..e40f554ff717 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -50,8 +50,6 @@ struct dw_xpcs; struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs); int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface); -int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, - int enable); void xpcs_config_eee_mult_fact(struct dw_xpcs *xpcs, u8 mult_fact); struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr); struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode); From 760320145a5acb5186b5500e396bd0ea434c8040 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:54:10 +0000 Subject: [PATCH 7/8] net: xpcs: clean up xpcs_config_eee() There is now no need to pass the mult_fact into xpcs_config_eee(), so let's remove that argument and use xpcs->eee_mult_fact directly. While changing the function signature, as we pass true/false for enable, use "bool" instead of "int" for this. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQY-003w7U-IG@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 6a28a4eae21c..cae6e8377191 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -602,8 +602,7 @@ static void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) __set_bit(compat->interface, interfaces); } -static int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, - int enable) +static int xpcs_config_eee(struct dw_xpcs *xpcs, bool enable) { u16 mask, val; int ret; @@ -618,7 +617,7 @@ static int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | FIELD_PREP(DW_VR_MII_EEE_MULT_FACT_100NS, - mult_fact_100ns); + xpcs->eee_mult_fact); else val = 0; @@ -1197,14 +1196,14 @@ static void xpcs_disable_eee(struct phylink_pcs *pcs) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - xpcs_config_eee(xpcs, 0, false); + xpcs_config_eee(xpcs, false); } static void xpcs_enable_eee(struct phylink_pcs *pcs) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - xpcs_config_eee(xpcs, xpcs->eee_mult_fact, true); + xpcs_config_eee(xpcs, true); } /** From 1d4c99a1ac126b73780b0caec3ab9fbd7fc85adc Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 10 Feb 2025 10:54:15 +0000 Subject: [PATCH 8/8] net: xpcs: group EEE code together Move xpcs_config_eee() with the other EEE-related functions. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1thRQd-003w7a-MM@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index cae6e8377191..ee0c1a27f06c 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -602,35 +602,6 @@ static void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) __set_bit(compat->interface, interfaces); } -static int xpcs_config_eee(struct dw_xpcs *xpcs, bool enable) -{ - u16 mask, val; - int ret; - - mask = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | - DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | - DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | - DW_VR_MII_EEE_MULT_FACT_100NS; - - if (enable) - val = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | - DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | - DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | - FIELD_PREP(DW_VR_MII_EEE_MULT_FACT_100NS, - xpcs->eee_mult_fact); - else - val = 0; - - ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, mask, - val); - if (ret < 0) - return ret; - - return xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, - DW_VR_MII_EEE_TRN_LPI, - enable ? DW_VR_MII_EEE_TRN_LPI : 0); -} - static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); @@ -1192,6 +1163,35 @@ static void xpcs_an_restart(struct phylink_pcs *pcs) BMCR_ANRESTART); } +static int xpcs_config_eee(struct dw_xpcs *xpcs, bool enable) +{ + u16 mask, val; + int ret; + + mask = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | + DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | + DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | + DW_VR_MII_EEE_MULT_FACT_100NS; + + if (enable) + val = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | + DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | + DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | + FIELD_PREP(DW_VR_MII_EEE_MULT_FACT_100NS, + xpcs->eee_mult_fact); + else + val = 0; + + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, mask, + val); + if (ret < 0) + return ret; + + return xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, + DW_VR_MII_EEE_TRN_LPI, + enable ? DW_VR_MII_EEE_TRN_LPI : 0); +} + static void xpcs_disable_eee(struct phylink_pcs *pcs) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);