0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include "bcm-phy-lib.h"
0014 #include <linux/delay.h>
0015 #include <linux/module.h>
0016 #include <linux/phy.h>
0017 #include <linux/brcmphy.h>
0018 #include <linux/of.h>
0019
0020 #define BRCM_PHY_MODEL(phydev) \
0021 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
0022
0023 #define BRCM_PHY_REV(phydev) \
0024 ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
0025
0026 MODULE_DESCRIPTION("Broadcom PHY driver");
0027 MODULE_AUTHOR("Maciej W. Rozycki");
0028 MODULE_LICENSE("GPL");
0029
0030 struct bcm54xx_phy_priv {
0031 u64 *stats;
0032 struct bcm_ptp_private *ptp;
0033 };
0034
0035 static int bcm54xx_config_clock_delay(struct phy_device *phydev)
0036 {
0037 int rc, val;
0038
0039
0040 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
0041 val |= MII_BCM54XX_AUXCTL_MISC_WREN;
0042 if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
0043 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
0044
0045 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
0046 }
0047 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
0048 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
0049
0050 val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
0051 }
0052 rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
0053 val);
0054 if (rc < 0)
0055 return rc;
0056
0057
0058 val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
0059 if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
0060 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
0061
0062 val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
0063 }
0064 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
0065 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
0066
0067 val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
0068 }
0069 rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
0070 if (rc < 0)
0071 return rc;
0072
0073 return 0;
0074 }
0075
0076 static int bcm54210e_config_init(struct phy_device *phydev)
0077 {
0078 int val;
0079
0080 bcm54xx_config_clock_delay(phydev);
0081
0082 if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
0083 val = phy_read(phydev, MII_CTRL1000);
0084 val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
0085 phy_write(phydev, MII_CTRL1000, val);
0086 }
0087
0088 return 0;
0089 }
0090
0091 static int bcm54612e_config_init(struct phy_device *phydev)
0092 {
0093 int reg;
0094
0095 bcm54xx_config_clock_delay(phydev);
0096
0097
0098 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
0099 int err;
0100
0101 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
0102 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
0103 BCM54612E_LED4_CLK125OUT_EN | reg);
0104
0105 if (err < 0)
0106 return err;
0107 }
0108
0109 return 0;
0110 }
0111
0112 static int bcm54616s_config_init(struct phy_device *phydev)
0113 {
0114 int rc, val;
0115
0116 if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
0117 phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
0118 return 0;
0119
0120
0121
0122 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
0123 if (val < 0)
0124 return val;
0125 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
0126 val |= MII_BCM54XX_AUXCTL_MISC_WREN;
0127 rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
0128 val);
0129 if (rc < 0)
0130 return rc;
0131
0132
0133 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
0134 if (val < 0)
0135 return val;
0136 val |= BCM54XX_SHD_MODE_1000BX;
0137 rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
0138 if (rc < 0)
0139 return rc;
0140
0141
0142 rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
0143 if (rc < 0)
0144 return rc;
0145
0146
0147 val &= ~BCM54XX_SHD_INTF_SEL_MASK;
0148 val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
0149 BCM54XX_SHD_INTF_SEL_SGMII :
0150 BCM54XX_SHD_INTF_SEL_GBIC;
0151 rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
0152 if (rc < 0)
0153 return rc;
0154
0155
0156 rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
0157 if (rc < 0)
0158 return rc;
0159
0160
0161 val &= ~BCM54XX_SHD_MODE_1000BX;
0162 rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
0163 if (rc < 0)
0164 return rc;
0165
0166
0167 return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
0168 }
0169
0170
0171 static int bcm50610_a0_workaround(struct phy_device *phydev)
0172 {
0173 int err;
0174
0175 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
0176 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
0177 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
0178 if (err < 0)
0179 return err;
0180
0181 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
0182 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
0183 if (err < 0)
0184 return err;
0185
0186 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
0187 MII_BCM54XX_EXP_EXP75_VDACCTRL);
0188 if (err < 0)
0189 return err;
0190
0191 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
0192 MII_BCM54XX_EXP_EXP96_MYST);
0193 if (err < 0)
0194 return err;
0195
0196 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
0197 MII_BCM54XX_EXP_EXP97_MYST);
0198
0199 return err;
0200 }
0201
0202 static int bcm54xx_phydsp_config(struct phy_device *phydev)
0203 {
0204 int err, err2;
0205
0206
0207 err = bcm54xx_auxctl_write(phydev,
0208 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
0209 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
0210 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
0211 if (err < 0)
0212 return err;
0213
0214 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
0215 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
0216
0217 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
0218 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
0219 if (err < 0)
0220 goto error;
0221
0222 if (phydev->drv->phy_id == PHY_ID_BCM50610) {
0223 err = bcm50610_a0_workaround(phydev);
0224 if (err < 0)
0225 goto error;
0226 }
0227 }
0228
0229 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
0230 int val;
0231
0232 val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
0233 if (val < 0)
0234 goto error;
0235
0236 val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
0237 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
0238 }
0239
0240 error:
0241
0242 err2 = bcm54xx_auxctl_write(phydev,
0243 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
0244 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
0245
0246
0247 return err ? err : err2;
0248 }
0249
0250 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
0251 {
0252 u32 orig;
0253 int val;
0254 bool clk125en = true;
0255
0256
0257 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
0258 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
0259 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
0260 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E &&
0261 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
0262 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
0263 return;
0264
0265 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
0266 if (val < 0)
0267 return;
0268
0269 orig = val;
0270
0271 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
0272 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
0273 BRCM_PHY_REV(phydev) >= 0x3) {
0274
0275
0276
0277
0278 clk125en = false;
0279 } else {
0280 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
0281 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) {
0282
0283 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
0284 }
0285 clk125en = false;
0286 }
0287 }
0288
0289 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
0290 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
0291 else
0292 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
0293
0294 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
0295 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
0296 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
0297 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
0298 val |= BCM54XX_SHD_SCR3_RXCTXC_DIS;
0299 else
0300 val |= BCM54XX_SHD_SCR3_TRDDAPD;
0301 }
0302
0303 if (orig != val)
0304 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
0305
0306 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
0307 if (val < 0)
0308 return;
0309
0310 orig = val;
0311
0312 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
0313 val |= BCM54XX_SHD_APD_EN;
0314 else
0315 val &= ~BCM54XX_SHD_APD_EN;
0316
0317 if (orig != val)
0318 bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
0319 }
0320
0321 static void bcm54xx_ptp_stop(struct phy_device *phydev)
0322 {
0323 struct bcm54xx_phy_priv *priv = phydev->priv;
0324
0325 if (priv->ptp)
0326 bcm_ptp_stop(priv->ptp);
0327 }
0328
0329 static void bcm54xx_ptp_config_init(struct phy_device *phydev)
0330 {
0331 struct bcm54xx_phy_priv *priv = phydev->priv;
0332
0333 if (priv->ptp)
0334 bcm_ptp_config_init(phydev);
0335 }
0336
0337 static int bcm54xx_config_init(struct phy_device *phydev)
0338 {
0339 int reg, err, val;
0340
0341 reg = phy_read(phydev, MII_BCM54XX_ECR);
0342 if (reg < 0)
0343 return reg;
0344
0345
0346 reg |= MII_BCM54XX_ECR_IM;
0347 err = phy_write(phydev, MII_BCM54XX_ECR, reg);
0348 if (err < 0)
0349 return err;
0350
0351
0352 reg = ~(MII_BCM54XX_INT_DUPLEX |
0353 MII_BCM54XX_INT_SPEED |
0354 MII_BCM54XX_INT_LINK);
0355 err = phy_write(phydev, MII_BCM54XX_IMR, reg);
0356 if (err < 0)
0357 return err;
0358
0359 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
0360 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
0361 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
0362 bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
0363
0364 bcm54xx_adjust_rxrefclk(phydev);
0365
0366 switch (BRCM_PHY_MODEL(phydev)) {
0367 case PHY_ID_BCM50610:
0368 case PHY_ID_BCM50610M:
0369 err = bcm54xx_config_clock_delay(phydev);
0370 break;
0371 case PHY_ID_BCM54210E:
0372 err = bcm54210e_config_init(phydev);
0373 break;
0374 case PHY_ID_BCM54612E:
0375 err = bcm54612e_config_init(phydev);
0376 break;
0377 case PHY_ID_BCM54616S:
0378 err = bcm54616s_config_init(phydev);
0379 break;
0380 case PHY_ID_BCM54810:
0381
0382 val = bcm_phy_read_exp(phydev,
0383 BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
0384 val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
0385 err = bcm_phy_write_exp(phydev,
0386 BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
0387 val);
0388 break;
0389 }
0390 if (err)
0391 return err;
0392
0393 bcm54xx_phydsp_config(phydev);
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 if (!phy_on_sfp(phydev)) {
0404 val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
0405 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
0406 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
0407
0408 val = BCM_LED_MULTICOLOR_IN_PHASE |
0409 BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
0410 BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
0411 bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
0412 }
0413
0414 bcm54xx_ptp_config_init(phydev);
0415
0416 return 0;
0417 }
0418
0419 static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable)
0420 {
0421 int ret = 0;
0422
0423 if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND))
0424 return ret;
0425
0426 ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL);
0427 if (ret < 0)
0428 goto out;
0429
0430 if (enable)
0431 ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP;
0432 else
0433 ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP);
0434
0435 ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret);
0436 out:
0437 return ret;
0438 }
0439
0440 static int bcm54xx_suspend(struct phy_device *phydev)
0441 {
0442 int ret;
0443
0444 bcm54xx_ptp_stop(phydev);
0445
0446
0447
0448
0449
0450 ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN);
0451 if (ret < 0)
0452 return ret;
0453
0454 return bcm54xx_iddq_set(phydev, true);
0455 }
0456
0457 static int bcm54xx_resume(struct phy_device *phydev)
0458 {
0459 int ret;
0460
0461 ret = bcm54xx_iddq_set(phydev, false);
0462 if (ret < 0)
0463 return ret;
0464
0465
0466
0467
0468 ret = genphy_resume(phydev);
0469 if (ret < 0)
0470 return ret;
0471
0472
0473
0474
0475 fsleep(40);
0476
0477
0478
0479
0480 if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) {
0481 ret = genphy_soft_reset(phydev);
0482 if (ret < 0)
0483 return ret;
0484 }
0485
0486 return bcm54xx_config_init(phydev);
0487 }
0488
0489 static int bcm54811_config_init(struct phy_device *phydev)
0490 {
0491 int err, reg;
0492
0493
0494 reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
0495 reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
0496 err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
0497 reg);
0498 if (err < 0)
0499 return err;
0500
0501 err = bcm54xx_config_init(phydev);
0502
0503
0504 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
0505 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
0506 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
0507 BCM54612E_LED4_CLK125OUT_EN | reg);
0508 if (err < 0)
0509 return err;
0510 }
0511
0512 return err;
0513 }
0514
0515 static int bcm5481_config_aneg(struct phy_device *phydev)
0516 {
0517 struct device_node *np = phydev->mdio.dev.of_node;
0518 int ret;
0519
0520
0521 ret = genphy_config_aneg(phydev);
0522
0523
0524 bcm54xx_config_clock_delay(phydev);
0525
0526 if (of_property_read_bool(np, "enet-phy-lane-swap")) {
0527
0528 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
0529 0x11B);
0530 if (ret < 0)
0531 return ret;
0532 }
0533
0534 return ret;
0535 }
0536
0537 struct bcm54616s_phy_priv {
0538 bool mode_1000bx_en;
0539 };
0540
0541 static int bcm54616s_probe(struct phy_device *phydev)
0542 {
0543 struct bcm54616s_phy_priv *priv;
0544 int val;
0545
0546 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
0547 if (!priv)
0548 return -ENOMEM;
0549
0550 phydev->priv = priv;
0551
0552 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
0553 if (val < 0)
0554 return val;
0555
0556
0557
0558
0559
0560
0561
0562 if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
0563 val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
0564 if (val < 0)
0565 return val;
0566
0567
0568
0569
0570
0571
0572 if (!(val & BCM54616S_100FX_MODE))
0573 priv->mode_1000bx_en = true;
0574
0575 phydev->port = PORT_FIBRE;
0576 }
0577
0578 return 0;
0579 }
0580
0581 static int bcm54616s_config_aneg(struct phy_device *phydev)
0582 {
0583 struct bcm54616s_phy_priv *priv = phydev->priv;
0584 int ret;
0585
0586
0587 if (priv->mode_1000bx_en)
0588 ret = genphy_c37_config_aneg(phydev);
0589 else
0590 ret = genphy_config_aneg(phydev);
0591
0592
0593 bcm54xx_config_clock_delay(phydev);
0594
0595 return ret;
0596 }
0597
0598 static int bcm54616s_read_status(struct phy_device *phydev)
0599 {
0600 struct bcm54616s_phy_priv *priv = phydev->priv;
0601 int err;
0602
0603 if (priv->mode_1000bx_en)
0604 err = genphy_c37_read_status(phydev);
0605 else
0606 err = genphy_read_status(phydev);
0607
0608 return err;
0609 }
0610
0611 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
0612 {
0613 int val;
0614
0615 val = phy_read(phydev, reg);
0616 if (val < 0)
0617 return val;
0618
0619 return phy_write(phydev, reg, val | set);
0620 }
0621
0622 static int brcm_fet_config_init(struct phy_device *phydev)
0623 {
0624 int reg, err, err2, brcmtest;
0625
0626
0627 err = phy_write(phydev, MII_BMCR, BMCR_RESET);
0628 if (err < 0)
0629 return err;
0630
0631
0632
0633
0634 usleep_range(1000, 2000);
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647 err = phy_read(phydev, MII_BMCR);
0648 if (err < 0 && err != -EIO)
0649 return err;
0650
0651 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
0652 if (reg < 0)
0653 return reg;
0654
0655
0656 reg = MII_BRCM_FET_IR_DUPLEX_EN |
0657 MII_BRCM_FET_IR_SPEED_EN |
0658 MII_BRCM_FET_IR_LINK_EN |
0659 MII_BRCM_FET_IR_ENABLE |
0660 MII_BRCM_FET_IR_MASK;
0661
0662 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
0663 if (err < 0)
0664 return err;
0665
0666
0667 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
0668 if (brcmtest < 0)
0669 return brcmtest;
0670
0671 reg = brcmtest | MII_BRCM_FET_BT_SRE;
0672
0673 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
0674 if (err < 0)
0675 return err;
0676
0677
0678 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
0679 if (reg < 0) {
0680 err = reg;
0681 goto done;
0682 }
0683
0684 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
0685 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
0686
0687 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
0688 if (err < 0)
0689 goto done;
0690
0691
0692 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
0693 MII_BRCM_FET_SHDW_MC_FAME);
0694 if (err < 0)
0695 goto done;
0696
0697 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
0698
0699 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
0700 MII_BRCM_FET_SHDW_AS2_APDE);
0701 }
0702
0703 done:
0704
0705 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
0706 if (!err)
0707 err = err2;
0708
0709 return err;
0710 }
0711
0712 static int brcm_fet_ack_interrupt(struct phy_device *phydev)
0713 {
0714 int reg;
0715
0716
0717 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
0718 if (reg < 0)
0719 return reg;
0720
0721 return 0;
0722 }
0723
0724 static int brcm_fet_config_intr(struct phy_device *phydev)
0725 {
0726 int reg, err;
0727
0728 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
0729 if (reg < 0)
0730 return reg;
0731
0732 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0733 err = brcm_fet_ack_interrupt(phydev);
0734 if (err)
0735 return err;
0736
0737 reg &= ~MII_BRCM_FET_IR_MASK;
0738 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
0739 } else {
0740 reg |= MII_BRCM_FET_IR_MASK;
0741 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
0742 if (err)
0743 return err;
0744
0745 err = brcm_fet_ack_interrupt(phydev);
0746 }
0747
0748 return err;
0749 }
0750
0751 static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
0752 {
0753 int irq_status;
0754
0755 irq_status = phy_read(phydev, MII_BRCM_FET_INTREG);
0756 if (irq_status < 0) {
0757 phy_error(phydev);
0758 return IRQ_NONE;
0759 }
0760
0761 if (irq_status == 0)
0762 return IRQ_NONE;
0763
0764 phy_trigger_machine(phydev);
0765
0766 return IRQ_HANDLED;
0767 }
0768
0769 static int bcm54xx_phy_probe(struct phy_device *phydev)
0770 {
0771 struct bcm54xx_phy_priv *priv;
0772
0773 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
0774 if (!priv)
0775 return -ENOMEM;
0776
0777 phydev->priv = priv;
0778
0779 priv->stats = devm_kcalloc(&phydev->mdio.dev,
0780 bcm_phy_get_sset_count(phydev), sizeof(u64),
0781 GFP_KERNEL);
0782 if (!priv->stats)
0783 return -ENOMEM;
0784
0785 priv->ptp = bcm_ptp_probe(phydev);
0786 if (IS_ERR(priv->ptp))
0787 return PTR_ERR(priv->ptp);
0788
0789 return 0;
0790 }
0791
0792 static void bcm54xx_get_stats(struct phy_device *phydev,
0793 struct ethtool_stats *stats, u64 *data)
0794 {
0795 struct bcm54xx_phy_priv *priv = phydev->priv;
0796
0797 bcm_phy_get_stats(phydev, priv->stats, stats, data);
0798 }
0799
0800 static void bcm54xx_link_change_notify(struct phy_device *phydev)
0801 {
0802 u16 mask = MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE |
0803 MII_BCM54XX_EXP_EXP08_FORCE_DAC_WAKE;
0804 int ret;
0805
0806 if (phydev->state != PHY_RUNNING)
0807 return;
0808
0809
0810
0811
0812 if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
0813 return;
0814
0815 ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08);
0816 if (ret < 0)
0817 return;
0818
0819
0820
0821
0822
0823 if (phydev->speed == SPEED_10)
0824 ret |= mask;
0825 else
0826 ret &= ~mask;
0827 bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret);
0828 }
0829
0830 static struct phy_driver broadcom_drivers[] = {
0831 {
0832 .phy_id = PHY_ID_BCM5411,
0833 .phy_id_mask = 0xfffffff0,
0834 .name = "Broadcom BCM5411",
0835
0836 .get_sset_count = bcm_phy_get_sset_count,
0837 .get_strings = bcm_phy_get_strings,
0838 .get_stats = bcm54xx_get_stats,
0839 .probe = bcm54xx_phy_probe,
0840 .config_init = bcm54xx_config_init,
0841 .config_intr = bcm_phy_config_intr,
0842 .handle_interrupt = bcm_phy_handle_interrupt,
0843 .link_change_notify = bcm54xx_link_change_notify,
0844 }, {
0845 .phy_id = PHY_ID_BCM5421,
0846 .phy_id_mask = 0xfffffff0,
0847 .name = "Broadcom BCM5421",
0848
0849 .get_sset_count = bcm_phy_get_sset_count,
0850 .get_strings = bcm_phy_get_strings,
0851 .get_stats = bcm54xx_get_stats,
0852 .probe = bcm54xx_phy_probe,
0853 .config_init = bcm54xx_config_init,
0854 .config_intr = bcm_phy_config_intr,
0855 .handle_interrupt = bcm_phy_handle_interrupt,
0856 .link_change_notify = bcm54xx_link_change_notify,
0857 }, {
0858 .phy_id = PHY_ID_BCM54210E,
0859 .phy_id_mask = 0xfffffff0,
0860 .name = "Broadcom BCM54210E",
0861
0862 .get_sset_count = bcm_phy_get_sset_count,
0863 .get_strings = bcm_phy_get_strings,
0864 .get_stats = bcm54xx_get_stats,
0865 .probe = bcm54xx_phy_probe,
0866 .config_init = bcm54xx_config_init,
0867 .config_intr = bcm_phy_config_intr,
0868 .handle_interrupt = bcm_phy_handle_interrupt,
0869 .link_change_notify = bcm54xx_link_change_notify,
0870 .suspend = bcm54xx_suspend,
0871 .resume = bcm54xx_resume,
0872 }, {
0873 .phy_id = PHY_ID_BCM5461,
0874 .phy_id_mask = 0xfffffff0,
0875 .name = "Broadcom BCM5461",
0876
0877 .get_sset_count = bcm_phy_get_sset_count,
0878 .get_strings = bcm_phy_get_strings,
0879 .get_stats = bcm54xx_get_stats,
0880 .probe = bcm54xx_phy_probe,
0881 .config_init = bcm54xx_config_init,
0882 .config_intr = bcm_phy_config_intr,
0883 .handle_interrupt = bcm_phy_handle_interrupt,
0884 .link_change_notify = bcm54xx_link_change_notify,
0885 }, {
0886 .phy_id = PHY_ID_BCM54612E,
0887 .phy_id_mask = 0xfffffff0,
0888 .name = "Broadcom BCM54612E",
0889
0890 .get_sset_count = bcm_phy_get_sset_count,
0891 .get_strings = bcm_phy_get_strings,
0892 .get_stats = bcm54xx_get_stats,
0893 .probe = bcm54xx_phy_probe,
0894 .config_init = bcm54xx_config_init,
0895 .config_intr = bcm_phy_config_intr,
0896 .handle_interrupt = bcm_phy_handle_interrupt,
0897 .link_change_notify = bcm54xx_link_change_notify,
0898 }, {
0899 .phy_id = PHY_ID_BCM54616S,
0900 .phy_id_mask = 0xfffffff0,
0901 .name = "Broadcom BCM54616S",
0902
0903 .soft_reset = genphy_soft_reset,
0904 .config_init = bcm54xx_config_init,
0905 .config_aneg = bcm54616s_config_aneg,
0906 .config_intr = bcm_phy_config_intr,
0907 .handle_interrupt = bcm_phy_handle_interrupt,
0908 .read_status = bcm54616s_read_status,
0909 .probe = bcm54616s_probe,
0910 .link_change_notify = bcm54xx_link_change_notify,
0911 }, {
0912 .phy_id = PHY_ID_BCM5464,
0913 .phy_id_mask = 0xfffffff0,
0914 .name = "Broadcom BCM5464",
0915
0916 .get_sset_count = bcm_phy_get_sset_count,
0917 .get_strings = bcm_phy_get_strings,
0918 .get_stats = bcm54xx_get_stats,
0919 .probe = bcm54xx_phy_probe,
0920 .config_init = bcm54xx_config_init,
0921 .config_intr = bcm_phy_config_intr,
0922 .handle_interrupt = bcm_phy_handle_interrupt,
0923 .suspend = genphy_suspend,
0924 .resume = genphy_resume,
0925 .link_change_notify = bcm54xx_link_change_notify,
0926 }, {
0927 .phy_id = PHY_ID_BCM5481,
0928 .phy_id_mask = 0xfffffff0,
0929 .name = "Broadcom BCM5481",
0930
0931 .get_sset_count = bcm_phy_get_sset_count,
0932 .get_strings = bcm_phy_get_strings,
0933 .get_stats = bcm54xx_get_stats,
0934 .probe = bcm54xx_phy_probe,
0935 .config_init = bcm54xx_config_init,
0936 .config_aneg = bcm5481_config_aneg,
0937 .config_intr = bcm_phy_config_intr,
0938 .handle_interrupt = bcm_phy_handle_interrupt,
0939 .link_change_notify = bcm54xx_link_change_notify,
0940 }, {
0941 .phy_id = PHY_ID_BCM54810,
0942 .phy_id_mask = 0xfffffff0,
0943 .name = "Broadcom BCM54810",
0944
0945 .get_sset_count = bcm_phy_get_sset_count,
0946 .get_strings = bcm_phy_get_strings,
0947 .get_stats = bcm54xx_get_stats,
0948 .probe = bcm54xx_phy_probe,
0949 .config_init = bcm54xx_config_init,
0950 .config_aneg = bcm5481_config_aneg,
0951 .config_intr = bcm_phy_config_intr,
0952 .handle_interrupt = bcm_phy_handle_interrupt,
0953 .suspend = bcm54xx_suspend,
0954 .resume = bcm54xx_resume,
0955 .link_change_notify = bcm54xx_link_change_notify,
0956 }, {
0957 .phy_id = PHY_ID_BCM54811,
0958 .phy_id_mask = 0xfffffff0,
0959 .name = "Broadcom BCM54811",
0960
0961 .get_sset_count = bcm_phy_get_sset_count,
0962 .get_strings = bcm_phy_get_strings,
0963 .get_stats = bcm54xx_get_stats,
0964 .probe = bcm54xx_phy_probe,
0965 .config_init = bcm54811_config_init,
0966 .config_aneg = bcm5481_config_aneg,
0967 .config_intr = bcm_phy_config_intr,
0968 .handle_interrupt = bcm_phy_handle_interrupt,
0969 .suspend = bcm54xx_suspend,
0970 .resume = bcm54xx_resume,
0971 .link_change_notify = bcm54xx_link_change_notify,
0972 }, {
0973 .phy_id = PHY_ID_BCM5482,
0974 .phy_id_mask = 0xfffffff0,
0975 .name = "Broadcom BCM5482",
0976
0977 .get_sset_count = bcm_phy_get_sset_count,
0978 .get_strings = bcm_phy_get_strings,
0979 .get_stats = bcm54xx_get_stats,
0980 .probe = bcm54xx_phy_probe,
0981 .config_init = bcm54xx_config_init,
0982 .config_intr = bcm_phy_config_intr,
0983 .handle_interrupt = bcm_phy_handle_interrupt,
0984 .link_change_notify = bcm54xx_link_change_notify,
0985 }, {
0986 .phy_id = PHY_ID_BCM50610,
0987 .phy_id_mask = 0xfffffff0,
0988 .name = "Broadcom BCM50610",
0989
0990 .get_sset_count = bcm_phy_get_sset_count,
0991 .get_strings = bcm_phy_get_strings,
0992 .get_stats = bcm54xx_get_stats,
0993 .probe = bcm54xx_phy_probe,
0994 .config_init = bcm54xx_config_init,
0995 .config_intr = bcm_phy_config_intr,
0996 .handle_interrupt = bcm_phy_handle_interrupt,
0997 .link_change_notify = bcm54xx_link_change_notify,
0998 .suspend = bcm54xx_suspend,
0999 .resume = bcm54xx_resume,
1000 }, {
1001 .phy_id = PHY_ID_BCM50610M,
1002 .phy_id_mask = 0xfffffff0,
1003 .name = "Broadcom BCM50610M",
1004
1005 .get_sset_count = bcm_phy_get_sset_count,
1006 .get_strings = bcm_phy_get_strings,
1007 .get_stats = bcm54xx_get_stats,
1008 .probe = bcm54xx_phy_probe,
1009 .config_init = bcm54xx_config_init,
1010 .config_intr = bcm_phy_config_intr,
1011 .handle_interrupt = bcm_phy_handle_interrupt,
1012 .link_change_notify = bcm54xx_link_change_notify,
1013 .suspend = bcm54xx_suspend,
1014 .resume = bcm54xx_resume,
1015 }, {
1016 .phy_id = PHY_ID_BCM57780,
1017 .phy_id_mask = 0xfffffff0,
1018 .name = "Broadcom BCM57780",
1019
1020 .get_sset_count = bcm_phy_get_sset_count,
1021 .get_strings = bcm_phy_get_strings,
1022 .get_stats = bcm54xx_get_stats,
1023 .probe = bcm54xx_phy_probe,
1024 .config_init = bcm54xx_config_init,
1025 .config_intr = bcm_phy_config_intr,
1026 .handle_interrupt = bcm_phy_handle_interrupt,
1027 .link_change_notify = bcm54xx_link_change_notify,
1028 }, {
1029 .phy_id = PHY_ID_BCMAC131,
1030 .phy_id_mask = 0xfffffff0,
1031 .name = "Broadcom BCMAC131",
1032
1033 .config_init = brcm_fet_config_init,
1034 .config_intr = brcm_fet_config_intr,
1035 .handle_interrupt = brcm_fet_handle_interrupt,
1036 }, {
1037 .phy_id = PHY_ID_BCM5241,
1038 .phy_id_mask = 0xfffffff0,
1039 .name = "Broadcom BCM5241",
1040
1041 .config_init = brcm_fet_config_init,
1042 .config_intr = brcm_fet_config_intr,
1043 .handle_interrupt = brcm_fet_handle_interrupt,
1044 }, {
1045 .phy_id = PHY_ID_BCM5395,
1046 .phy_id_mask = 0xfffffff0,
1047 .name = "Broadcom BCM5395",
1048 .flags = PHY_IS_INTERNAL,
1049
1050 .get_sset_count = bcm_phy_get_sset_count,
1051 .get_strings = bcm_phy_get_strings,
1052 .get_stats = bcm54xx_get_stats,
1053 .probe = bcm54xx_phy_probe,
1054 .link_change_notify = bcm54xx_link_change_notify,
1055 }, {
1056 .phy_id = PHY_ID_BCM53125,
1057 .phy_id_mask = 0xfffffff0,
1058 .name = "Broadcom BCM53125",
1059 .flags = PHY_IS_INTERNAL,
1060
1061 .get_sset_count = bcm_phy_get_sset_count,
1062 .get_strings = bcm_phy_get_strings,
1063 .get_stats = bcm54xx_get_stats,
1064 .probe = bcm54xx_phy_probe,
1065 .config_init = bcm54xx_config_init,
1066 .config_intr = bcm_phy_config_intr,
1067 .handle_interrupt = bcm_phy_handle_interrupt,
1068 .link_change_notify = bcm54xx_link_change_notify,
1069 }, {
1070 .phy_id = PHY_ID_BCM53128,
1071 .phy_id_mask = 0xfffffff0,
1072 .name = "Broadcom BCM53128",
1073 .flags = PHY_IS_INTERNAL,
1074
1075 .get_sset_count = bcm_phy_get_sset_count,
1076 .get_strings = bcm_phy_get_strings,
1077 .get_stats = bcm54xx_get_stats,
1078 .probe = bcm54xx_phy_probe,
1079 .config_init = bcm54xx_config_init,
1080 .config_intr = bcm_phy_config_intr,
1081 .handle_interrupt = bcm_phy_handle_interrupt,
1082 .link_change_notify = bcm54xx_link_change_notify,
1083 }, {
1084 .phy_id = PHY_ID_BCM89610,
1085 .phy_id_mask = 0xfffffff0,
1086 .name = "Broadcom BCM89610",
1087
1088 .get_sset_count = bcm_phy_get_sset_count,
1089 .get_strings = bcm_phy_get_strings,
1090 .get_stats = bcm54xx_get_stats,
1091 .probe = bcm54xx_phy_probe,
1092 .config_init = bcm54xx_config_init,
1093 .config_intr = bcm_phy_config_intr,
1094 .handle_interrupt = bcm_phy_handle_interrupt,
1095 .link_change_notify = bcm54xx_link_change_notify,
1096 } };
1097
1098 module_phy_driver(broadcom_drivers);
1099
1100 static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
1101 { PHY_ID_BCM5411, 0xfffffff0 },
1102 { PHY_ID_BCM5421, 0xfffffff0 },
1103 { PHY_ID_BCM54210E, 0xfffffff0 },
1104 { PHY_ID_BCM5461, 0xfffffff0 },
1105 { PHY_ID_BCM54612E, 0xfffffff0 },
1106 { PHY_ID_BCM54616S, 0xfffffff0 },
1107 { PHY_ID_BCM5464, 0xfffffff0 },
1108 { PHY_ID_BCM5481, 0xfffffff0 },
1109 { PHY_ID_BCM54810, 0xfffffff0 },
1110 { PHY_ID_BCM54811, 0xfffffff0 },
1111 { PHY_ID_BCM5482, 0xfffffff0 },
1112 { PHY_ID_BCM50610, 0xfffffff0 },
1113 { PHY_ID_BCM50610M, 0xfffffff0 },
1114 { PHY_ID_BCM57780, 0xfffffff0 },
1115 { PHY_ID_BCMAC131, 0xfffffff0 },
1116 { PHY_ID_BCM5241, 0xfffffff0 },
1117 { PHY_ID_BCM5395, 0xfffffff0 },
1118 { PHY_ID_BCM53125, 0xfffffff0 },
1119 { PHY_ID_BCM53128, 0xfffffff0 },
1120 { PHY_ID_BCM89610, 0xfffffff0 },
1121 { }
1122 };
1123
1124 MODULE_DEVICE_TABLE(mdio, broadcom_tbl);