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

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
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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,
+3 −1
Original line number Diff line number Diff line
@@ -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 */
+57 −2
Original line number Diff line number Diff line
@@ -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,
+8 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#define PHY_BRCM_CLEAR_RGMII_MODE	0x00000004
#define PHY_BRCM_DIS_TXCRXC_NOENRGY	0x00000008
#define PHY_BRCM_EN_MASTER_MODE		0x00000010
#define PHY_BRCM_IDDQ_SUSPEND		0x000000220

/* Broadcom BCM7xxx specific workarounds */
#define PHY_BRCM_7XXX_REV(x)		(((x) >> 8) & 0xff)
@@ -84,6 +85,7 @@

#define MII_BCM54XX_EXP_DATA	0x15	/* Expansion register data */
#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_ER	0x0f00	/* Expansion register select */
#define MII_BCM54XX_EXP_SEL_ETC	0x0d00	/* Expansion register spare + 2k mem */
@@ -243,6 +245,12 @@
#define MII_BCM54XX_EXP_EXP97			0x0f97
#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
 */