linux/drivers/net/phy/bcm7xxx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Broadcom BCM7xxx internal transceivers support.
   4 *
   5 * Copyright (C) 2014-2017 Broadcom
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/phy.h>
  10#include <linux/delay.h>
  11#include "bcm-phy-lib.h"
  12#include <linux/bitops.h>
  13#include <linux/brcmphy.h>
  14#include <linux/mdio.h>
  15
  16/* Broadcom BCM7xxx internal PHY registers */
  17
  18/* EPHY only register definitions */
  19#define MII_BCM7XXX_100TX_AUX_CTL       0x10
  20#define MII_BCM7XXX_100TX_FALSE_CAR     0x13
  21#define MII_BCM7XXX_100TX_DISC          0x14
  22#define MII_BCM7XXX_AUX_MODE            0x1d
  23#define  MII_BCM7XXX_64CLK_MDIO         BIT(12)
  24#define MII_BCM7XXX_TEST                0x1f
  25#define  MII_BCM7XXX_SHD_MODE_2         BIT(2)
  26#define MII_BCM7XXX_SHD_2_ADDR_CTRL     0xe
  27#define MII_BCM7XXX_SHD_2_CTRL_STAT     0xf
  28#define MII_BCM7XXX_SHD_2_BIAS_TRIM     0x1a
  29#define MII_BCM7XXX_SHD_3_AN_EEE_ADV    0x3
  30#define MII_BCM7XXX_SHD_3_PCS_CTRL_2    0x6
  31#define  MII_BCM7XXX_PCS_CTRL_2_DEF     0x4400
  32#define MII_BCM7XXX_SHD_3_AN_STAT       0xb
  33#define  MII_BCM7XXX_AN_NULL_MSG_EN     BIT(0)
  34#define  MII_BCM7XXX_AN_EEE_EN          BIT(1)
  35#define MII_BCM7XXX_SHD_3_EEE_THRESH    0xe
  36#define  MII_BCM7XXX_EEE_THRESH_DEF     0x50
  37#define MII_BCM7XXX_SHD_3_TL4           0x23
  38#define  MII_BCM7XXX_TL4_RST_MSK        (BIT(2) | BIT(1))
  39
  40struct bcm7xxx_phy_priv {
  41        u64     *stats;
  42};
  43
  44static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
  45{
  46        /* AFE_RXCONFIG_0 */
  47        bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
  48
  49        /* AFE_RXCONFIG_1 */
  50        bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
  51
  52        /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
  53        bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
  54
  55        /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
  56        bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
  57
  58        /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
  59        bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
  60
  61        /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
  62        bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
  63
  64        /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
  65        bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
  66
  67        /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
  68         * offset for HT=0 code
  69         */
  70        bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
  71
  72        /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
  73        phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
  74
  75        /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
  76        bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
  77
  78        /* Reset R_CAL/RC_CAL engine */
  79        bcm_phy_r_rc_cal_reset(phydev);
  80
  81        return 0;
  82}
  83
  84static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
  85{
  86        /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
  87        bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
  88
  89        /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
  90        bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
  91
  92        /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
  93        bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
  94
  95        /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
  96         * offset for HT=0 code
  97         */
  98        bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
  99
 100        /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
 101        phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
 102
 103        /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
 104        bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
 105
 106        /* Reset R_CAL/RC_CAL engine */
 107        bcm_phy_r_rc_cal_reset(phydev);
 108
 109        return 0;
 110}
 111
 112static int bcm7xxx_28nm_a0_patch_afe_config_init(struct phy_device *phydev)
 113{
 114        /* +1 RC_CAL codes for RL centering for both LT and HT conditions */
 115        bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0xd003);
 116
 117        /* Cut master bias current by 2% to compensate for RC_CAL offset */
 118        bcm_phy_write_misc(phydev, DSP_TAP10, 0x791b);
 119
 120        /* Improve hybrid leakage */
 121        bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x10e3);
 122
 123        /* Change rx_on_tune 8 to 0xf */
 124        bcm_phy_write_misc(phydev, 0x21, 0x2, 0x87f6);
 125
 126        /* Change 100Tx EEE bandwidth */
 127        bcm_phy_write_misc(phydev, 0x22, 0x2, 0x017d);
 128
 129        /* Enable ffe zero detection for Vitesse interoperability */
 130        bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015);
 131
 132        bcm_phy_r_rc_cal_reset(phydev);
 133
 134        return 0;
 135}
 136
 137static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
 138{
 139        u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
 140        u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
 141        u8 count;
 142        int ret = 0;
 143
 144        /* Newer devices have moved the revision information back into a
 145         * standard location in MII_PHYS_ID[23]
 146         */
 147        if (rev == 0)
 148                rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
 149
 150        pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
 151                     phydev_name(phydev), phydev->drv->name, rev, patch);
 152
 153        /* Dummy read to a register to workaround an issue upon reset where the
 154         * internal inverter may not allow the first MDIO transaction to pass
 155         * the MDIO management controller and make us return 0xffff for such
 156         * reads.
 157         */
 158        phy_read(phydev, MII_BMSR);
 159
 160        switch (rev) {
 161        case 0xa0:
 162        case 0xb0:
 163                ret = bcm_phy_28nm_a0b0_afe_config_init(phydev);
 164                break;
 165        case 0xd0:
 166                ret = bcm7xxx_28nm_d0_afe_config_init(phydev);
 167                break;
 168        case 0xe0:
 169        case 0xf0:
 170        /* Rev G0 introduces a roll over */
 171        case 0x10:
 172                ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
 173                break;
 174        case 0x01:
 175                ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev);
 176                break;
 177        default:
 178                break;
 179        }
 180
 181        if (ret)
 182                return ret;
 183
 184        ret = bcm_phy_downshift_get(phydev, &count);
 185        if (ret)
 186                return ret;
 187
 188        /* Only enable EEE if Wirespeed/downshift is disabled */
 189        ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
 190        if (ret)
 191                return ret;
 192
 193        return bcm_phy_enable_apd(phydev, true);
 194}
 195
 196static int bcm7xxx_28nm_resume(struct phy_device *phydev)
 197{
 198        int ret;
 199
 200        /* Re-apply workarounds coming out suspend/resume */
 201        ret = bcm7xxx_28nm_config_init(phydev);
 202        if (ret)
 203                return ret;
 204
 205        /* 28nm Gigabit PHYs come out of reset without any half-duplex
 206         * or "hub" compliant advertised mode, fix that. This does not
 207         * cause any problems with the PHY library since genphy_config_aneg()
 208         * gracefully handles auto-negotiated and forced modes.
 209         */
 210        return genphy_config_aneg(phydev);
 211}
 212
 213static int phy_set_clr_bits(struct phy_device *dev, int location,
 214                                        int set_mask, int clr_mask)
 215{
 216        int v, ret;
 217
 218        v = phy_read(dev, location);
 219        if (v < 0)
 220                return v;
 221
 222        v &= ~clr_mask;
 223        v |= set_mask;
 224
 225        ret = phy_write(dev, location, v);
 226        if (ret < 0)
 227                return ret;
 228
 229        return v;
 230}
 231
 232static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
 233{
 234        int ret;
 235
 236        /* set shadow mode 2 */
 237        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
 238                               MII_BCM7XXX_SHD_MODE_2, 0);
 239        if (ret < 0)
 240                return ret;
 241
 242        /* Set current trim values INT_trim = -1, Ext_trim =0 */
 243        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0);
 244        if (ret < 0)
 245                goto reset_shadow_mode;
 246
 247        /* Cal reset */
 248        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
 249                        MII_BCM7XXX_SHD_3_TL4);
 250        if (ret < 0)
 251                goto reset_shadow_mode;
 252        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
 253                               MII_BCM7XXX_TL4_RST_MSK, 0);
 254        if (ret < 0)
 255                goto reset_shadow_mode;
 256
 257        /* Cal reset disable */
 258        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
 259                        MII_BCM7XXX_SHD_3_TL4);
 260        if (ret < 0)
 261                goto reset_shadow_mode;
 262        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
 263                               0, MII_BCM7XXX_TL4_RST_MSK);
 264        if (ret < 0)
 265                goto reset_shadow_mode;
 266
 267reset_shadow_mode:
 268        /* reset shadow mode 2 */
 269        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
 270                               MII_BCM7XXX_SHD_MODE_2);
 271        if (ret < 0)
 272                return ret;
 273
 274        return 0;
 275}
 276
 277/* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */
 278static int bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev)
 279{
 280        int ret;
 281
 282        /* set shadow mode 1 */
 283        ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST,
 284                               MII_BRCM_FET_BT_SRE, 0);
 285        if (ret < 0)
 286                return ret;
 287
 288        /* Enable auto-power down */
 289        ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
 290                               MII_BRCM_FET_SHDW_AS2_APDE, 0);
 291        if (ret < 0)
 292                return ret;
 293
 294        /* reset shadow mode 1 */
 295        ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
 296                               MII_BRCM_FET_BT_SRE);
 297        if (ret < 0)
 298                return ret;
 299
 300        return 0;
 301}
 302
 303static int bcm7xxx_28nm_ephy_eee_enable(struct phy_device *phydev)
 304{
 305        int ret;
 306
 307        /* set shadow mode 2 */
 308        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
 309                               MII_BCM7XXX_SHD_MODE_2, 0);
 310        if (ret < 0)
 311                return ret;
 312
 313        /* Advertise supported modes */
 314        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
 315                        MII_BCM7XXX_SHD_3_AN_EEE_ADV);
 316        if (ret < 0)
 317                goto reset_shadow_mode;
 318        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
 319                        MDIO_EEE_100TX);
 320        if (ret < 0)
 321                goto reset_shadow_mode;
 322
 323        /* Restore Defaults */
 324        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
 325                        MII_BCM7XXX_SHD_3_PCS_CTRL_2);
 326        if (ret < 0)
 327                goto reset_shadow_mode;
 328        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
 329                        MII_BCM7XXX_PCS_CTRL_2_DEF);
 330        if (ret < 0)
 331                goto reset_shadow_mode;
 332
 333        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
 334                        MII_BCM7XXX_SHD_3_EEE_THRESH);
 335        if (ret < 0)
 336                goto reset_shadow_mode;
 337        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
 338                        MII_BCM7XXX_EEE_THRESH_DEF);
 339        if (ret < 0)
 340                goto reset_shadow_mode;
 341
 342        /* Enable EEE autonegotiation */
 343        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
 344                        MII_BCM7XXX_SHD_3_AN_STAT);
 345        if (ret < 0)
 346                goto reset_shadow_mode;
 347        ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
 348                        (MII_BCM7XXX_AN_NULL_MSG_EN | MII_BCM7XXX_AN_EEE_EN));
 349        if (ret < 0)
 350                goto reset_shadow_mode;
 351
 352reset_shadow_mode:
 353        /* reset shadow mode 2 */
 354        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
 355                               MII_BCM7XXX_SHD_MODE_2);
 356        if (ret < 0)
 357                return ret;
 358
 359        /* Restart autoneg */
 360        phy_write(phydev, MII_BMCR,
 361                  (BMCR_SPEED100 | BMCR_ANENABLE | BMCR_ANRESTART));
 362
 363        return 0;
 364}
 365
 366static int bcm7xxx_28nm_ephy_config_init(struct phy_device *phydev)
 367{
 368        u8 rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
 369        int ret = 0;
 370
 371        pr_info_once("%s: %s PHY revision: 0x%02x\n",
 372                     phydev_name(phydev), phydev->drv->name, rev);
 373
 374        /* Dummy read to a register to workaround a possible issue upon reset
 375         * where the internal inverter may not allow the first MDIO transaction
 376         * to pass the MDIO management controller and make us return 0xffff for
 377         * such reads.
 378         */
 379        phy_read(phydev, MII_BMSR);
 380
 381        /* Apply AFE software work-around if necessary */
 382        if (rev == 0x01) {
 383                ret = bcm7xxx_28nm_ephy_01_afe_config_init(phydev);
 384                if (ret)
 385                        return ret;
 386        }
 387
 388        ret = bcm7xxx_28nm_ephy_eee_enable(phydev);
 389        if (ret)
 390                return ret;
 391
 392        return bcm7xxx_28nm_ephy_apd_enable(phydev);
 393}
 394
 395static int bcm7xxx_28nm_ephy_resume(struct phy_device *phydev)
 396{
 397        int ret;
 398
 399        /* Re-apply workarounds coming out suspend/resume */
 400        ret = bcm7xxx_28nm_ephy_config_init(phydev);
 401        if (ret)
 402                return ret;
 403
 404        return genphy_config_aneg(phydev);
 405}
 406
 407static int bcm7xxx_config_init(struct phy_device *phydev)
 408{
 409        int ret;
 410
 411        /* Enable 64 clock MDIO */
 412        phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
 413        phy_read(phydev, MII_BCM7XXX_AUX_MODE);
 414
 415        /* set shadow mode 2 */
 416        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
 417                        MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
 418        if (ret < 0)
 419                return ret;
 420
 421        /* set iddq_clkbias */
 422        phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
 423        udelay(10);
 424
 425        /* reset iddq_clkbias */
 426        phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
 427
 428        phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
 429
 430        /* reset shadow mode 2 */
 431        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
 432        if (ret < 0)
 433                return ret;
 434
 435        return 0;
 436}
 437
 438/* Workaround for putting the PHY in IDDQ mode, required
 439 * for all BCM7XXX 40nm and 65nm PHYs
 440 */
 441static int bcm7xxx_suspend(struct phy_device *phydev)
 442{
 443        int ret;
 444        static const struct bcm7xxx_regs {
 445                int reg;
 446                u16 value;
 447        } bcm7xxx_suspend_cfg[] = {
 448                { MII_BCM7XXX_TEST, 0x008b },
 449                { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
 450                { MII_BCM7XXX_100TX_DISC, 0x7000 },
 451                { MII_BCM7XXX_TEST, 0x000f },
 452                { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
 453                { MII_BCM7XXX_TEST, 0x000b },
 454        };
 455        unsigned int i;
 456
 457        for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
 458                ret = phy_write(phydev,
 459                                bcm7xxx_suspend_cfg[i].reg,
 460                                bcm7xxx_suspend_cfg[i].value);
 461                if (ret)
 462                        return ret;
 463        }
 464
 465        return 0;
 466}
 467
 468static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev,
 469                                    struct ethtool_tunable *tuna,
 470                                    void *data)
 471{
 472        switch (tuna->id) {
 473        case ETHTOOL_PHY_DOWNSHIFT:
 474                return bcm_phy_downshift_get(phydev, (u8 *)data);
 475        default:
 476                return -EOPNOTSUPP;
 477        }
 478}
 479
 480static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
 481                                    struct ethtool_tunable *tuna,
 482                                    const void *data)
 483{
 484        u8 count = *(u8 *)data;
 485        int ret;
 486
 487        switch (tuna->id) {
 488        case ETHTOOL_PHY_DOWNSHIFT:
 489                ret = bcm_phy_downshift_set(phydev, count);
 490                break;
 491        default:
 492                return -EOPNOTSUPP;
 493        }
 494
 495        if (ret)
 496                return ret;
 497
 498        /* Disable EEE advertisement since this prevents the PHY
 499         * from successfully linking up, trigger auto-negotiation restart
 500         * to let the MAC decide what to do.
 501         */
 502        ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
 503        if (ret)
 504                return ret;
 505
 506        return genphy_restart_aneg(phydev);
 507}
 508
 509static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
 510                                       struct ethtool_stats *stats, u64 *data)
 511{
 512        struct bcm7xxx_phy_priv *priv = phydev->priv;
 513
 514        bcm_phy_get_stats(phydev, priv->stats, stats, data);
 515}
 516
 517static int bcm7xxx_28nm_probe(struct phy_device *phydev)
 518{
 519        struct bcm7xxx_phy_priv *priv;
 520
 521        priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
 522        if (!priv)
 523                return -ENOMEM;
 524
 525        phydev->priv = priv;
 526
 527        priv->stats = devm_kcalloc(&phydev->mdio.dev,
 528                                   bcm_phy_get_sset_count(phydev), sizeof(u64),
 529                                   GFP_KERNEL);
 530        if (!priv->stats)
 531                return -ENOMEM;
 532
 533        return 0;
 534}
 535
 536#define BCM7XXX_28NM_GPHY(_oui, _name)                                  \
 537{                                                                       \
 538        .phy_id         = (_oui),                                       \
 539        .phy_id_mask    = 0xfffffff0,                                   \
 540        .name           = _name,                                        \
 541        /* PHY_GBIT_FEATURES */                                         \
 542        .flags          = PHY_IS_INTERNAL,                              \
 543        .config_init    = bcm7xxx_28nm_config_init,                     \
 544        .resume         = bcm7xxx_28nm_resume,                          \
 545        .get_tunable    = bcm7xxx_28nm_get_tunable,                     \
 546        .set_tunable    = bcm7xxx_28nm_set_tunable,                     \
 547        .get_sset_count = bcm_phy_get_sset_count,                       \
 548        .get_strings    = bcm_phy_get_strings,                          \
 549        .get_stats      = bcm7xxx_28nm_get_phy_stats,                   \
 550        .probe          = bcm7xxx_28nm_probe,                           \
 551}
 552
 553#define BCM7XXX_28NM_EPHY(_oui, _name)                                  \
 554{                                                                       \
 555        .phy_id         = (_oui),                                       \
 556        .phy_id_mask    = 0xfffffff0,                                   \
 557        .name           = _name,                                        \
 558        /* PHY_BASIC_FEATURES */                                        \
 559        .flags          = PHY_IS_INTERNAL,                              \
 560        .config_init    = bcm7xxx_28nm_ephy_config_init,                \
 561        .resume         = bcm7xxx_28nm_ephy_resume,                     \
 562        .get_sset_count = bcm_phy_get_sset_count,                       \
 563        .get_strings    = bcm_phy_get_strings,                          \
 564        .get_stats      = bcm7xxx_28nm_get_phy_stats,                   \
 565        .probe          = bcm7xxx_28nm_probe,                           \
 566}
 567
 568#define BCM7XXX_40NM_EPHY(_oui, _name)                                  \
 569{                                                                       \
 570        .phy_id         = (_oui),                                       \
 571        .phy_id_mask    = 0xfffffff0,                                   \
 572        .name           = _name,                                        \
 573        /* PHY_BASIC_FEATURES */                                        \
 574        .flags          = PHY_IS_INTERNAL,                              \
 575        .soft_reset     = genphy_soft_reset,                            \
 576        .config_init    = bcm7xxx_config_init,                          \
 577        .suspend        = bcm7xxx_suspend,                              \
 578        .resume         = bcm7xxx_config_init,                          \
 579}
 580
 581static struct phy_driver bcm7xxx_driver[] = {
 582        BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
 583        BCM7XXX_28NM_EPHY(PHY_ID_BCM7255, "Broadcom BCM7255"),
 584        BCM7XXX_28NM_EPHY(PHY_ID_BCM7260, "Broadcom BCM7260"),
 585        BCM7XXX_28NM_EPHY(PHY_ID_BCM7268, "Broadcom BCM7268"),
 586        BCM7XXX_28NM_EPHY(PHY_ID_BCM7271, "Broadcom BCM7271"),
 587        BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"),
 588        BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
 589        BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
 590        BCM7XXX_28NM_GPHY(PHY_ID_BCM74371, "Broadcom BCM74371"),
 591        BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
 592        BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
 593        BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
 594        BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"),
 595        BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"),
 596        BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
 597        BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
 598        BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
 599};
 600
 601static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
 602        { PHY_ID_BCM7250, 0xfffffff0, },
 603        { PHY_ID_BCM7255, 0xfffffff0, },
 604        { PHY_ID_BCM7260, 0xfffffff0, },
 605        { PHY_ID_BCM7268, 0xfffffff0, },
 606        { PHY_ID_BCM7271, 0xfffffff0, },
 607        { PHY_ID_BCM7278, 0xfffffff0, },
 608        { PHY_ID_BCM7364, 0xfffffff0, },
 609        { PHY_ID_BCM7366, 0xfffffff0, },
 610        { PHY_ID_BCM7346, 0xfffffff0, },
 611        { PHY_ID_BCM7362, 0xfffffff0, },
 612        { PHY_ID_BCM7425, 0xfffffff0, },
 613        { PHY_ID_BCM7429, 0xfffffff0, },
 614        { PHY_ID_BCM74371, 0xfffffff0, },
 615        { PHY_ID_BCM7439, 0xfffffff0, },
 616        { PHY_ID_BCM7435, 0xfffffff0, },
 617        { PHY_ID_BCM7445, 0xfffffff0, },
 618        { }
 619};
 620
 621module_phy_driver(bcm7xxx_driver);
 622
 623MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
 624
 625MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
 626MODULE_LICENSE("GPL");
 627MODULE_AUTHOR("Broadcom Corporation");
 628