linux/drivers/net/phy/broadcom.c
<<
>>
Prefs
   1/*
   2 *      drivers/net/phy/broadcom.c
   3 *
   4 *      Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
   5 *      transceivers.
   6 *
   7 *      Copyright (c) 2006  Maciej W. Rozycki
   8 *
   9 *      Inspired by code written by Amy Fong.
  10 *
  11 *      This program is free software; you can redistribute it and/or
  12 *      modify it under the terms of the GNU General Public License
  13 *      as published by the Free Software Foundation; either version
  14 *      2 of the License, or (at your option) any later version.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/phy.h>
  19
  20#define PHY_ID_BCM50610         0x0143bd60
  21#define PHY_ID_BCM50610M        0x0143bd70
  22#define PHY_ID_BCM57780         0x03625d90
  23
  24#define BRCM_PHY_MODEL(phydev) \
  25        ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
  26
  27
  28#define MII_BCM54XX_ECR         0x10    /* BCM54xx extended control register */
  29#define MII_BCM54XX_ECR_IM      0x1000  /* Interrupt mask */
  30#define MII_BCM54XX_ECR_IF      0x0800  /* Interrupt force */
  31
  32#define MII_BCM54XX_ESR         0x11    /* BCM54xx extended status register */
  33#define MII_BCM54XX_ESR_IS      0x1000  /* Interrupt status */
  34
  35#define MII_BCM54XX_EXP_DATA    0x15    /* Expansion register data */
  36#define MII_BCM54XX_EXP_SEL     0x17    /* Expansion register select */
  37#define MII_BCM54XX_EXP_SEL_SSD 0x0e00  /* Secondary SerDes select */
  38#define MII_BCM54XX_EXP_SEL_ER  0x0f00  /* Expansion register select */
  39
  40#define MII_BCM54XX_AUX_CTL     0x18    /* Auxiliary control register */
  41#define MII_BCM54XX_ISR         0x1a    /* BCM54xx interrupt status register */
  42#define MII_BCM54XX_IMR         0x1b    /* BCM54xx interrupt mask register */
  43#define MII_BCM54XX_INT_CRCERR  0x0001  /* CRC error */
  44#define MII_BCM54XX_INT_LINK    0x0002  /* Link status changed */
  45#define MII_BCM54XX_INT_SPEED   0x0004  /* Link speed change */
  46#define MII_BCM54XX_INT_DUPLEX  0x0008  /* Duplex mode changed */
  47#define MII_BCM54XX_INT_LRS     0x0010  /* Local receiver status changed */
  48#define MII_BCM54XX_INT_RRS     0x0020  /* Remote receiver status changed */
  49#define MII_BCM54XX_INT_SSERR   0x0040  /* Scrambler synchronization error */
  50#define MII_BCM54XX_INT_UHCD    0x0080  /* Unsupported HCD negotiated */
  51#define MII_BCM54XX_INT_NHCD    0x0100  /* No HCD */
  52#define MII_BCM54XX_INT_NHCDL   0x0200  /* No HCD link */
  53#define MII_BCM54XX_INT_ANPR    0x0400  /* Auto-negotiation page received */
  54#define MII_BCM54XX_INT_LC      0x0800  /* All counters below 128 */
  55#define MII_BCM54XX_INT_HC      0x1000  /* Counter above 32768 */
  56#define MII_BCM54XX_INT_MDIX    0x2000  /* MDIX status change */
  57#define MII_BCM54XX_INT_PSERR   0x4000  /* Pair swap error */
  58
  59#define MII_BCM54XX_SHD         0x1c    /* 0x1c shadow registers */
  60#define MII_BCM54XX_SHD_WRITE   0x8000
  61#define MII_BCM54XX_SHD_VAL(x)  ((x & 0x1f) << 10)
  62#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
  63
  64/*
  65 * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
  66 */
  67#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL       0x0000
  68#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB          0x0400
  69#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA       0x0800
  70
  71#define MII_BCM54XX_AUXCTL_MISC_WREN    0x8000
  72#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX     0x0200
  73#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC      0x7000
  74#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
  75
  76#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL       0x0000
  77
  78
  79/*
  80 * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
  81 * BCM5482, and possibly some others.
  82 */
  83#define BCM_LED_SRC_LINKSPD1    0x0
  84#define BCM_LED_SRC_LINKSPD2    0x1
  85#define BCM_LED_SRC_XMITLED     0x2
  86#define BCM_LED_SRC_ACTIVITYLED 0x3
  87#define BCM_LED_SRC_FDXLED      0x4
  88#define BCM_LED_SRC_SLAVE       0x5
  89#define BCM_LED_SRC_INTR        0x6
  90#define BCM_LED_SRC_QUALITY     0x7
  91#define BCM_LED_SRC_RCVLED      0x8
  92#define BCM_LED_SRC_MULTICOLOR1 0xa
  93#define BCM_LED_SRC_OPENSHORT   0xb
  94#define BCM_LED_SRC_OFF         0xe     /* Tied high */
  95#define BCM_LED_SRC_ON          0xf     /* Tied low */
  96
  97/*
  98 * BCM5482: Shadow registers
  99 * Shadow values go into bits [14:10] of register 0x1c to select a shadow
 100 * register to access.
 101 */
 102#define BCM5482_SHD_LEDS1       0x0d    /* 01101: LED Selector 1 */
 103                                        /* LED3 / ~LINKSPD[2] selector */
 104#define BCM5482_SHD_LEDS1_LED3(src)     ((src & 0xf) << 4)
 105                                        /* LED1 / ~LINKSPD[1] selector */
 106#define BCM5482_SHD_LEDS1_LED1(src)     ((src & 0xf) << 0)
 107#define BCM5482_SHD_SSD         0x14    /* 10100: Secondary SerDes control */
 108#define BCM5482_SHD_SSD_LEDM    0x0008  /* SSD LED Mode enable */
 109#define BCM5482_SHD_SSD_EN      0x0001  /* SSD enable */
 110#define BCM5482_SHD_MODE        0x1f    /* 11111: Mode Control Register */
 111#define BCM5482_SHD_MODE_1000BX 0x0001  /* Enable 1000BASE-X registers */
 112
 113/*
 114 * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
 115 */
 116#define MII_BCM54XX_EXP_AADJ1CH0                0x001f
 117#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN  0x0200
 118#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF    0x0100
 119#define MII_BCM54XX_EXP_AADJ1CH3                0x601f
 120#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ      0x0002
 121#define MII_BCM54XX_EXP_EXP08                   0x0F08
 122#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ        0x0001
 123#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE   0x0200
 124#define MII_BCM54XX_EXP_EXP75                   0x0f75
 125#define  MII_BCM54XX_EXP_EXP75_VDACCTRL         0x003c
 126#define  MII_BCM54XX_EXP_EXP75_CM_OSC           0x0001
 127#define MII_BCM54XX_EXP_EXP96                   0x0f96
 128#define  MII_BCM54XX_EXP_EXP96_MYST             0x0010
 129#define MII_BCM54XX_EXP_EXP97                   0x0f97
 130#define  MII_BCM54XX_EXP_EXP97_MYST             0x0c0c
 131
 132/*
 133 * BCM5482: Secondary SerDes registers
 134 */
 135#define BCM5482_SSD_1000BX_CTL          0x00    /* 1000BASE-X Control */
 136#define BCM5482_SSD_1000BX_CTL_PWRDOWN  0x0800  /* Power-down SSD */
 137#define BCM5482_SSD_SGMII_SLAVE         0x15    /* SGMII Slave Register */
 138#define BCM5482_SSD_SGMII_SLAVE_EN      0x0002  /* Slave mode enable */
 139#define BCM5482_SSD_SGMII_SLAVE_AD      0x0001  /* Slave auto-detection */
 140
 141/*
 142 * Device flags for PHYs that can be configured for different operating
 143 * modes.
 144 */
 145#define PHY_BCM_FLAGS_VALID             0x80000000
 146#define PHY_BCM_FLAGS_INTF_XAUI         0x00000020
 147#define PHY_BCM_FLAGS_INTF_SGMII        0x00000010
 148#define PHY_BCM_FLAGS_MODE_1000BX       0x00000002
 149#define PHY_BCM_FLAGS_MODE_COPPER       0x00000001
 150
 151
 152/*****************************************************************************/
 153/* Fast Ethernet Transceiver definitions. */
 154/*****************************************************************************/
 155
 156#define MII_BRCM_FET_INTREG             0x1a    /* Interrupt register */
 157#define MII_BRCM_FET_IR_MASK            0x0100  /* Mask all interrupts */
 158#define MII_BRCM_FET_IR_LINK_EN         0x0200  /* Link status change enable */
 159#define MII_BRCM_FET_IR_SPEED_EN        0x0400  /* Link speed change enable */
 160#define MII_BRCM_FET_IR_DUPLEX_EN       0x0800  /* Duplex mode change enable */
 161#define MII_BRCM_FET_IR_ENABLE          0x4000  /* Interrupt enable */
 162
 163#define MII_BRCM_FET_BRCMTEST           0x1f    /* Brcm test register */
 164#define MII_BRCM_FET_BT_SRE             0x0080  /* Shadow register enable */
 165
 166
 167/*** Shadow register definitions ***/
 168
 169#define MII_BRCM_FET_SHDW_MISCCTRL      0x10    /* Shadow misc ctrl */
 170#define MII_BRCM_FET_SHDW_MC_FAME       0x4000  /* Force Auto MDIX enable */
 171
 172#define MII_BRCM_FET_SHDW_AUXMODE4      0x1a    /* Auxiliary mode 4 */
 173#define MII_BRCM_FET_SHDW_AM4_LED_MASK  0x0003
 174#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
 175
 176#define MII_BRCM_FET_SHDW_AUXSTAT2      0x1b    /* Auxiliary status 2 */
 177#define MII_BRCM_FET_SHDW_AS2_APDE      0x0020  /* Auto power down enable */
 178
 179
 180MODULE_DESCRIPTION("Broadcom PHY driver");
 181MODULE_AUTHOR("Maciej W. Rozycki");
 182MODULE_LICENSE("GPL");
 183
 184/*
 185 * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
 186 * 0x1c shadow registers.
 187 */
 188static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
 189{
 190        phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
 191        return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
 192}
 193
 194static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
 195{
 196        return phy_write(phydev, MII_BCM54XX_SHD,
 197                         MII_BCM54XX_SHD_WRITE |
 198                         MII_BCM54XX_SHD_VAL(shadow) |
 199                         MII_BCM54XX_SHD_DATA(val));
 200}
 201
 202/* Indirect register access functions for the Expansion Registers */
 203static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
 204{
 205        int val;
 206
 207        val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
 208        if (val < 0)
 209                return val;
 210
 211        val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
 212
 213        /* Restore default value.  It's O.K. if this write fails. */
 214        phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
 215
 216        return val;
 217}
 218
 219static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
 220{
 221        int ret;
 222
 223        ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
 224        if (ret < 0)
 225                return ret;
 226
 227        ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
 228
 229        /* Restore default value.  It's O.K. if this write fails. */
 230        phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
 231
 232        return ret;
 233}
 234
 235static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
 236{
 237        return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
 238}
 239
 240static int bcm50610_a0_workaround(struct phy_device *phydev)
 241{
 242        int err;
 243
 244        err = bcm54xx_auxctl_write(phydev,
 245                                   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 246                                   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
 247                                   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 248        if (err < 0)
 249                return err;
 250
 251        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
 252                                MII_BCM54XX_EXP_EXP08_RJCT_2MHZ |
 253                                MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE);
 254        if (err < 0)
 255                goto error;
 256
 257        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
 258                                MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
 259                                MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
 260        if (err < 0)
 261                goto error;
 262
 263        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
 264                                        MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
 265        if (err < 0)
 266                goto error;
 267
 268        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
 269                                MII_BCM54XX_EXP_EXP75_VDACCTRL);
 270        if (err < 0)
 271                goto error;
 272
 273        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
 274                                MII_BCM54XX_EXP_EXP96_MYST);
 275        if (err < 0)
 276                goto error;
 277
 278        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
 279                                MII_BCM54XX_EXP_EXP97_MYST);
 280
 281error:
 282        bcm54xx_auxctl_write(phydev,
 283                             MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 284                             MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 285
 286        return err;
 287}
 288
 289static int bcm54xx_config_init(struct phy_device *phydev)
 290{
 291        int reg, err;
 292
 293        reg = phy_read(phydev, MII_BCM54XX_ECR);
 294        if (reg < 0)
 295                return reg;
 296
 297        /* Mask interrupts globally.  */
 298        reg |= MII_BCM54XX_ECR_IM;
 299        err = phy_write(phydev, MII_BCM54XX_ECR, reg);
 300        if (err < 0)
 301                return err;
 302
 303        /* Unmask events we are interested in.  */
 304        reg = ~(MII_BCM54XX_INT_DUPLEX |
 305                MII_BCM54XX_INT_SPEED |
 306                MII_BCM54XX_INT_LINK);
 307        err = phy_write(phydev, MII_BCM54XX_IMR, reg);
 308        if (err < 0)
 309                return err;
 310
 311        if (phydev->drv->phy_id == PHY_ID_BCM50610) {
 312                err = bcm50610_a0_workaround(phydev);
 313                if (err < 0)
 314                        return err;
 315        }
 316
 317        if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
 318                int err2;
 319
 320                err = bcm54xx_auxctl_write(phydev,
 321                                           MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 322                                           MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
 323                                           MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 324                if (err < 0)
 325                        return err;
 326
 327                reg = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
 328                if (reg < 0)
 329                        goto error;
 330
 331                reg |= MII_BCM54XX_EXP_EXP75_CM_OSC;
 332                err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, reg);
 333
 334error:
 335                err2 = bcm54xx_auxctl_write(phydev,
 336                                            MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 337                                            MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 338                if (err)
 339                        return err;
 340                if (err2)
 341                        return err2;
 342        }
 343
 344        return 0;
 345}
 346
 347static int bcm5482_config_init(struct phy_device *phydev)
 348{
 349        int err, reg;
 350
 351        err = bcm54xx_config_init(phydev);
 352
 353        if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
 354                /*
 355                 * Enable secondary SerDes and its use as an LED source
 356                 */
 357                reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
 358                bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
 359                                     reg |
 360                                     BCM5482_SHD_SSD_LEDM |
 361                                     BCM5482_SHD_SSD_EN);
 362
 363                /*
 364                 * Enable SGMII slave mode and auto-detection
 365                 */
 366                reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
 367                err = bcm54xx_exp_read(phydev, reg);
 368                if (err < 0)
 369                        return err;
 370                err = bcm54xx_exp_write(phydev, reg, err |
 371                                        BCM5482_SSD_SGMII_SLAVE_EN |
 372                                        BCM5482_SSD_SGMII_SLAVE_AD);
 373                if (err < 0)
 374                        return err;
 375
 376                /*
 377                 * Disable secondary SerDes powerdown
 378                 */
 379                reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
 380                err = bcm54xx_exp_read(phydev, reg);
 381                if (err < 0)
 382                        return err;
 383                err = bcm54xx_exp_write(phydev, reg,
 384                                        err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
 385                if (err < 0)
 386                        return err;
 387
 388                /*
 389                 * Select 1000BASE-X register set (primary SerDes)
 390                 */
 391                reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
 392                bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
 393                                     reg | BCM5482_SHD_MODE_1000BX);
 394
 395                /*
 396                 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
 397                 * (Use LED1 as secondary SerDes ACTIVITY LED)
 398                 */
 399                bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
 400                        BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
 401                        BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
 402
 403                /*
 404                 * Auto-negotiation doesn't seem to work quite right
 405                 * in this mode, so we disable it and force it to the
 406                 * right speed/duplex setting.  Only 'link status'
 407                 * is important.
 408                 */
 409                phydev->autoneg = AUTONEG_DISABLE;
 410                phydev->speed = SPEED_1000;
 411                phydev->duplex = DUPLEX_FULL;
 412        }
 413
 414        return err;
 415}
 416
 417static int bcm5482_read_status(struct phy_device *phydev)
 418{
 419        int err;
 420
 421        err = genphy_read_status(phydev);
 422
 423        if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
 424                /*
 425                 * Only link status matters for 1000Base-X mode, so force
 426                 * 1000 Mbit/s full-duplex status
 427                 */
 428                if (phydev->link) {
 429                        phydev->speed = SPEED_1000;
 430                        phydev->duplex = DUPLEX_FULL;
 431                }
 432        }
 433
 434        return err;
 435}
 436
 437static int bcm54xx_ack_interrupt(struct phy_device *phydev)
 438{
 439        int reg;
 440
 441        /* Clear pending interrupts.  */
 442        reg = phy_read(phydev, MII_BCM54XX_ISR);
 443        if (reg < 0)
 444                return reg;
 445
 446        return 0;
 447}
 448
 449static int bcm54xx_config_intr(struct phy_device *phydev)
 450{
 451        int reg, err;
 452
 453        reg = phy_read(phydev, MII_BCM54XX_ECR);
 454        if (reg < 0)
 455                return reg;
 456
 457        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 458                reg &= ~MII_BCM54XX_ECR_IM;
 459        else
 460                reg |= MII_BCM54XX_ECR_IM;
 461
 462        err = phy_write(phydev, MII_BCM54XX_ECR, reg);
 463        return err;
 464}
 465
 466static int bcm5481_config_aneg(struct phy_device *phydev)
 467{
 468        int ret;
 469
 470        /* Aneg firsly. */
 471        ret = genphy_config_aneg(phydev);
 472
 473        /* Then we can set up the delay. */
 474        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
 475                u16 reg;
 476
 477                /*
 478                 * There is no BCM5481 specification available, so down
 479                 * here is everything we know about "register 0x18". This
 480                 * at least helps BCM5481 to successfuly receive packets
 481                 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
 482                 * says: "This sets delay between the RXD and RXC signals
 483                 * instead of using trace lengths to achieve timing".
 484                 */
 485
 486                /* Set RDX clk delay. */
 487                reg = 0x7 | (0x7 << 12);
 488                phy_write(phydev, 0x18, reg);
 489
 490                reg = phy_read(phydev, 0x18);
 491                /* Set RDX-RXC skew. */
 492                reg |= (1 << 8);
 493                /* Write bits 14:0. */
 494                reg |= (1 << 15);
 495                phy_write(phydev, 0x18, reg);
 496        }
 497
 498        return ret;
 499}
 500
 501static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
 502{
 503        int val;
 504
 505        val = phy_read(phydev, reg);
 506        if (val < 0)
 507                return val;
 508
 509        return phy_write(phydev, reg, val | set);
 510}
 511
 512static int brcm_fet_config_init(struct phy_device *phydev)
 513{
 514        int reg, err, err2, brcmtest;
 515
 516        /* Reset the PHY to bring it to a known state. */
 517        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
 518        if (err < 0)
 519                return err;
 520
 521        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 522        if (reg < 0)
 523                return reg;
 524
 525        /* Unmask events we are interested in and mask interrupts globally. */
 526        reg = MII_BRCM_FET_IR_DUPLEX_EN |
 527              MII_BRCM_FET_IR_SPEED_EN |
 528              MII_BRCM_FET_IR_LINK_EN |
 529              MII_BRCM_FET_IR_ENABLE |
 530              MII_BRCM_FET_IR_MASK;
 531
 532        err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 533        if (err < 0)
 534                return err;
 535
 536        /* Enable shadow register access */
 537        brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
 538        if (brcmtest < 0)
 539                return brcmtest;
 540
 541        reg = brcmtest | MII_BRCM_FET_BT_SRE;
 542
 543        err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
 544        if (err < 0)
 545                return err;
 546
 547        /* Set the LED mode */
 548        reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
 549        if (reg < 0) {
 550                err = reg;
 551                goto done;
 552        }
 553
 554        reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
 555        reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
 556
 557        err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
 558        if (err < 0)
 559                goto done;
 560
 561        /* Enable auto MDIX */
 562        err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
 563                                       MII_BRCM_FET_SHDW_MC_FAME);
 564        if (err < 0)
 565                goto done;
 566
 567        /* Enable auto power down */
 568        err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
 569                                       MII_BRCM_FET_SHDW_AS2_APDE);
 570
 571done:
 572        /* Disable shadow register access */
 573        err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
 574        if (!err)
 575                err = err2;
 576
 577        return err;
 578}
 579
 580static int brcm_fet_ack_interrupt(struct phy_device *phydev)
 581{
 582        int reg;
 583
 584        /* Clear pending interrupts.  */
 585        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 586        if (reg < 0)
 587                return reg;
 588
 589        return 0;
 590}
 591
 592static int brcm_fet_config_intr(struct phy_device *phydev)
 593{
 594        int reg, err;
 595
 596        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 597        if (reg < 0)
 598                return reg;
 599
 600        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 601                reg &= ~MII_BRCM_FET_IR_MASK;
 602        else
 603                reg |= MII_BRCM_FET_IR_MASK;
 604
 605        err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 606        return err;
 607}
 608
 609static struct phy_driver bcm5411_driver = {
 610        .phy_id         = 0x00206070,
 611        .phy_id_mask    = 0xfffffff0,
 612        .name           = "Broadcom BCM5411",
 613        .features       = PHY_GBIT_FEATURES |
 614                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 615        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 616        .config_init    = bcm54xx_config_init,
 617        .config_aneg    = genphy_config_aneg,
 618        .read_status    = genphy_read_status,
 619        .ack_interrupt  = bcm54xx_ack_interrupt,
 620        .config_intr    = bcm54xx_config_intr,
 621        .driver         = { .owner = THIS_MODULE },
 622};
 623
 624static struct phy_driver bcm5421_driver = {
 625        .phy_id         = 0x002060e0,
 626        .phy_id_mask    = 0xfffffff0,
 627        .name           = "Broadcom BCM5421",
 628        .features       = PHY_GBIT_FEATURES |
 629                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 630        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 631        .config_init    = bcm54xx_config_init,
 632        .config_aneg    = genphy_config_aneg,
 633        .read_status    = genphy_read_status,
 634        .ack_interrupt  = bcm54xx_ack_interrupt,
 635        .config_intr    = bcm54xx_config_intr,
 636        .driver         = { .owner = THIS_MODULE },
 637};
 638
 639static struct phy_driver bcm5461_driver = {
 640        .phy_id         = 0x002060c0,
 641        .phy_id_mask    = 0xfffffff0,
 642        .name           = "Broadcom BCM5461",
 643        .features       = PHY_GBIT_FEATURES |
 644                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 645        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 646        .config_init    = bcm54xx_config_init,
 647        .config_aneg    = genphy_config_aneg,
 648        .read_status    = genphy_read_status,
 649        .ack_interrupt  = bcm54xx_ack_interrupt,
 650        .config_intr    = bcm54xx_config_intr,
 651        .driver         = { .owner = THIS_MODULE },
 652};
 653
 654static struct phy_driver bcm5464_driver = {
 655        .phy_id         = 0x002060b0,
 656        .phy_id_mask    = 0xfffffff0,
 657        .name           = "Broadcom BCM5464",
 658        .features       = PHY_GBIT_FEATURES |
 659                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 660        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 661        .config_init    = bcm54xx_config_init,
 662        .config_aneg    = genphy_config_aneg,
 663        .read_status    = genphy_read_status,
 664        .ack_interrupt  = bcm54xx_ack_interrupt,
 665        .config_intr    = bcm54xx_config_intr,
 666        .driver         = { .owner = THIS_MODULE },
 667};
 668
 669static struct phy_driver bcm5481_driver = {
 670        .phy_id         = 0x0143bca0,
 671        .phy_id_mask    = 0xfffffff0,
 672        .name           = "Broadcom BCM5481",
 673        .features       = PHY_GBIT_FEATURES |
 674                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 675        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 676        .config_init    = bcm54xx_config_init,
 677        .config_aneg    = bcm5481_config_aneg,
 678        .read_status    = genphy_read_status,
 679        .ack_interrupt  = bcm54xx_ack_interrupt,
 680        .config_intr    = bcm54xx_config_intr,
 681        .driver         = { .owner = THIS_MODULE },
 682};
 683
 684static struct phy_driver bcm5482_driver = {
 685        .phy_id         = 0x0143bcb0,
 686        .phy_id_mask    = 0xfffffff0,
 687        .name           = "Broadcom BCM5482",
 688        .features       = PHY_GBIT_FEATURES |
 689                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 690        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 691        .config_init    = bcm5482_config_init,
 692        .config_aneg    = genphy_config_aneg,
 693        .read_status    = bcm5482_read_status,
 694        .ack_interrupt  = bcm54xx_ack_interrupt,
 695        .config_intr    = bcm54xx_config_intr,
 696        .driver         = { .owner = THIS_MODULE },
 697};
 698
 699static struct phy_driver bcm50610_driver = {
 700        .phy_id         = PHY_ID_BCM50610,
 701        .phy_id_mask    = 0xfffffff0,
 702        .name           = "Broadcom BCM50610",
 703        .features       = PHY_GBIT_FEATURES |
 704                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 705        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 706        .config_init    = bcm54xx_config_init,
 707        .config_aneg    = genphy_config_aneg,
 708        .read_status    = genphy_read_status,
 709        .ack_interrupt  = bcm54xx_ack_interrupt,
 710        .config_intr    = bcm54xx_config_intr,
 711        .driver         = { .owner = THIS_MODULE },
 712};
 713
 714static struct phy_driver bcm50610m_driver = {
 715        .phy_id         = PHY_ID_BCM50610M,
 716        .phy_id_mask    = 0xfffffff0,
 717        .name           = "Broadcom BCM50610M",
 718        .features       = PHY_GBIT_FEATURES |
 719                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 720        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 721        .config_init    = bcm54xx_config_init,
 722        .config_aneg    = genphy_config_aneg,
 723        .read_status    = genphy_read_status,
 724        .ack_interrupt  = bcm54xx_ack_interrupt,
 725        .config_intr    = bcm54xx_config_intr,
 726        .driver         = { .owner = THIS_MODULE },
 727};
 728
 729static struct phy_driver bcm57780_driver = {
 730        .phy_id         = PHY_ID_BCM57780,
 731        .phy_id_mask    = 0xfffffff0,
 732        .name           = "Broadcom BCM57780",
 733        .features       = PHY_GBIT_FEATURES |
 734                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 735        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 736        .config_init    = bcm54xx_config_init,
 737        .config_aneg    = genphy_config_aneg,
 738        .read_status    = genphy_read_status,
 739        .ack_interrupt  = bcm54xx_ack_interrupt,
 740        .config_intr    = bcm54xx_config_intr,
 741        .driver         = { .owner = THIS_MODULE },
 742};
 743
 744static struct phy_driver bcmac131_driver = {
 745        .phy_id         = 0x0143bc70,
 746        .phy_id_mask    = 0xfffffff0,
 747        .name           = "Broadcom BCMAC131",
 748        .features       = PHY_BASIC_FEATURES |
 749                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 750        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 751        .config_init    = brcm_fet_config_init,
 752        .config_aneg    = genphy_config_aneg,
 753        .read_status    = genphy_read_status,
 754        .ack_interrupt  = brcm_fet_ack_interrupt,
 755        .config_intr    = brcm_fet_config_intr,
 756        .driver         = { .owner = THIS_MODULE },
 757};
 758
 759static int __init broadcom_init(void)
 760{
 761        int ret;
 762
 763        ret = phy_driver_register(&bcm5411_driver);
 764        if (ret)
 765                goto out_5411;
 766        ret = phy_driver_register(&bcm5421_driver);
 767        if (ret)
 768                goto out_5421;
 769        ret = phy_driver_register(&bcm5461_driver);
 770        if (ret)
 771                goto out_5461;
 772        ret = phy_driver_register(&bcm5464_driver);
 773        if (ret)
 774                goto out_5464;
 775        ret = phy_driver_register(&bcm5481_driver);
 776        if (ret)
 777                goto out_5481;
 778        ret = phy_driver_register(&bcm5482_driver);
 779        if (ret)
 780                goto out_5482;
 781        ret = phy_driver_register(&bcm50610_driver);
 782        if (ret)
 783                goto out_50610;
 784        ret = phy_driver_register(&bcm50610m_driver);
 785        if (ret)
 786                goto out_50610m;
 787        ret = phy_driver_register(&bcm57780_driver);
 788        if (ret)
 789                goto out_57780;
 790        ret = phy_driver_register(&bcmac131_driver);
 791        if (ret)
 792                goto out_ac131;
 793        return ret;
 794
 795out_ac131:
 796        phy_driver_unregister(&bcm57780_driver);
 797out_57780:
 798        phy_driver_unregister(&bcm50610m_driver);
 799out_50610m:
 800        phy_driver_unregister(&bcm50610_driver);
 801out_50610:
 802        phy_driver_unregister(&bcm5482_driver);
 803out_5482:
 804        phy_driver_unregister(&bcm5481_driver);
 805out_5481:
 806        phy_driver_unregister(&bcm5464_driver);
 807out_5464:
 808        phy_driver_unregister(&bcm5461_driver);
 809out_5461:
 810        phy_driver_unregister(&bcm5421_driver);
 811out_5421:
 812        phy_driver_unregister(&bcm5411_driver);
 813out_5411:
 814        return ret;
 815}
 816
 817static void __exit broadcom_exit(void)
 818{
 819        phy_driver_unregister(&bcmac131_driver);
 820        phy_driver_unregister(&bcm57780_driver);
 821        phy_driver_unregister(&bcm50610m_driver);
 822        phy_driver_unregister(&bcm50610_driver);
 823        phy_driver_unregister(&bcm5482_driver);
 824        phy_driver_unregister(&bcm5481_driver);
 825        phy_driver_unregister(&bcm5464_driver);
 826        phy_driver_unregister(&bcm5461_driver);
 827        phy_driver_unregister(&bcm5421_driver);
 828        phy_driver_unregister(&bcm5411_driver);
 829}
 830
 831module_init(broadcom_init);
 832module_exit(broadcom_exit);
 833