diff options
author | 2021-09-21 10:58:36 +0100 | |
---|---|---|
committer | 2021-09-21 10:58:36 +0100 | |
commit | 6a3807536328c632ead28911b7524bf14cfe71aa (patch) | |
tree | 8e67db0e1a8a0bdbb90f1fd0ec35e9e28559d126 /drivers/net | |
parent | net/ipv4/syncookies.c: remove superfluous header files from syncookies.c (diff) | |
parent | net: dsa: bcm_sf2: Request APD, DLL disable and IDDQ-SR (diff) | |
download | linux-dev-6a3807536328c632ead28911b7524bf14cfe71aa.tar.xz linux-dev-6a3807536328c632ead28911b7524bf14cfe71aa.zip |
Merge branch 'iddq-sr-mode'
Florian Fainelli says:
====================
net: phy: broadcom: IDDQ-SR mode
This patch series adds support for the IDDQ with soft recovery mode
which allows power savings of roughly 150mW compared to a simple
BMCR.PDOWN power off (called standby power down in Broadcom datasheets).
In order to leverage these modes we add a new PHY driver flags for
drivers to opt-in for that behavior, the PHY driver is modified to do
the appropriate programming and the PHYs on which this was tested get
updated to have an appropriate suspend/resume set of functions.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/dsa/bcm_sf2.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmmii.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/broadcom.c | 59 |
3 files changed, 63 insertions, 4 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 6ce9ec1283e0..aa713936d77c 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -667,7 +667,9 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port) if (priv->int_phy_mask & BIT(port)) return priv->hw_params.gphy_rev; else - return 0; + return PHY_BRCM_AUTO_PWRDWN_ENABLE | + PHY_BRCM_DIS_TXCRXC_NOENRGY | + PHY_BRCM_IDDQ_SUSPEND; } static void bcm_sf2_sw_validate(struct dsa_switch *ds, int port, diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 2d29de9a33e3..ff1efd52ce16 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -288,7 +288,9 @@ int bcmgenet_mii_probe(struct net_device *dev) struct device_node *dn = kdev->of_node; phy_interface_t phy_iface = priv->phy_interface; struct phy_device *phydev; - u32 phy_flags = 0; + u32 phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE | + PHY_BRCM_DIS_TXCRXC_NOENRGY | + PHY_BRCM_IDDQ_SUSPEND; int ret; /* Communicate the integrated PHY revision */ diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index add0c4e33425..bb5104ae4610 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -392,10 +392,50 @@ static int bcm54xx_config_init(struct phy_device *phydev) return 0; } +static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable) +{ + int ret = 0; + + if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND)) + return ret; + + ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL); + if (ret < 0) + goto out; + + if (enable) + ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP; + else + ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP); + + ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret); +out: + return ret; +} + +static int bcm54xx_suspend(struct phy_device *phydev) +{ + int ret; + + /* We cannot use a read/modify/write here otherwise the PHY gets into + * a bad state where its LEDs keep flashing, thus defeating the purpose + * of low power mode. + */ + ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN); + if (ret < 0) + return ret; + + return bcm54xx_iddq_set(phydev, true); +} + static int bcm54xx_resume(struct phy_device *phydev) { int ret; + ret = bcm54xx_iddq_set(phydev, false); + if (ret < 0) + return ret; + /* Writes to register other than BMCR would be ignored * unless we clear the PDOWN bit first */ @@ -408,6 +448,15 @@ static int bcm54xx_resume(struct phy_device *phydev) */ fsleep(40); + /* Issue a soft reset after clearing the power down bit + * and before doing any other configuration. + */ + if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) { + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + } + return bcm54xx_config_init(phydev); } @@ -772,6 +821,8 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .suspend = bcm54xx_suspend, + .resume = bcm54xx_resume, }, { .phy_id = PHY_ID_BCM5461, .phy_id_mask = 0xfffffff0, @@ -852,7 +903,7 @@ static struct phy_driver broadcom_drivers[] = { .config_aneg = bcm5481_config_aneg, .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, - .suspend = genphy_suspend, + .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, .link_change_notify = bcm54xx_link_change_notify, }, { @@ -868,7 +919,7 @@ static struct phy_driver broadcom_drivers[] = { .config_aneg = bcm5481_config_aneg, .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, - .suspend = genphy_suspend, + .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, .link_change_notify = bcm54xx_link_change_notify, }, { @@ -897,6 +948,8 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .suspend = bcm54xx_suspend, + .resume = bcm54xx_resume, }, { .phy_id = PHY_ID_BCM50610M, .phy_id_mask = 0xfffffff0, @@ -910,6 +963,8 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .suspend = bcm54xx_suspend, + .resume = bcm54xx_resume, }, { .phy_id = PHY_ID_BCM57780, .phy_id_mask = 0xfffffff0, |