142142#define PHY_BCM_FLAGS_MODE_1000BX 0x00000002
143143#define PHY_BCM_FLAGS_MODE_COPPER 0x00000001
144144
145+
146+ /*****************************************************************************/
147+ /* Fast Ethernet Transceiver definitions. */
148+ /*****************************************************************************/
149+
150+ #define MII_BRCM_FET_INTREG 0x1a /* Interrupt register */
151+ #define MII_BRCM_FET_IR_MASK 0x0100 /* Mask all interrupts */
152+ #define MII_BRCM_FET_IR_LINK_EN 0x0200 /* Link status change enable */
153+ #define MII_BRCM_FET_IR_SPEED_EN 0x0400 /* Link speed change enable */
154+ #define MII_BRCM_FET_IR_DUPLEX_EN 0x0800 /* Duplex mode change enable */
155+ #define MII_BRCM_FET_IR_ENABLE 0x4000 /* Interrupt enable */
156+
157+ #define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */
158+ #define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */
159+
160+
161+ /*** Shadow register definitions ***/
162+
163+ #define MII_BRCM_FET_SHDW_MISCCTRL 0x10 /* Shadow misc ctrl */
164+ #define MII_BRCM_FET_SHDW_MC_FAME 0x4000 /* Force Auto MDIX enable */
165+
166+ #define MII_BRCM_FET_SHDW_AUXMODE4 0x1a /* Auxiliary mode 4 */
167+ #define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
168+ #define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
169+
170+ #define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */
171+ #define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */
172+
173+
145174MODULE_DESCRIPTION ("Broadcom PHY driver" );
146175MODULE_AUTHOR ("Maciej W. Rozycki" );
147176MODULE_LICENSE ("GPL" );
@@ -436,6 +465,114 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
436465 return ret ;
437466}
438467
468+ static int brcm_phy_setbits (struct phy_device * phydev , int reg , int set )
469+ {
470+ int val ;
471+
472+ val = phy_read (phydev , reg );
473+ if (val < 0 )
474+ return val ;
475+
476+ return phy_write (phydev , reg , val | set );
477+ }
478+
479+ static int brcm_fet_config_init (struct phy_device * phydev )
480+ {
481+ int reg , err , err2 , brcmtest ;
482+
483+ /* Reset the PHY to bring it to a known state. */
484+ err = phy_write (phydev , MII_BMCR , BMCR_RESET );
485+ if (err < 0 )
486+ return err ;
487+
488+ reg = phy_read (phydev , MII_BRCM_FET_INTREG );
489+ if (reg < 0 )
490+ return reg ;
491+
492+ /* Unmask events we are interested in and mask interrupts globally. */
493+ reg = MII_BRCM_FET_IR_DUPLEX_EN |
494+ MII_BRCM_FET_IR_SPEED_EN |
495+ MII_BRCM_FET_IR_LINK_EN |
496+ MII_BRCM_FET_IR_ENABLE |
497+ MII_BRCM_FET_IR_MASK ;
498+
499+ err = phy_write (phydev , MII_BRCM_FET_INTREG , reg );
500+ if (err < 0 )
501+ return err ;
502+
503+ /* Enable shadow register access */
504+ brcmtest = phy_read (phydev , MII_BRCM_FET_BRCMTEST );
505+ if (brcmtest < 0 )
506+ return brcmtest ;
507+
508+ reg = brcmtest | MII_BRCM_FET_BT_SRE ;
509+
510+ err = phy_write (phydev , MII_BRCM_FET_BRCMTEST , reg );
511+ if (err < 0 )
512+ return err ;
513+
514+ /* Set the LED mode */
515+ reg = phy_read (phydev , MII_BRCM_FET_SHDW_AUXMODE4 );
516+ if (reg < 0 ) {
517+ err = reg ;
518+ goto done ;
519+ }
520+
521+ reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK ;
522+ reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1 ;
523+
524+ err = phy_write (phydev , MII_BRCM_FET_SHDW_AUXMODE4 , reg );
525+ if (err < 0 )
526+ goto done ;
527+
528+ /* Enable auto MDIX */
529+ err = brcm_phy_setbits (phydev , MII_BRCM_FET_SHDW_MISCCTRL ,
530+ MII_BRCM_FET_SHDW_MC_FAME );
531+ if (err < 0 )
532+ goto done ;
533+
534+ /* Enable auto power down */
535+ err = brcm_phy_setbits (phydev , MII_BRCM_FET_SHDW_AUXSTAT2 ,
536+ MII_BRCM_FET_SHDW_AS2_APDE );
537+
538+ done :
539+ /* Disable shadow register access */
540+ err2 = phy_write (phydev , MII_BRCM_FET_BRCMTEST , brcmtest );
541+ if (!err )
542+ err = err2 ;
543+
544+ return err ;
545+ }
546+
547+ static int brcm_fet_ack_interrupt (struct phy_device * phydev )
548+ {
549+ int reg ;
550+
551+ /* Clear pending interrupts. */
552+ reg = phy_read (phydev , MII_BRCM_FET_INTREG );
553+ if (reg < 0 )
554+ return reg ;
555+
556+ return 0 ;
557+ }
558+
559+ static int brcm_fet_config_intr (struct phy_device * phydev )
560+ {
561+ int reg , err ;
562+
563+ reg = phy_read (phydev , MII_BRCM_FET_INTREG );
564+ if (reg < 0 )
565+ return reg ;
566+
567+ if (phydev -> interrupts == PHY_INTERRUPT_ENABLED )
568+ reg &= ~MII_BRCM_FET_IR_MASK ;
569+ else
570+ reg |= MII_BRCM_FET_IR_MASK ;
571+
572+ err = phy_write (phydev , MII_BRCM_FET_INTREG , reg );
573+ return err ;
574+ }
575+
439576static struct phy_driver bcm5411_driver = {
440577 .phy_id = 0x00206070 ,
441578 .phy_id_mask = 0xfffffff0 ,
@@ -571,6 +708,21 @@ static struct phy_driver bcm57780_driver = {
571708 .driver = { .owner = THIS_MODULE },
572709};
573710
711+ static struct phy_driver bcmac131_driver = {
712+ .phy_id = 0x0143bc70 ,
713+ .phy_id_mask = 0xfffffff0 ,
714+ .name = "Broadcom BCMAC131" ,
715+ .features = PHY_BASIC_FEATURES |
716+ SUPPORTED_Pause | SUPPORTED_Asym_Pause ,
717+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT ,
718+ .config_init = brcm_fet_config_init ,
719+ .config_aneg = genphy_config_aneg ,
720+ .read_status = genphy_read_status ,
721+ .ack_interrupt = brcm_fet_ack_interrupt ,
722+ .config_intr = brcm_fet_config_intr ,
723+ .driver = { .owner = THIS_MODULE },
724+ };
725+
574726static int __init broadcom_init (void )
575727{
576728 int ret ;
@@ -602,8 +754,13 @@ static int __init broadcom_init(void)
602754 ret = phy_driver_register (& bcm57780_driver );
603755 if (ret )
604756 goto out_57780 ;
757+ ret = phy_driver_register (& bcmac131_driver );
758+ if (ret )
759+ goto out_ac131 ;
605760 return ret ;
606761
762+ out_ac131 :
763+ phy_driver_unregister (& bcm57780_driver );
607764out_57780 :
608765 phy_driver_unregister (& bcm50610m_driver );
609766out_50610m :
@@ -626,6 +783,7 @@ static int __init broadcom_init(void)
626783
627784static void __exit broadcom_exit (void )
628785{
786+ phy_driver_unregister (& bcmac131_driver );
629787 phy_driver_unregister (& bcm57780_driver );
630788 phy_driver_unregister (& bcm50610m_driver );
631789 phy_driver_unregister (& bcm50610_driver );
0 commit comments