root/drivers/net/phy/broadcom.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm54210e_config_init
  2. bcm54612e_config_init
  3. bcm54xx_config_clock_delay
  4. bcm50610_a0_workaround
  5. bcm54xx_phydsp_config
  6. bcm54xx_adjust_rxrefclk
  7. bcm54xx_config_init
  8. bcm5482_config_init
  9. bcm5482_read_status
  10. bcm5481_config_aneg
  11. bcm54616s_config_aneg
  12. brcm_phy_setbits
  13. brcm_fet_config_init
  14. brcm_fet_ack_interrupt
  15. brcm_fet_config_intr
  16. bcm53xx_phy_probe
  17. bcm53xx_phy_get_stats

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

/* [<][>][^][v][top][bottom][index][help] */