Commit 6a380753 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents c595b120 4972ce72
...@@ -667,7 +667,9 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port) ...@@ -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)) if (priv->int_phy_mask & BIT(port))
return priv->hw_params.gphy_rev; return priv->hw_params.gphy_rev;
else 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, static void bcm_sf2_sw_validate(struct dsa_switch *ds, int port,
......
...@@ -288,7 +288,9 @@ int bcmgenet_mii_probe(struct net_device *dev) ...@@ -288,7 +288,9 @@ int bcmgenet_mii_probe(struct net_device *dev)
struct device_node *dn = kdev->of_node; struct device_node *dn = kdev->of_node;
phy_interface_t phy_iface = priv->phy_interface; phy_interface_t phy_iface = priv->phy_interface;
struct phy_device *phydev; 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; int ret;
/* Communicate the integrated PHY revision */ /* Communicate the integrated PHY revision */
......
...@@ -392,10 +392,50 @@ static int bcm54xx_config_init(struct phy_device *phydev) ...@@ -392,10 +392,50 @@ static int bcm54xx_config_init(struct phy_device *phydev)
return 0; 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) static int bcm54xx_resume(struct phy_device *phydev)
{ {
int ret; int ret;
ret = bcm54xx_iddq_set(phydev, false);
if (ret < 0)
return ret;
/* Writes to register other than BMCR would be ignored /* Writes to register other than BMCR would be ignored
* unless we clear the PDOWN bit first * unless we clear the PDOWN bit first
*/ */
...@@ -408,6 +448,15 @@ static int bcm54xx_resume(struct phy_device *phydev) ...@@ -408,6 +448,15 @@ static int bcm54xx_resume(struct phy_device *phydev)
*/ */
fsleep(40); 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); return bcm54xx_config_init(phydev);
} }
...@@ -772,6 +821,8 @@ static struct phy_driver broadcom_drivers[] = { ...@@ -772,6 +821,8 @@ static struct phy_driver broadcom_drivers[] = {
.config_intr = bcm_phy_config_intr, .config_intr = bcm_phy_config_intr,
.handle_interrupt = bcm_phy_handle_interrupt, .handle_interrupt = bcm_phy_handle_interrupt,
.link_change_notify = bcm54xx_link_change_notify, .link_change_notify = bcm54xx_link_change_notify,
.suspend = bcm54xx_suspend,
.resume = bcm54xx_resume,
}, { }, {
.phy_id = PHY_ID_BCM5461, .phy_id = PHY_ID_BCM5461,
.phy_id_mask = 0xfffffff0, .phy_id_mask = 0xfffffff0,
...@@ -852,7 +903,7 @@ static struct phy_driver broadcom_drivers[] = { ...@@ -852,7 +903,7 @@ static struct phy_driver broadcom_drivers[] = {
.config_aneg = bcm5481_config_aneg, .config_aneg = bcm5481_config_aneg,
.config_intr = bcm_phy_config_intr, .config_intr = bcm_phy_config_intr,
.handle_interrupt = bcm_phy_handle_interrupt, .handle_interrupt = bcm_phy_handle_interrupt,
.suspend = genphy_suspend, .suspend = bcm54xx_suspend,
.resume = bcm54xx_resume, .resume = bcm54xx_resume,
.link_change_notify = bcm54xx_link_change_notify, .link_change_notify = bcm54xx_link_change_notify,
}, { }, {
...@@ -868,7 +919,7 @@ static struct phy_driver broadcom_drivers[] = { ...@@ -868,7 +919,7 @@ static struct phy_driver broadcom_drivers[] = {
.config_aneg = bcm5481_config_aneg, .config_aneg = bcm5481_config_aneg,
.config_intr = bcm_phy_config_intr, .config_intr = bcm_phy_config_intr,
.handle_interrupt = bcm_phy_handle_interrupt, .handle_interrupt = bcm_phy_handle_interrupt,
.suspend = genphy_suspend, .suspend = bcm54xx_suspend,
.resume = bcm54xx_resume, .resume = bcm54xx_resume,
.link_change_notify = bcm54xx_link_change_notify, .link_change_notify = bcm54xx_link_change_notify,
}, { }, {
...@@ -897,6 +948,8 @@ static struct phy_driver broadcom_drivers[] = { ...@@ -897,6 +948,8 @@ static struct phy_driver broadcom_drivers[] = {
.config_intr = bcm_phy_config_intr, .config_intr = bcm_phy_config_intr,
.handle_interrupt = bcm_phy_handle_interrupt, .handle_interrupt = bcm_phy_handle_interrupt,
.link_change_notify = bcm54xx_link_change_notify, .link_change_notify = bcm54xx_link_change_notify,
.suspend = bcm54xx_suspend,
.resume = bcm54xx_resume,
}, { }, {
.phy_id = PHY_ID_BCM50610M, .phy_id = PHY_ID_BCM50610M,
.phy_id_mask = 0xfffffff0, .phy_id_mask = 0xfffffff0,
...@@ -910,6 +963,8 @@ static struct phy_driver broadcom_drivers[] = { ...@@ -910,6 +963,8 @@ static struct phy_driver broadcom_drivers[] = {
.config_intr = bcm_phy_config_intr, .config_intr = bcm_phy_config_intr,
.handle_interrupt = bcm_phy_handle_interrupt, .handle_interrupt = bcm_phy_handle_interrupt,
.link_change_notify = bcm54xx_link_change_notify, .link_change_notify = bcm54xx_link_change_notify,
.suspend = bcm54xx_suspend,
.resume = bcm54xx_resume,
}, { }, {
.phy_id = PHY_ID_BCM57780, .phy_id = PHY_ID_BCM57780,
.phy_id_mask = 0xfffffff0, .phy_id_mask = 0xfffffff0,
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#define PHY_BRCM_CLEAR_RGMII_MODE 0x00000004 #define PHY_BRCM_CLEAR_RGMII_MODE 0x00000004
#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00000008 #define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00000008
#define PHY_BRCM_EN_MASTER_MODE 0x00000010 #define PHY_BRCM_EN_MASTER_MODE 0x00000010
#define PHY_BRCM_IDDQ_SUSPEND 0x000000220
/* Broadcom BCM7xxx specific workarounds */ /* Broadcom BCM7xxx specific workarounds */
#define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff) #define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
...@@ -84,6 +85,7 @@ ...@@ -84,6 +85,7 @@
#define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ #define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */
#define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ #define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */
#define MII_BCM54XX_EXP_SEL_TOP 0x0d00 /* TOP_MISC expansion register select */
#define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ #define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */
#define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ #define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */
#define MII_BCM54XX_EXP_SEL_ETC 0x0d00 /* Expansion register spare + 2k mem */ #define MII_BCM54XX_EXP_SEL_ETC 0x0d00 /* Expansion register spare + 2k mem */
...@@ -243,6 +245,12 @@ ...@@ -243,6 +245,12 @@
#define MII_BCM54XX_EXP_EXP97 0x0f97 #define MII_BCM54XX_EXP_EXP97 0x0f97
#define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c #define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c
/* Top-MISC expansion registers */
#define BCM54XX_TOP_MISC_IDDQ_CTRL (MII_BCM54XX_EXP_SEL_TOP + 0x06)
#define BCM54XX_TOP_MISC_IDDQ_LP (1 << 0)
#define BCM54XX_TOP_MISC_IDDQ_SD (1 << 2)
#define BCM54XX_TOP_MISC_IDDQ_SR (1 << 3)
/* /*
* BCM5482: Secondary SerDes registers * BCM5482: Secondary SerDes registers
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment