forked from mirrors/linux
		
	net: phy: broadcom: Add IDDQ-SR mode
Add support for putting the PHY into IDDQ Soft Recovery mode by setting the TOP_MISC register bits accordingly. This requires us to implement a custom bcm54xx_suspend() routine which diverges from genphy_suspend() in order to configure the PHY to enter IDDQ with software recovery as well as avoid doing a read/modify/write on the BMCR register. Doing a read/modify/write on the BMCR register means that the auto-negotation bit may remain which interferes with the ability to put the PHY into IDDQ-SR mode. We do software reset upon suspend in order to put the PHY back into its state prior to suspend as recommended by the datasheet. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c595b120eb
								
							
						
					
					
						commit
						d6da08ed14
					
				
					 2 changed files with 59 additions and 0 deletions
				
			
		| 
						 | 
					@ -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)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	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[] = {
 | 
				
			||||||
	.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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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 @@
 | 
				
			||||||
#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
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue