forked from mirrors/linux
		
	broadcom: Add AC131 phy support
This patch adds support for the AC131 fast ethernet transceiver. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									4f4598fd0a
								
							
						
					
					
						commit
						d7a2ed9248
					
				
					 1 changed files with 158 additions and 0 deletions
				
			
		| 
						 | 
					@ -142,6 +142,35 @@
 | 
				
			||||||
#define PHY_BCM_FLAGS_MODE_1000BX	0x00000002
 | 
					#define PHY_BCM_FLAGS_MODE_1000BX	0x00000002
 | 
				
			||||||
#define PHY_BCM_FLAGS_MODE_COPPER	0x00000001
 | 
					#define PHY_BCM_FLAGS_MODE_COPPER	0x00000001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*****************************************************************************/
 | 
				
			||||||
 | 
					/* Fast Ethernet Transceiver definitions. */
 | 
				
			||||||
 | 
					/*****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_INTREG		0x1a	/* Interrupt register */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_IR_MASK		0x0100	/* Mask all interrupts */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_IR_LINK_EN		0x0200	/* Link status change enable */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_IR_SPEED_EN	0x0400	/* Link speed change enable */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_IR_DUPLEX_EN	0x0800	/* Duplex mode change enable */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_IR_ENABLE		0x4000	/* Interrupt enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_BRCMTEST		0x1f	/* Brcm test register */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_BT_SRE		0x0080	/* Shadow register enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*** Shadow register definitions ***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_MISCCTRL	0x10	/* Shadow misc ctrl */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_MC_FAME	0x4000	/* Force Auto MDIX enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_AUXMODE4	0x1a	/* Auxiliary mode 4 */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_AM4_LED_MASK	0x0003
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_AUXSTAT2	0x1b	/* Auxiliary status 2 */
 | 
				
			||||||
 | 
					#define MII_BRCM_FET_SHDW_AS2_APDE	0x0020	/* Auto power down enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_DESCRIPTION("Broadcom PHY driver");
 | 
					MODULE_DESCRIPTION("Broadcom PHY driver");
 | 
				
			||||||
MODULE_AUTHOR("Maciej W. Rozycki");
 | 
					MODULE_AUTHOR("Maciej W. Rozycki");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					@ -436,6 +465,114 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = phy_read(phydev, reg);
 | 
				
			||||||
 | 
						if (val < 0)
 | 
				
			||||||
 | 
							return val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return phy_write(phydev, reg, val | set);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int brcm_fet_config_init(struct phy_device *phydev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int reg, err, err2, brcmtest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reset the PHY to bring it to a known state. */
 | 
				
			||||||
 | 
						err = phy_write(phydev, MII_BMCR, BMCR_RESET);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 | 
				
			||||||
 | 
						if (reg < 0)
 | 
				
			||||||
 | 
							return reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Unmask events we are interested in and mask interrupts globally. */
 | 
				
			||||||
 | 
						reg = MII_BRCM_FET_IR_DUPLEX_EN |
 | 
				
			||||||
 | 
						      MII_BRCM_FET_IR_SPEED_EN |
 | 
				
			||||||
 | 
						      MII_BRCM_FET_IR_LINK_EN |
 | 
				
			||||||
 | 
						      MII_BRCM_FET_IR_ENABLE |
 | 
				
			||||||
 | 
						      MII_BRCM_FET_IR_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable shadow register access */
 | 
				
			||||||
 | 
						brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
 | 
				
			||||||
 | 
						if (brcmtest < 0)
 | 
				
			||||||
 | 
							return brcmtest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = brcmtest | MII_BRCM_FET_BT_SRE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set the LED mode */
 | 
				
			||||||
 | 
						reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
 | 
				
			||||||
 | 
						if (reg < 0) {
 | 
				
			||||||
 | 
							err = reg;
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
 | 
				
			||||||
 | 
						reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable auto MDIX */
 | 
				
			||||||
 | 
						err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
 | 
				
			||||||
 | 
									       MII_BRCM_FET_SHDW_MC_FAME);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable auto power down */
 | 
				
			||||||
 | 
						err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
 | 
				
			||||||
 | 
									       MII_BRCM_FET_SHDW_AS2_APDE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						/* Disable shadow register access */
 | 
				
			||||||
 | 
						err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
 | 
				
			||||||
 | 
						if (!err)
 | 
				
			||||||
 | 
							err = err2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int brcm_fet_ack_interrupt(struct phy_device *phydev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Clear pending interrupts.  */
 | 
				
			||||||
 | 
						reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 | 
				
			||||||
 | 
						if (reg < 0)
 | 
				
			||||||
 | 
							return reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int brcm_fet_config_intr(struct phy_device *phydev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int reg, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 | 
				
			||||||
 | 
						if (reg < 0)
 | 
				
			||||||
 | 
							return reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 | 
				
			||||||
 | 
							reg &= ~MII_BRCM_FET_IR_MASK;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							reg |= MII_BRCM_FET_IR_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct phy_driver bcm5411_driver = {
 | 
					static struct phy_driver bcm5411_driver = {
 | 
				
			||||||
	.phy_id		= 0x00206070,
 | 
						.phy_id		= 0x00206070,
 | 
				
			||||||
	.phy_id_mask	= 0xfffffff0,
 | 
						.phy_id_mask	= 0xfffffff0,
 | 
				
			||||||
| 
						 | 
					@ -571,6 +708,21 @@ static struct phy_driver bcm57780_driver = {
 | 
				
			||||||
	.driver		= { .owner = THIS_MODULE },
 | 
						.driver		= { .owner = THIS_MODULE },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct phy_driver bcmac131_driver = {
 | 
				
			||||||
 | 
						.phy_id		= 0x0143bc70,
 | 
				
			||||||
 | 
						.phy_id_mask	= 0xfffffff0,
 | 
				
			||||||
 | 
						.name		= "Broadcom BCMAC131",
 | 
				
			||||||
 | 
						.features	= PHY_BASIC_FEATURES |
 | 
				
			||||||
 | 
								  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 | 
				
			||||||
 | 
						.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 | 
				
			||||||
 | 
						.config_init	= brcm_fet_config_init,
 | 
				
			||||||
 | 
						.config_aneg	= genphy_config_aneg,
 | 
				
			||||||
 | 
						.read_status	= genphy_read_status,
 | 
				
			||||||
 | 
						.ack_interrupt	= brcm_fet_ack_interrupt,
 | 
				
			||||||
 | 
						.config_intr	= brcm_fet_config_intr,
 | 
				
			||||||
 | 
						.driver		= { .owner = THIS_MODULE },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init broadcom_init(void)
 | 
					static int __init broadcom_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					@ -602,8 +754,13 @@ static int __init broadcom_init(void)
 | 
				
			||||||
	ret = phy_driver_register(&bcm57780_driver);
 | 
						ret = phy_driver_register(&bcm57780_driver);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto out_57780;
 | 
							goto out_57780;
 | 
				
			||||||
 | 
						ret = phy_driver_register(&bcmac131_driver);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto out_ac131;
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_ac131:
 | 
				
			||||||
 | 
						phy_driver_unregister(&bcm57780_driver);
 | 
				
			||||||
out_57780:
 | 
					out_57780:
 | 
				
			||||||
	phy_driver_unregister(&bcm50610m_driver);
 | 
						phy_driver_unregister(&bcm50610m_driver);
 | 
				
			||||||
out_50610m:
 | 
					out_50610m:
 | 
				
			||||||
| 
						 | 
					@ -626,6 +783,7 @@ static int __init broadcom_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit broadcom_exit(void)
 | 
					static void __exit broadcom_exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						phy_driver_unregister(&bcmac131_driver);
 | 
				
			||||||
	phy_driver_unregister(&bcm57780_driver);
 | 
						phy_driver_unregister(&bcm57780_driver);
 | 
				
			||||||
	phy_driver_unregister(&bcm50610m_driver);
 | 
						phy_driver_unregister(&bcm50610m_driver);
 | 
				
			||||||
	phy_driver_unregister(&bcm50610_driver);
 | 
						phy_driver_unregister(&bcm50610_driver);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue