Merge branch 'net-phylink-xpcs-stmmac-support-pcs-eee-configuration'

Russell King says:

====================
net: phylink,xpcs,stmmac: support PCS EEE configuration

This series adds support for phylink managed EEE at the PCS level,
allowing xpcs_config_eee() to be removed. Sadly, we still end up with
a XPCS specific function to configure the clock multiplier.
====================

Link: https://patch.msgid.link/Z6naiPpxfxGr1Ic6@shell.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-02-14 13:42:53 -08:00
commit 412723d54a
7 changed files with 107 additions and 42 deletions

View File

@ -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,

View File

@ -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;

View File

@ -602,36 +602,6 @@ 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)
{
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,
mult_fact_100ns);
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);
}
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);
@ -1193,6 +1163,63 @@ 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);
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, true);
}
/**
* 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;
@ -1341,6 +1368,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)

View File

@ -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);

View File

@ -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,

View File

@ -50,8 +50,7 @@ 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);
void xpcs_destroy(struct dw_xpcs *xpcs);

View File

@ -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.