linux/drivers/net/phy/broadcom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *      drivers/net/phy/broadcom.c
   4 *
   5 *      Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
   6 *      transceivers.
   7 *
   8 *      Copyright (c) 2006  Maciej W. Rozycki
   9 *
  10 *      Inspired by code written by Amy Fong.
  11 */
  12
  13#include "bcm-phy-lib.h"
  14#include <linux/module.h>
  15#include <linux/phy.h>
  16#include <linux/brcmphy.h>
  17#include <linux/of.h>
  18
  19#define BRCM_PHY_MODEL(phydev) \
  20        ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
  21
  22#define BRCM_PHY_REV(phydev) \
  23        ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
  24
  25MODULE_DESCRIPTION("Broadcom PHY driver");
  26MODULE_AUTHOR("Maciej W. Rozycki");
  27MODULE_LICENSE("GPL");
  28
  29static int bcm54xx_config_clock_delay(struct phy_device *phydev)
  30{
  31        int rc, val;
  32
  33        /* handling PHY's internal RX clock delay */
  34        val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  35        val |= MII_BCM54XX_AUXCTL_MISC_WREN;
  36        if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
  37            phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
  38                /* Disable RGMII RXC-RXD skew */
  39                val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  40        }
  41        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  42            phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
  43                /* Enable RGMII RXC-RXD skew */
  44                val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  45        }
  46        rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  47                                  val);
  48        if (rc < 0)
  49                return rc;
  50
  51        /* handling PHY's internal TX clock delay */
  52        val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
  53        if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
  54            phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
  55                /* Disable internal TX clock delay */
  56                val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
  57        }
  58        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  59            phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
  60                /* Enable internal TX clock delay */
  61                val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
  62        }
  63        rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
  64        if (rc < 0)
  65                return rc;
  66
  67        return 0;
  68}
  69
  70static int bcm54210e_config_init(struct phy_device *phydev)
  71{
  72        int val;
  73
  74        bcm54xx_config_clock_delay(phydev);
  75
  76        if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
  77                val = phy_read(phydev, MII_CTRL1000);
  78                val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
  79                phy_write(phydev, MII_CTRL1000, val);
  80        }
  81
  82        return 0;
  83}
  84
  85static int bcm54612e_config_init(struct phy_device *phydev)
  86{
  87        int reg;
  88
  89        bcm54xx_config_clock_delay(phydev);
  90
  91        /* Enable CLK125 MUX on LED4 if ref clock is enabled. */
  92        if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
  93                int err;
  94
  95                reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
  96                err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
  97                                        BCM54612E_LED4_CLK125OUT_EN | reg);
  98
  99                if (err < 0)
 100                        return err;
 101        }
 102
 103        return 0;
 104}
 105
 106static int bcm54616s_config_init(struct phy_device *phydev)
 107{
 108        int rc, val;
 109
 110        if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
 111            phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
 112                return 0;
 113
 114        /* Ensure proper interface mode is selected. */
 115        /* Disable RGMII mode */
 116        val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
 117        if (val < 0)
 118                return val;
 119        val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
 120        val |= MII_BCM54XX_AUXCTL_MISC_WREN;
 121        rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
 122                                  val);
 123        if (rc < 0)
 124                return rc;
 125
 126        /* Select 1000BASE-X register set (primary SerDes) */
 127        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
 128        if (val < 0)
 129                return val;
 130        val |= BCM54XX_SHD_MODE_1000BX;
 131        rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
 132        if (rc < 0)
 133                return rc;
 134
 135        /* Power down SerDes interface */
 136        rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
 137        if (rc < 0)
 138                return rc;
 139
 140        /* Select proper interface mode */
 141        val &= ~BCM54XX_SHD_INTF_SEL_MASK;
 142        val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
 143                BCM54XX_SHD_INTF_SEL_SGMII :
 144                BCM54XX_SHD_INTF_SEL_GBIC;
 145        rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
 146        if (rc < 0)
 147                return rc;
 148
 149        /* Power up SerDes interface */
 150        rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
 151        if (rc < 0)
 152                return rc;
 153
 154        /* Select copper register set */
 155        val &= ~BCM54XX_SHD_MODE_1000BX;
 156        rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
 157        if (rc < 0)
 158                return rc;
 159
 160        /* Power up copper interface */
 161        return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
 162}
 163
 164/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
 165static int bcm50610_a0_workaround(struct phy_device *phydev)
 166{
 167        int err;
 168
 169        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
 170                                MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
 171                                MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
 172        if (err < 0)
 173                return err;
 174
 175        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
 176                                MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
 177        if (err < 0)
 178                return err;
 179
 180        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
 181                                MII_BCM54XX_EXP_EXP75_VDACCTRL);
 182        if (err < 0)
 183                return err;
 184
 185        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
 186                                MII_BCM54XX_EXP_EXP96_MYST);
 187        if (err < 0)
 188                return err;
 189
 190        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
 191                                MII_BCM54XX_EXP_EXP97_MYST);
 192
 193        return err;
 194}
 195
 196static int bcm54xx_phydsp_config(struct phy_device *phydev)
 197{
 198        int err, err2;
 199
 200        /* Enable the SMDSP clock */
 201        err = bcm54xx_auxctl_write(phydev,
 202                                   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 203                                   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
 204                                   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 205        if (err < 0)
 206                return err;
 207
 208        if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 209            BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
 210                /* Clear bit 9 to fix a phy interop issue. */
 211                err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
 212                                        MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
 213                if (err < 0)
 214                        goto error;
 215
 216                if (phydev->drv->phy_id == PHY_ID_BCM50610) {
 217                        err = bcm50610_a0_workaround(phydev);
 218                        if (err < 0)
 219                                goto error;
 220                }
 221        }
 222
 223        if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
 224                int val;
 225
 226                val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
 227                if (val < 0)
 228                        goto error;
 229
 230                val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
 231                err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
 232        }
 233
 234error:
 235        /* Disable the SMDSP clock */
 236        err2 = bcm54xx_auxctl_write(phydev,
 237                                    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
 238                                    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
 239
 240        /* Return the first error reported. */
 241        return err ? err : err2;
 242}
 243
 244static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
 245{
 246        u32 orig;
 247        int val;
 248        bool clk125en = true;
 249
 250        /* Abort if we are using an untested phy. */
 251        if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
 252            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
 253            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
 254            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E &&
 255            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
 256            BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
 257                return;
 258
 259        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
 260        if (val < 0)
 261                return;
 262
 263        orig = val;
 264
 265        if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 266             BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
 267            BRCM_PHY_REV(phydev) >= 0x3) {
 268                /*
 269                 * Here, bit 0 _disables_ CLK125 when set.
 270                 * This bit is set by default.
 271                 */
 272                clk125en = false;
 273        } else {
 274                if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
 275                        if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) {
 276                                /* Here, bit 0 _enables_ CLK125 when set */
 277                                val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
 278                        }
 279                        clk125en = false;
 280                }
 281        }
 282
 283        if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
 284                val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
 285        else
 286                val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
 287
 288        if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
 289                if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
 290                    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
 291                    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
 292                        val |= BCM54XX_SHD_SCR3_RXCTXC_DIS;
 293                else
 294                        val |= BCM54XX_SHD_SCR3_TRDDAPD;
 295        }
 296
 297        if (orig != val)
 298                bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
 299
 300        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
 301        if (val < 0)
 302                return;
 303
 304        orig = val;
 305
 306        if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
 307                val |= BCM54XX_SHD_APD_EN;
 308        else
 309                val &= ~BCM54XX_SHD_APD_EN;
 310
 311        if (orig != val)
 312                bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
 313}
 314
 315static int bcm54xx_config_init(struct phy_device *phydev)
 316{
 317        int reg, err, val;
 318
 319        reg = phy_read(phydev, MII_BCM54XX_ECR);
 320        if (reg < 0)
 321                return reg;
 322
 323        /* Mask interrupts globally.  */
 324        reg |= MII_BCM54XX_ECR_IM;
 325        err = phy_write(phydev, MII_BCM54XX_ECR, reg);
 326        if (err < 0)
 327                return err;
 328
 329        /* Unmask events we are interested in.  */
 330        reg = ~(MII_BCM54XX_INT_DUPLEX |
 331                MII_BCM54XX_INT_SPEED |
 332                MII_BCM54XX_INT_LINK);
 333        err = phy_write(phydev, MII_BCM54XX_IMR, reg);
 334        if (err < 0)
 335                return err;
 336
 337        if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 338             BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
 339            (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
 340                bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
 341
 342        bcm54xx_adjust_rxrefclk(phydev);
 343
 344        switch (BRCM_PHY_MODEL(phydev)) {
 345        case PHY_ID_BCM50610:
 346        case PHY_ID_BCM50610M:
 347                err = bcm54xx_config_clock_delay(phydev);
 348                break;
 349        case PHY_ID_BCM54210E:
 350                err = bcm54210e_config_init(phydev);
 351                break;
 352        case PHY_ID_BCM54612E:
 353                err = bcm54612e_config_init(phydev);
 354                break;
 355        case PHY_ID_BCM54616S:
 356                err = bcm54616s_config_init(phydev);
 357                break;
 358        case PHY_ID_BCM54810:
 359                /* For BCM54810, we need to disable BroadR-Reach function */
 360                val = bcm_phy_read_exp(phydev,
 361                                       BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
 362                val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
 363                err = bcm_phy_write_exp(phydev,
 364                                        BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
 365                                        val);
 366                break;
 367        }
 368        if (err)
 369                return err;
 370
 371        bcm54xx_phydsp_config(phydev);
 372
 373        /* For non-SFP setups, encode link speed into LED1 and LED3 pair
 374         * (green/amber).
 375         * Also flash these two LEDs on activity. This means configuring
 376         * them for MULTICOLOR and encoding link/activity into them.
 377         * Don't do this for devices on an SFP module, since some of these
 378         * use the LED outputs to control the SFP LOS signal, and changing
 379         * these settings will cause LOS to malfunction.
 380         */
 381        if (!phy_on_sfp(phydev)) {
 382                val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
 383                        BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
 384                bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
 385
 386                val = BCM_LED_MULTICOLOR_IN_PHASE |
 387                        BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
 388                        BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
 389                bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
 390        }
 391
 392        return 0;
 393}
 394
 395static int bcm54xx_resume(struct phy_device *phydev)
 396{
 397        int ret;
 398
 399        /* Writes to register other than BMCR would be ignored
 400         * unless we clear the PDOWN bit first
 401         */
 402        ret = genphy_resume(phydev);
 403        if (ret < 0)
 404                return ret;
 405
 406        /* Upon exiting power down, the PHY remains in an internal reset state
 407         * for 40us
 408         */
 409        fsleep(40);
 410
 411        return bcm54xx_config_init(phydev);
 412}
 413
 414static int bcm54811_config_init(struct phy_device *phydev)
 415{
 416        int err, reg;
 417
 418        /* Disable BroadR-Reach function. */
 419        reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
 420        reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
 421        err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
 422                                reg);
 423        if (err < 0)
 424                return err;
 425
 426        err = bcm54xx_config_init(phydev);
 427
 428        /* Enable CLK125 MUX on LED4 if ref clock is enabled. */
 429        if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
 430                reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
 431                err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
 432                                        BCM54612E_LED4_CLK125OUT_EN | reg);
 433                if (err < 0)
 434                        return err;
 435        }
 436
 437        return err;
 438}
 439
 440static int bcm5481_config_aneg(struct phy_device *phydev)
 441{
 442        struct device_node *np = phydev->mdio.dev.of_node;
 443        int ret;
 444
 445        /* Aneg firstly. */
 446        ret = genphy_config_aneg(phydev);
 447
 448        /* Then we can set up the delay. */
 449        bcm54xx_config_clock_delay(phydev);
 450
 451        if (of_property_read_bool(np, "enet-phy-lane-swap")) {
 452                /* Lane Swap - Undocumented register...magic! */
 453                ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
 454                                        0x11B);
 455                if (ret < 0)
 456                        return ret;
 457        }
 458
 459        return ret;
 460}
 461
 462struct bcm54616s_phy_priv {
 463        bool mode_1000bx_en;
 464};
 465
 466static int bcm54616s_probe(struct phy_device *phydev)
 467{
 468        struct bcm54616s_phy_priv *priv;
 469        int val;
 470
 471        priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
 472        if (!priv)
 473                return -ENOMEM;
 474
 475        phydev->priv = priv;
 476
 477        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
 478        if (val < 0)
 479                return val;
 480
 481        /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0]
 482         * is 01b, and the link between PHY and its link partner can be
 483         * either 1000Base-X or 100Base-FX.
 484         * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
 485         * support is still missing as of now.
 486         */
 487        if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
 488                val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
 489                if (val < 0)
 490                        return val;
 491
 492                /* Bit 0 of the SerDes 100-FX Control register, when set
 493                 * to 1, sets the MII/RGMII -> 100BASE-FX configuration.
 494                 * When this bit is set to 0, it sets the GMII/RGMII ->
 495                 * 1000BASE-X configuration.
 496                 */
 497                if (!(val & BCM54616S_100FX_MODE))
 498                        priv->mode_1000bx_en = true;
 499
 500                phydev->port = PORT_FIBRE;
 501        }
 502
 503        return 0;
 504}
 505
 506static int bcm54616s_config_aneg(struct phy_device *phydev)
 507{
 508        struct bcm54616s_phy_priv *priv = phydev->priv;
 509        int ret;
 510
 511        /* Aneg firstly. */
 512        if (priv->mode_1000bx_en)
 513                ret = genphy_c37_config_aneg(phydev);
 514        else
 515                ret = genphy_config_aneg(phydev);
 516
 517        /* Then we can set up the delay. */
 518        bcm54xx_config_clock_delay(phydev);
 519
 520        return ret;
 521}
 522
 523static int bcm54616s_read_status(struct phy_device *phydev)
 524{
 525        struct bcm54616s_phy_priv *priv = phydev->priv;
 526        int err;
 527
 528        if (priv->mode_1000bx_en)
 529                err = genphy_c37_read_status(phydev);
 530        else
 531                err = genphy_read_status(phydev);
 532
 533        return err;
 534}
 535
 536static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
 537{
 538        int val;
 539
 540        val = phy_read(phydev, reg);
 541        if (val < 0)
 542                return val;
 543
 544        return phy_write(phydev, reg, val | set);
 545}
 546
 547static int brcm_fet_config_init(struct phy_device *phydev)
 548{
 549        int reg, err, err2, brcmtest;
 550
 551        /* Reset the PHY to bring it to a known state. */
 552        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
 553        if (err < 0)
 554                return err;
 555
 556        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 557        if (reg < 0)
 558                return reg;
 559
 560        /* Unmask events we are interested in and mask interrupts globally. */
 561        reg = MII_BRCM_FET_IR_DUPLEX_EN |
 562              MII_BRCM_FET_IR_SPEED_EN |
 563              MII_BRCM_FET_IR_LINK_EN |
 564              MII_BRCM_FET_IR_ENABLE |
 565              MII_BRCM_FET_IR_MASK;
 566
 567        err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 568        if (err < 0)
 569                return err;
 570
 571        /* Enable shadow register access */
 572        brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
 573        if (brcmtest < 0)
 574                return brcmtest;
 575
 576        reg = brcmtest | MII_BRCM_FET_BT_SRE;
 577
 578        err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
 579        if (err < 0)
 580                return err;
 581
 582        /* Set the LED mode */
 583        reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
 584        if (reg < 0) {
 585                err = reg;
 586                goto done;
 587        }
 588
 589        reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
 590        reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
 591
 592        err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
 593        if (err < 0)
 594                goto done;
 595
 596        /* Enable auto MDIX */
 597        err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
 598                                       MII_BRCM_FET_SHDW_MC_FAME);
 599        if (err < 0)
 600                goto done;
 601
 602        if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
 603                /* Enable auto power down */
 604                err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
 605                                               MII_BRCM_FET_SHDW_AS2_APDE);
 606        }
 607
 608done:
 609        /* Disable shadow register access */
 610        err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
 611        if (!err)
 612                err = err2;
 613
 614        return err;
 615}
 616
 617static int brcm_fet_ack_interrupt(struct phy_device *phydev)
 618{
 619        int reg;
 620
 621        /* Clear pending interrupts.  */
 622        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 623        if (reg < 0)
 624                return reg;
 625
 626        return 0;
 627}
 628
 629static int brcm_fet_config_intr(struct phy_device *phydev)
 630{
 631        int reg, err;
 632
 633        reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 634        if (reg < 0)
 635                return reg;
 636
 637        if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 638                err = brcm_fet_ack_interrupt(phydev);
 639                if (err)
 640                        return err;
 641
 642                reg &= ~MII_BRCM_FET_IR_MASK;
 643                err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 644        } else {
 645                reg |= MII_BRCM_FET_IR_MASK;
 646                err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 647                if (err)
 648                        return err;
 649
 650                err = brcm_fet_ack_interrupt(phydev);
 651        }
 652
 653        return err;
 654}
 655
 656static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
 657{
 658        int irq_status;
 659
 660        irq_status = phy_read(phydev, MII_BRCM_FET_INTREG);
 661        if (irq_status < 0) {
 662                phy_error(phydev);
 663                return IRQ_NONE;
 664        }
 665
 666        if (irq_status == 0)
 667                return IRQ_NONE;
 668
 669        phy_trigger_machine(phydev);
 670
 671        return IRQ_HANDLED;
 672}
 673
 674struct bcm54xx_phy_priv {
 675        u64     *stats;
 676};
 677
 678static int bcm54xx_phy_probe(struct phy_device *phydev)
 679{
 680        struct bcm54xx_phy_priv *priv;
 681
 682        priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
 683        if (!priv)
 684                return -ENOMEM;
 685
 686        phydev->priv = priv;
 687
 688        priv->stats = devm_kcalloc(&phydev->mdio.dev,
 689                                   bcm_phy_get_sset_count(phydev), sizeof(u64),
 690                                   GFP_KERNEL);
 691        if (!priv->stats)
 692                return -ENOMEM;
 693
 694        return 0;
 695}
 696
 697static void bcm54xx_get_stats(struct phy_device *phydev,
 698                              struct ethtool_stats *stats, u64 *data)
 699{
 700        struct bcm54xx_phy_priv *priv = phydev->priv;
 701
 702        bcm_phy_get_stats(phydev, priv->stats, stats, data);
 703}
 704
 705static struct phy_driver broadcom_drivers[] = {
 706{
 707        .phy_id         = PHY_ID_BCM5411,
 708        .phy_id_mask    = 0xfffffff0,
 709        .name           = "Broadcom BCM5411",
 710        /* PHY_GBIT_FEATURES */
 711        .get_sset_count = bcm_phy_get_sset_count,
 712        .get_strings    = bcm_phy_get_strings,
 713        .get_stats      = bcm54xx_get_stats,
 714        .probe          = bcm54xx_phy_probe,
 715        .config_init    = bcm54xx_config_init,
 716        .config_intr    = bcm_phy_config_intr,
 717        .handle_interrupt = bcm_phy_handle_interrupt,
 718}, {
 719        .phy_id         = PHY_ID_BCM5421,
 720        .phy_id_mask    = 0xfffffff0,
 721        .name           = "Broadcom BCM5421",
 722        /* PHY_GBIT_FEATURES */
 723        .get_sset_count = bcm_phy_get_sset_count,
 724        .get_strings    = bcm_phy_get_strings,
 725        .get_stats      = bcm54xx_get_stats,
 726        .probe          = bcm54xx_phy_probe,
 727        .config_init    = bcm54xx_config_init,
 728        .config_intr    = bcm_phy_config_intr,
 729        .handle_interrupt = bcm_phy_handle_interrupt,
 730}, {
 731        .phy_id         = PHY_ID_BCM54210E,
 732        .phy_id_mask    = 0xfffffff0,
 733        .name           = "Broadcom BCM54210E",
 734        /* PHY_GBIT_FEATURES */
 735        .get_sset_count = bcm_phy_get_sset_count,
 736        .get_strings    = bcm_phy_get_strings,
 737        .get_stats      = bcm54xx_get_stats,
 738        .probe          = bcm54xx_phy_probe,
 739        .config_init    = bcm54xx_config_init,
 740        .config_intr    = bcm_phy_config_intr,
 741        .handle_interrupt = bcm_phy_handle_interrupt,
 742}, {
 743        .phy_id         = PHY_ID_BCM5461,
 744        .phy_id_mask    = 0xfffffff0,
 745        .name           = "Broadcom BCM5461",
 746        /* PHY_GBIT_FEATURES */
 747        .get_sset_count = bcm_phy_get_sset_count,
 748        .get_strings    = bcm_phy_get_strings,
 749        .get_stats      = bcm54xx_get_stats,
 750        .probe          = bcm54xx_phy_probe,
 751        .config_init    = bcm54xx_config_init,
 752        .config_intr    = bcm_phy_config_intr,
 753        .handle_interrupt = bcm_phy_handle_interrupt,
 754}, {
 755        .phy_id         = PHY_ID_BCM54612E,
 756        .phy_id_mask    = 0xfffffff0,
 757        .name           = "Broadcom BCM54612E",
 758        /* PHY_GBIT_FEATURES */
 759        .get_sset_count = bcm_phy_get_sset_count,
 760        .get_strings    = bcm_phy_get_strings,
 761        .get_stats      = bcm54xx_get_stats,
 762        .probe          = bcm54xx_phy_probe,
 763        .config_init    = bcm54xx_config_init,
 764        .config_intr    = bcm_phy_config_intr,
 765        .handle_interrupt = bcm_phy_handle_interrupt,
 766}, {
 767        .phy_id         = PHY_ID_BCM54616S,
 768        .phy_id_mask    = 0xfffffff0,
 769        .name           = "Broadcom BCM54616S",
 770        /* PHY_GBIT_FEATURES */
 771        .config_init    = bcm54xx_config_init,
 772        .config_aneg    = bcm54616s_config_aneg,
 773        .config_intr    = bcm_phy_config_intr,
 774        .handle_interrupt = bcm_phy_handle_interrupt,
 775        .read_status    = bcm54616s_read_status,
 776        .probe          = bcm54616s_probe,
 777}, {
 778        .phy_id         = PHY_ID_BCM5464,
 779        .phy_id_mask    = 0xfffffff0,
 780        .name           = "Broadcom BCM5464",
 781        /* PHY_GBIT_FEATURES */
 782        .get_sset_count = bcm_phy_get_sset_count,
 783        .get_strings    = bcm_phy_get_strings,
 784        .get_stats      = bcm54xx_get_stats,
 785        .probe          = bcm54xx_phy_probe,
 786        .config_init    = bcm54xx_config_init,
 787        .config_intr    = bcm_phy_config_intr,
 788        .handle_interrupt = bcm_phy_handle_interrupt,
 789        .suspend        = genphy_suspend,
 790        .resume         = genphy_resume,
 791}, {
 792        .phy_id         = PHY_ID_BCM5481,
 793        .phy_id_mask    = 0xfffffff0,
 794        .name           = "Broadcom BCM5481",
 795        /* PHY_GBIT_FEATURES */
 796        .get_sset_count = bcm_phy_get_sset_count,
 797        .get_strings    = bcm_phy_get_strings,
 798        .get_stats      = bcm54xx_get_stats,
 799        .probe          = bcm54xx_phy_probe,
 800        .config_init    = bcm54xx_config_init,
 801        .config_aneg    = bcm5481_config_aneg,
 802        .config_intr    = bcm_phy_config_intr,
 803        .handle_interrupt = bcm_phy_handle_interrupt,
 804}, {
 805        .phy_id         = PHY_ID_BCM54810,
 806        .phy_id_mask    = 0xfffffff0,
 807        .name           = "Broadcom BCM54810",
 808        /* PHY_GBIT_FEATURES */
 809        .get_sset_count = bcm_phy_get_sset_count,
 810        .get_strings    = bcm_phy_get_strings,
 811        .get_stats      = bcm54xx_get_stats,
 812        .probe          = bcm54xx_phy_probe,
 813        .config_init    = bcm54xx_config_init,
 814        .config_aneg    = bcm5481_config_aneg,
 815        .config_intr    = bcm_phy_config_intr,
 816        .handle_interrupt = bcm_phy_handle_interrupt,
 817        .suspend        = genphy_suspend,
 818        .resume         = bcm54xx_resume,
 819}, {
 820        .phy_id         = PHY_ID_BCM54811,
 821        .phy_id_mask    = 0xfffffff0,
 822        .name           = "Broadcom BCM54811",
 823        /* PHY_GBIT_FEATURES */
 824        .get_sset_count = bcm_phy_get_sset_count,
 825        .get_strings    = bcm_phy_get_strings,
 826        .get_stats      = bcm54xx_get_stats,
 827        .probe          = bcm54xx_phy_probe,
 828        .config_init    = bcm54811_config_init,
 829        .config_aneg    = bcm5481_config_aneg,
 830        .config_intr    = bcm_phy_config_intr,
 831        .handle_interrupt = bcm_phy_handle_interrupt,
 832        .suspend        = genphy_suspend,
 833        .resume         = bcm54xx_resume,
 834}, {
 835        .phy_id         = PHY_ID_BCM5482,
 836        .phy_id_mask    = 0xfffffff0,
 837        .name           = "Broadcom BCM5482",
 838        /* PHY_GBIT_FEATURES */
 839        .get_sset_count = bcm_phy_get_sset_count,
 840        .get_strings    = bcm_phy_get_strings,
 841        .get_stats      = bcm54xx_get_stats,
 842        .probe          = bcm54xx_phy_probe,
 843        .config_init    = bcm54xx_config_init,
 844        .config_intr    = bcm_phy_config_intr,
 845        .handle_interrupt = bcm_phy_handle_interrupt,
 846}, {
 847        .phy_id         = PHY_ID_BCM50610,
 848        .phy_id_mask    = 0xfffffff0,
 849        .name           = "Broadcom BCM50610",
 850        /* PHY_GBIT_FEATURES */
 851        .get_sset_count = bcm_phy_get_sset_count,
 852        .get_strings    = bcm_phy_get_strings,
 853        .get_stats      = bcm54xx_get_stats,
 854        .probe          = bcm54xx_phy_probe,
 855        .config_init    = bcm54xx_config_init,
 856        .config_intr    = bcm_phy_config_intr,
 857        .handle_interrupt = bcm_phy_handle_interrupt,
 858}, {
 859        .phy_id         = PHY_ID_BCM50610M,
 860        .phy_id_mask    = 0xfffffff0,
 861        .name           = "Broadcom BCM50610M",
 862        /* PHY_GBIT_FEATURES */
 863        .get_sset_count = bcm_phy_get_sset_count,
 864        .get_strings    = bcm_phy_get_strings,
 865        .get_stats      = bcm54xx_get_stats,
 866        .probe          = bcm54xx_phy_probe,
 867        .config_init    = bcm54xx_config_init,
 868        .config_intr    = bcm_phy_config_intr,
 869        .handle_interrupt = bcm_phy_handle_interrupt,
 870}, {
 871        .phy_id         = PHY_ID_BCM57780,
 872        .phy_id_mask    = 0xfffffff0,
 873        .name           = "Broadcom BCM57780",
 874        /* PHY_GBIT_FEATURES */
 875        .get_sset_count = bcm_phy_get_sset_count,
 876        .get_strings    = bcm_phy_get_strings,
 877        .get_stats      = bcm54xx_get_stats,
 878        .probe          = bcm54xx_phy_probe,
 879        .config_init    = bcm54xx_config_init,
 880        .config_intr    = bcm_phy_config_intr,
 881        .handle_interrupt = bcm_phy_handle_interrupt,
 882}, {
 883        .phy_id         = PHY_ID_BCMAC131,
 884        .phy_id_mask    = 0xfffffff0,
 885        .name           = "Broadcom BCMAC131",
 886        /* PHY_BASIC_FEATURES */
 887        .config_init    = brcm_fet_config_init,
 888        .config_intr    = brcm_fet_config_intr,
 889        .handle_interrupt = brcm_fet_handle_interrupt,
 890}, {
 891        .phy_id         = PHY_ID_BCM5241,
 892        .phy_id_mask    = 0xfffffff0,
 893        .name           = "Broadcom BCM5241",
 894        /* PHY_BASIC_FEATURES */
 895        .config_init    = brcm_fet_config_init,
 896        .config_intr    = brcm_fet_config_intr,
 897        .handle_interrupt = brcm_fet_handle_interrupt,
 898}, {
 899        .phy_id         = PHY_ID_BCM5395,
 900        .phy_id_mask    = 0xfffffff0,
 901        .name           = "Broadcom BCM5395",
 902        .flags          = PHY_IS_INTERNAL,
 903        /* PHY_GBIT_FEATURES */
 904        .get_sset_count = bcm_phy_get_sset_count,
 905        .get_strings    = bcm_phy_get_strings,
 906        .get_stats      = bcm54xx_get_stats,
 907        .probe          = bcm54xx_phy_probe,
 908}, {
 909        .phy_id         = PHY_ID_BCM53125,
 910        .phy_id_mask    = 0xfffffff0,
 911        .name           = "Broadcom BCM53125",
 912        .flags          = PHY_IS_INTERNAL,
 913        /* PHY_GBIT_FEATURES */
 914        .get_sset_count = bcm_phy_get_sset_count,
 915        .get_strings    = bcm_phy_get_strings,
 916        .get_stats      = bcm54xx_get_stats,
 917        .probe          = bcm54xx_phy_probe,
 918        .config_init    = bcm54xx_config_init,
 919        .config_intr    = bcm_phy_config_intr,
 920        .handle_interrupt = bcm_phy_handle_interrupt,
 921}, {
 922        .phy_id         = PHY_ID_BCM89610,
 923        .phy_id_mask    = 0xfffffff0,
 924        .name           = "Broadcom BCM89610",
 925        /* PHY_GBIT_FEATURES */
 926        .get_sset_count = bcm_phy_get_sset_count,
 927        .get_strings    = bcm_phy_get_strings,
 928        .get_stats      = bcm54xx_get_stats,
 929        .probe          = bcm54xx_phy_probe,
 930        .config_init    = bcm54xx_config_init,
 931        .config_intr    = bcm_phy_config_intr,
 932        .handle_interrupt = bcm_phy_handle_interrupt,
 933} };
 934
 935module_phy_driver(broadcom_drivers);
 936
 937static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
 938        { PHY_ID_BCM5411, 0xfffffff0 },
 939        { PHY_ID_BCM5421, 0xfffffff0 },
 940        { PHY_ID_BCM54210E, 0xfffffff0 },
 941        { PHY_ID_BCM5461, 0xfffffff0 },
 942        { PHY_ID_BCM54612E, 0xfffffff0 },
 943        { PHY_ID_BCM54616S, 0xfffffff0 },
 944        { PHY_ID_BCM5464, 0xfffffff0 },
 945        { PHY_ID_BCM5481, 0xfffffff0 },
 946        { PHY_ID_BCM54810, 0xfffffff0 },
 947        { PHY_ID_BCM54811, 0xfffffff0 },
 948        { PHY_ID_BCM5482, 0xfffffff0 },
 949        { PHY_ID_BCM50610, 0xfffffff0 },
 950        { PHY_ID_BCM50610M, 0xfffffff0 },
 951        { PHY_ID_BCM57780, 0xfffffff0 },
 952        { PHY_ID_BCMAC131, 0xfffffff0 },
 953        { PHY_ID_BCM5241, 0xfffffff0 },
 954        { PHY_ID_BCM5395, 0xfffffff0 },
 955        { PHY_ID_BCM53125, 0xfffffff0 },
 956        { PHY_ID_BCM89610, 0xfffffff0 },
 957        { }
 958};
 959
 960MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
 961