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 "bcm-phy-lib.h"
  18#include <linux/module.h>
  19#include <linux/phy.h>
  20#include <linux/brcmphy.h>
  21#include <linux/of.h>
  22
  23#define BRCM_PHY_MODEL(phydev) \
  24        ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
  25
  26#define BRCM_PHY_REV(phydev) \
  27        ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
  28
  29MODULE_DESCRIPTION("Broadcom PHY driver");
  30MODULE_AUTHOR("Maciej W. Rozycki");
  31MODULE_LICENSE("GPL");
  32
  33static int bcm54210e_config_init(struct phy_device *phydev)
  34{
  35        int val;
  36
  37        val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  38        val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  39        val |= MII_BCM54XX_AUXCTL_MISC_WREN;
  40        bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val);
  41
  42        val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
  43        val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
  44        bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
  45
  46        return 0;
  47}
  48
  49static int bcm54612e_config_init(struct phy_device *phydev)
  50{
  51        /* Clear TX internal delay unless requested. */
  52        if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
  53            (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
  54                /* Disable TXD to GTXCLK clock delay (default set) */
  55                /* Bit 9 is the only field in shadow register 00011 */
  56                bcm_phy_write_shadow(phydev, 0x03, 0);
  57        }
  58
  59        /* Clear RX internal delay unless requested. */
  60        if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
  61            (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
  62                u16 reg;
  63
  64                reg = bcm54xx_auxctl_read(phydev,
  65                                          MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  66                /* Disable RXD to RXC delay (default set) */
  67                reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  68                /* Clear shadow selector field */
  69                reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
  70                bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  71                                     MII_BCM54XX_AUXCTL_MISC_WREN | reg);
  72        }
  73
  74        return 0;
  75}
  76
  77static int bcm54810_config(struct phy_device *phydev)
  78{
  79        int rc, val;
  80
  81        val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
  82        val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
  83        rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
  84                               val);
  85        if (rc < 0)
  86                return rc;
  87
  88        val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  89        val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  90        val |= MII_BCM54XX_AUXCTL_MISC_WREN;
  91        rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  92                                  val);
  93        if (rc < 0)
  94                return rc;
  95
  96        val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
  97        val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
  98        rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
  99        if (rc < 0)
 100                return rc;
 101
 102        return 0;
 103}
 104
 105/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
 106static int bcm50610_a0_workaround(struct phy_device *phydev)
 107{
 108        int err;
 109
 110        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
 111                                MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
 112                                MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
 113        if (err < 0)
 114                return err;
 115
 116        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
 117                                MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
 118        if (err < 0)
 119                return err;
 120
 121        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
 122                                MII_BCM54XX_EXP_EXP75_VDACCTRL);
 123        if (err < 0)
 124                return err;
 125
 126        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
 127                                MII_BCM54XX_EXP_EXP96_MYST);
 128        if (err < 0)
 129                return err;
 130
 131        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
 132                                MII_BCM54XX_EXP_EXP97_MYST);
 133
 134        return err;
 135}
 136
 137static int bcm54xx_phydsp_config(struct phy_device *phydev)
 138{
 139        int err, err2;
 140
 141        /* Enable the SMDSP clock */
 142        err = bcm54xx_auxctl_write(phydev,
 143                                   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 144                                   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
 145                                   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 146        if (err < 0)
 147                return err;
 148
 149        if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 150            BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
 151                /* Clear bit 9 to fix a phy interop issue. */
 152                err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
 153                                        MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
 154                if (err < 0)
 155                        goto error;
 156
 157                if (phydev->drv->phy_id == PHY_ID_BCM50610) {
 158                        err = bcm50610_a0_workaround(phydev);
 159                        if (err < 0)
 160                                goto error;
 161                }
 162        }
 163
 164        if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
 165                int val;
 166
 167                val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
 168                if (val < 0)
 169                        goto error;
 170
 171                val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
 172                err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
 173        }
 174
 175error:
 176        /* Disable the SMDSP clock */
 177        err2 = bcm54xx_auxctl_write(phydev,
 178                                    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 179                                    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 180
 181        /* Return the first error reported. */
 182        return err ? err : err2;
 183}
 184
 185static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
 186{
 187        u32 orig;
 188        int val;
 189        bool clk125en = true;
 190
 191        /* Abort if we are using an untested phy. */
 192        if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
 193            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
 194            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
 195                return;
 196
 197        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
 198        if (val < 0)
 199                return;
 200
 201        orig = val;
 202
 203        if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 204             BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
 205            BRCM_PHY_REV(phydev) >= 0x3) {
 206                /*
 207                 * Here, bit 0 _disables_ CLK125 when set.
 208                 * This bit is set by default.
 209                 */
 210                clk125en = false;
 211        } else {
 212                if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
 213                        /* Here, bit 0 _enables_ CLK125 when set */
 214                        val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
 215                        clk125en = false;
 216                }
 217        }
 218
 219        if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
 220                val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
 221        else
 222                val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
 223
 224        if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
 225                val |= BCM54XX_SHD_SCR3_TRDDAPD;
 226
 227        if (orig != val)
 228                bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
 229
 230        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
 231        if (val < 0)
 232                return;
 233
 234        orig = val;
 235
 236        if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
 237                val |= BCM54XX_SHD_APD_EN;
 238        else
 239                val &= ~BCM54XX_SHD_APD_EN;
 240
 241        if (orig != val)
 242                bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
 243}
 244
 245static int bcm54xx_config_init(struct phy_device *phydev)
 246{
 247        int reg, err;
 248
 249        reg = phy_read(phydev, MII_BCM54XX_ECR);
 250        if (reg < 0)
 251                return reg;
 252
 253        /* Mask interrupts globally.  */
 254        reg |= MII_BCM54XX_ECR_IM;
 255        err = phy_write(phydev, MII_BCM54XX_ECR, reg);
 256        if (err < 0)
 257                return err;
 258
 259        /* Unmask events we are interested in.  */
 260        reg = ~(MII_BCM54XX_INT_DUPLEX |
 261                MII_BCM54XX_INT_SPEED |
 262                MII_BCM54XX_INT_LINK);
 263        err = phy_write(phydev, MII_BCM54XX_IMR, reg);
 264        if (err < 0)
 265                return err;
 266
 267        if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 268             BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
 269            (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
 270                bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
 271
 272        if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
 273            (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
 274            (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
 275                bcm54xx_adjust_rxrefclk(phydev);
 276
 277        if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) {
 278                err = bcm54210e_config_init(phydev);
 279                if (err)
 280                        return err;
 281        } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
 282                err = bcm54612e_config_init(phydev);
 283                if (err)
 284                        return err;
 285        } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
 286                err = bcm54810_config(phydev);
 287                if (err)
 288                        return err;
 289        }
 290
 291        bcm54xx_phydsp_config(phydev);
 292
 293        return 0;
 294}
 295
 296static int bcm5482_config_init(struct phy_device *phydev)
 297{
 298        int err, reg;
 299
 300        err = bcm54xx_config_init(phydev);
 301
 302        if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
 303                /*
 304                 * Enable secondary SerDes and its use as an LED source
 305                 */
 306                reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
 307                bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
 308                                     reg |
 309                                     BCM5482_SHD_SSD_LEDM |
 310                                     BCM5482_SHD_SSD_EN);
 311
 312                /*
 313                 * Enable SGMII slave mode and auto-detection
 314                 */
 315                reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
 316                err = bcm_phy_read_exp(phydev, reg);
 317                if (err < 0)
 318                        return err;
 319                err = bcm_phy_write_exp(phydev, reg, err |
 320                                        BCM5482_SSD_SGMII_SLAVE_EN |
 321                                        BCM5482_SSD_SGMII_SLAVE_AD);
 322                if (err < 0)
 323                        return err;
 324
 325                /*
 326                 * Disable secondary SerDes powerdown
 327                 */
 328                reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
 329                err = bcm_phy_read_exp(phydev, reg);
 330                if (err < 0)
 331                        return err;
 332                err = bcm_phy_write_exp(phydev, reg,
 333                                        err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
 334                if (err < 0)
 335                        return err;
 336
 337                /*
 338                 * Select 1000BASE-X register set (primary SerDes)
 339                 */
 340                reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
 341                bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
 342                                     reg | BCM5482_SHD_MODE_1000BX);
 343
 344                /*
 345                 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
 346                 * (Use LED1 as secondary SerDes ACTIVITY LED)
 347                 */
 348                bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
 349                        BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
 350                        BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
 351
 352                /*
 353                 * Auto-negotiation doesn't seem to work quite right
 354                 * in this mode, so we disable it and force it to the
 355                 * right speed/duplex setting.  Only 'link status'
 356                 * is important.
 357                 */
 358                phydev->autoneg = AUTONEG_DISABLE;
 359                phydev->speed = SPEED_1000;
 360                phydev->duplex = DUPLEX_FULL;
 361        }
 362
 363        return err;
 364}
 365
 366static int bcm5482_read_status(struct phy_device *phydev)
 367{
 368        int err;
 369
 370        err = genphy_read_status(phydev);
 371
 372        if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
 373                /*
 374                 * Only link status matters for 1000Base-X mode, so force
 375                 * 1000 Mbit/s full-duplex status
 376                 */
 377                if (phydev->link) {
 378                        phydev->speed = SPEED_1000;
 379                        phydev->duplex = DUPLEX_FULL;
 380                }
 381        }
 382
 383        return err;
 384}
 385
 386static int bcm5481_config_aneg(struct phy_device *phydev)
 387{
 388        struct device_node *np = phydev->mdio.dev.of_node;
 389        int ret;
 390
 391        /* Aneg firsly. */
 392        ret = genphy_config_aneg(phydev);
 393
 394        /* Then we can set up the delay. */
 395        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
 396                u16 reg;
 397
 398                /*
 399                 * There is no BCM5481 specification available, so down
 400                 * here is everything we know about "register 0x18". This
 401                 * at least helps BCM5481 to successfully receive packets
 402                 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
 403                 * says: "This sets delay between the RXD and RXC signals
 404                 * instead of using trace lengths to achieve timing".
 405                 */
 406
 407                /* Set RDX clk delay. */
 408                reg = 0x7 | (0x7 << 12);
 409                phy_write(phydev, 0x18, reg);
 410
 411                reg = phy_read(phydev, 0x18);
 412                /* Set RDX-RXC skew. */
 413                reg |= (1 << 8);
 414                /* Write bits 14:0. */
 415                reg |= (1 << 15);
 416                phy_write(phydev, 0x18, reg);
 417        }
 418
 419        if (of_property_read_bool(np, "enet-phy-lane-swap")) {
 420                /* Lane Swap - Undocumented register...magic! */
 421                ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
 422                                        0x11B);
 423                if (ret < 0)
 424                        return ret;
 425        }
 426
 427        return ret;
 428}
 429
 430static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
 431{
 432        int val;
 433
 434        val = phy_read(phydev, reg);
 435        if (val < 0)
 436                return val;
 437
 438        return phy_write(phydev, reg, val | set);
 439}
 440
 441static int brcm_fet_config_init(struct phy_device *phydev)
 442{
 443        int reg, err, err2, brcmtest;
 444
 445        /* Reset the PHY to bring it to a known state. */
 446        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
 447        if (err < 0)
 448                return err;
 449
 450        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 451        if (reg < 0)
 452                return reg;
 453
 454        /* Unmask events we are interested in and mask interrupts globally. */
 455        reg = MII_BRCM_FET_IR_DUPLEX_EN |
 456              MII_BRCM_FET_IR_SPEED_EN |
 457              MII_BRCM_FET_IR_LINK_EN |
 458              MII_BRCM_FET_IR_ENABLE |
 459              MII_BRCM_FET_IR_MASK;
 460
 461        err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 462        if (err < 0)
 463                return err;
 464
 465        /* Enable shadow register access */
 466        brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
 467        if (brcmtest < 0)
 468                return brcmtest;
 469
 470        reg = brcmtest | MII_BRCM_FET_BT_SRE;
 471
 472        err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
 473        if (err < 0)
 474                return err;
 475
 476        /* Set the LED mode */
 477        reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
 478        if (reg < 0) {
 479                err = reg;
 480                goto done;
 481        }
 482
 483        reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
 484        reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
 485
 486        err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
 487        if (err < 0)
 488                goto done;
 489
 490        /* Enable auto MDIX */
 491        err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
 492                                       MII_BRCM_FET_SHDW_MC_FAME);
 493        if (err < 0)
 494                goto done;
 495
 496        if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
 497                /* Enable auto power down */
 498                err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
 499                                               MII_BRCM_FET_SHDW_AS2_APDE);
 500        }
 501
 502done:
 503        /* Disable shadow register access */
 504        err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
 505        if (!err)
 506                err = err2;
 507
 508        return err;
 509}
 510
 511static int brcm_fet_ack_interrupt(struct phy_device *phydev)
 512{
 513        int reg;
 514
 515        /* Clear pending interrupts.  */
 516        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 517        if (reg < 0)
 518                return reg;
 519
 520        return 0;
 521}
 522
 523static int brcm_fet_config_intr(struct phy_device *phydev)
 524{
 525        int reg, err;
 526
 527        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 528        if (reg < 0)
 529                return reg;
 530
 531        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 532                reg &= ~MII_BRCM_FET_IR_MASK;
 533        else
 534                reg |= MII_BRCM_FET_IR_MASK;
 535
 536        err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 537        return err;
 538}
 539
 540static struct phy_driver broadcom_drivers[] = {
 541{
 542        .phy_id         = PHY_ID_BCM5411,
 543        .phy_id_mask    = 0xfffffff0,
 544        .name           = "Broadcom BCM5411",
 545        .features       = PHY_GBIT_FEATURES,
 546        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 547        .config_init    = bcm54xx_config_init,
 548        .config_aneg    = genphy_config_aneg,
 549        .read_status    = genphy_read_status,
 550        .ack_interrupt  = bcm_phy_ack_intr,
 551        .config_intr    = bcm_phy_config_intr,
 552}, {
 553        .phy_id         = PHY_ID_BCM5421,
 554        .phy_id_mask    = 0xfffffff0,
 555        .name           = "Broadcom BCM5421",
 556        .features       = PHY_GBIT_FEATURES,
 557        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 558        .config_init    = bcm54xx_config_init,
 559        .config_aneg    = genphy_config_aneg,
 560        .read_status    = genphy_read_status,
 561        .ack_interrupt  = bcm_phy_ack_intr,
 562        .config_intr    = bcm_phy_config_intr,
 563}, {
 564        .phy_id         = PHY_ID_BCM54210E,
 565        .phy_id_mask    = 0xfffffff0,
 566        .name           = "Broadcom BCM54210E",
 567        .features       = PHY_GBIT_FEATURES,
 568        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 569        .config_init    = bcm54xx_config_init,
 570        .config_aneg    = genphy_config_aneg,
 571        .read_status    = genphy_read_status,
 572        .ack_interrupt  = bcm_phy_ack_intr,
 573        .config_intr    = bcm_phy_config_intr,
 574}, {
 575        .phy_id         = PHY_ID_BCM5461,
 576        .phy_id_mask    = 0xfffffff0,
 577        .name           = "Broadcom BCM5461",
 578        .features       = PHY_GBIT_FEATURES,
 579        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 580        .config_init    = bcm54xx_config_init,
 581        .config_aneg    = genphy_config_aneg,
 582        .read_status    = genphy_read_status,
 583        .ack_interrupt  = bcm_phy_ack_intr,
 584        .config_intr    = bcm_phy_config_intr,
 585}, {
 586        .phy_id         = PHY_ID_BCM54612E,
 587        .phy_id_mask    = 0xfffffff0,
 588        .name           = "Broadcom BCM54612E",
 589        .features       = PHY_GBIT_FEATURES,
 590        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 591        .config_init    = bcm54xx_config_init,
 592        .config_aneg    = genphy_config_aneg,
 593        .read_status    = genphy_read_status,
 594        .ack_interrupt  = bcm_phy_ack_intr,
 595        .config_intr    = bcm_phy_config_intr,
 596}, {
 597        .phy_id         = PHY_ID_BCM54616S,
 598        .phy_id_mask    = 0xfffffff0,
 599        .name           = "Broadcom BCM54616S",
 600        .features       = PHY_GBIT_FEATURES,
 601        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 602        .config_init    = bcm54xx_config_init,
 603        .config_aneg    = genphy_config_aneg,
 604        .read_status    = genphy_read_status,
 605        .ack_interrupt  = bcm_phy_ack_intr,
 606        .config_intr    = bcm_phy_config_intr,
 607}, {
 608        .phy_id         = PHY_ID_BCM5464,
 609        .phy_id_mask    = 0xfffffff0,
 610        .name           = "Broadcom BCM5464",
 611        .features       = PHY_GBIT_FEATURES,
 612        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 613        .config_init    = bcm54xx_config_init,
 614        .config_aneg    = genphy_config_aneg,
 615        .read_status    = genphy_read_status,
 616        .ack_interrupt  = bcm_phy_ack_intr,
 617        .config_intr    = bcm_phy_config_intr,
 618}, {
 619        .phy_id         = PHY_ID_BCM5481,
 620        .phy_id_mask    = 0xfffffff0,
 621        .name           = "Broadcom BCM5481",
 622        .features       = PHY_GBIT_FEATURES,
 623        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 624        .config_init    = bcm54xx_config_init,
 625        .config_aneg    = bcm5481_config_aneg,
 626        .read_status    = genphy_read_status,
 627        .ack_interrupt  = bcm_phy_ack_intr,
 628        .config_intr    = bcm_phy_config_intr,
 629}, {
 630        .phy_id         = PHY_ID_BCM54810,
 631        .phy_id_mask    = 0xfffffff0,
 632        .name           = "Broadcom BCM54810",
 633        .features       = PHY_GBIT_FEATURES,
 634        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 635        .config_init    = bcm54xx_config_init,
 636        .config_aneg    = bcm5481_config_aneg,
 637        .read_status    = genphy_read_status,
 638        .ack_interrupt  = bcm_phy_ack_intr,
 639        .config_intr    = bcm_phy_config_intr,
 640}, {
 641        .phy_id         = PHY_ID_BCM5482,
 642        .phy_id_mask    = 0xfffffff0,
 643        .name           = "Broadcom BCM5482",
 644        .features       = PHY_GBIT_FEATURES,
 645        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 646        .config_init    = bcm5482_config_init,
 647        .config_aneg    = genphy_config_aneg,
 648        .read_status    = bcm5482_read_status,
 649        .ack_interrupt  = bcm_phy_ack_intr,
 650        .config_intr    = bcm_phy_config_intr,
 651}, {
 652        .phy_id         = PHY_ID_BCM50610,
 653        .phy_id_mask    = 0xfffffff0,
 654        .name           = "Broadcom BCM50610",
 655        .features       = PHY_GBIT_FEATURES,
 656        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 657        .config_init    = bcm54xx_config_init,
 658        .config_aneg    = genphy_config_aneg,
 659        .read_status    = genphy_read_status,
 660        .ack_interrupt  = bcm_phy_ack_intr,
 661        .config_intr    = bcm_phy_config_intr,
 662}, {
 663        .phy_id         = PHY_ID_BCM50610M,
 664        .phy_id_mask    = 0xfffffff0,
 665        .name           = "Broadcom BCM50610M",
 666        .features       = PHY_GBIT_FEATURES,
 667        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 668        .config_init    = bcm54xx_config_init,
 669        .config_aneg    = genphy_config_aneg,
 670        .read_status    = genphy_read_status,
 671        .ack_interrupt  = bcm_phy_ack_intr,
 672        .config_intr    = bcm_phy_config_intr,
 673}, {
 674        .phy_id         = PHY_ID_BCM57780,
 675        .phy_id_mask    = 0xfffffff0,
 676        .name           = "Broadcom BCM57780",
 677        .features       = PHY_GBIT_FEATURES,
 678        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 679        .config_init    = bcm54xx_config_init,
 680        .config_aneg    = genphy_config_aneg,
 681        .read_status    = genphy_read_status,
 682        .ack_interrupt  = bcm_phy_ack_intr,
 683        .config_intr    = bcm_phy_config_intr,
 684}, {
 685        .phy_id         = PHY_ID_BCMAC131,
 686        .phy_id_mask    = 0xfffffff0,
 687        .name           = "Broadcom BCMAC131",
 688        .features       = PHY_BASIC_FEATURES,
 689        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 690        .config_init    = brcm_fet_config_init,
 691        .config_aneg    = genphy_config_aneg,
 692        .read_status    = genphy_read_status,
 693        .ack_interrupt  = brcm_fet_ack_interrupt,
 694        .config_intr    = brcm_fet_config_intr,
 695}, {
 696        .phy_id         = PHY_ID_BCM5241,
 697        .phy_id_mask    = 0xfffffff0,
 698        .name           = "Broadcom BCM5241",
 699        .features       = PHY_BASIC_FEATURES,
 700        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 701        .config_init    = brcm_fet_config_init,
 702        .config_aneg    = genphy_config_aneg,
 703        .read_status    = genphy_read_status,
 704        .ack_interrupt  = brcm_fet_ack_interrupt,
 705        .config_intr    = brcm_fet_config_intr,
 706} };
 707
 708module_phy_driver(broadcom_drivers);
 709
 710static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
 711        { PHY_ID_BCM5411, 0xfffffff0 },
 712        { PHY_ID_BCM5421, 0xfffffff0 },
 713        { PHY_ID_BCM54210E, 0xfffffff0 },
 714        { PHY_ID_BCM5461, 0xfffffff0 },
 715        { PHY_ID_BCM54612E, 0xfffffff0 },
 716        { PHY_ID_BCM54616S, 0xfffffff0 },
 717        { PHY_ID_BCM5464, 0xfffffff0 },
 718        { PHY_ID_BCM5481, 0xfffffff0 },
 719        { PHY_ID_BCM54810, 0xfffffff0 },
 720        { PHY_ID_BCM5482, 0xfffffff0 },
 721        { PHY_ID_BCM50610, 0xfffffff0 },
 722        { PHY_ID_BCM50610M, 0xfffffff0 },
 723        { PHY_ID_BCM57780, 0xfffffff0 },
 724        { PHY_ID_BCMAC131, 0xfffffff0 },
 725        { PHY_ID_BCM5241, 0xfffffff0 },
 726        { }
 727};
 728
 729MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
 730