0001
0002
0003
0004 #include "igc_phy.h"
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 s32 igc_check_reset_block(struct igc_hw *hw)
0015 {
0016 u32 manc;
0017
0018 manc = rd32(IGC_MANC);
0019
0020 return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
0021 IGC_ERR_BLK_PHY_RESET : 0;
0022 }
0023
0024
0025
0026
0027
0028
0029
0030
0031 s32 igc_get_phy_id(struct igc_hw *hw)
0032 {
0033 struct igc_phy_info *phy = &hw->phy;
0034 s32 ret_val = 0;
0035 u16 phy_id;
0036
0037 ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
0038 if (ret_val)
0039 goto out;
0040
0041 phy->id = (u32)(phy_id << 16);
0042 usleep_range(200, 500);
0043 ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
0044 if (ret_val)
0045 goto out;
0046
0047 phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
0048 phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
0049
0050 out:
0051 return ret_val;
0052 }
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
0064 u32 usec_interval, bool *success)
0065 {
0066 u16 i, phy_status;
0067 s32 ret_val = 0;
0068
0069 for (i = 0; i < iterations; i++) {
0070
0071
0072
0073
0074 ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
0075 if (ret_val && usec_interval > 0) {
0076
0077
0078
0079
0080 if (usec_interval >= 1000)
0081 mdelay(usec_interval / 1000);
0082 else
0083 udelay(usec_interval);
0084 }
0085 ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
0086 if (ret_val)
0087 break;
0088 if (phy_status & MII_SR_LINK_STATUS)
0089 break;
0090 if (usec_interval >= 1000)
0091 mdelay(usec_interval / 1000);
0092 else
0093 udelay(usec_interval);
0094 }
0095
0096 *success = (i < iterations) ? true : false;
0097
0098 return ret_val;
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108 void igc_power_up_phy_copper(struct igc_hw *hw)
0109 {
0110 u16 mii_reg = 0;
0111
0112
0113 hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
0114 mii_reg &= ~MII_CR_POWER_DOWN;
0115 hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125 void igc_power_down_phy_copper(struct igc_hw *hw)
0126 {
0127 u16 mii_reg = 0;
0128
0129
0130 hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
0131 mii_reg |= MII_CR_POWER_DOWN;
0132
0133
0134
0135
0136
0137 usleep_range(1000, 2000);
0138 }
0139
0140
0141
0142
0143
0144
0145
0146 void igc_check_downshift(struct igc_hw *hw)
0147 {
0148 struct igc_phy_info *phy = &hw->phy;
0149
0150
0151 phy->speed_downgraded = false;
0152 }
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 s32 igc_phy_hw_reset(struct igc_hw *hw)
0164 {
0165 struct igc_phy_info *phy = &hw->phy;
0166 u32 phpm = 0, timeout = 10000;
0167 s32 ret_val;
0168 u32 ctrl;
0169
0170 ret_val = igc_check_reset_block(hw);
0171 if (ret_val) {
0172 ret_val = 0;
0173 goto out;
0174 }
0175
0176 ret_val = phy->ops.acquire(hw);
0177 if (ret_val)
0178 goto out;
0179
0180 phpm = rd32(IGC_I225_PHPM);
0181
0182 ctrl = rd32(IGC_CTRL);
0183 wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
0184 wrfl();
0185
0186 udelay(phy->reset_delay_us);
0187
0188 wr32(IGC_CTRL, ctrl);
0189 wrfl();
0190
0191
0192 usleep_range(100, 150);
0193 do {
0194 phpm = rd32(IGC_I225_PHPM);
0195 timeout--;
0196 udelay(1);
0197 } while (!(phpm & IGC_PHY_RST_COMP) && timeout);
0198
0199 if (!timeout)
0200 hw_dbg("Timeout is expired after a phy reset\n");
0201
0202 usleep_range(100, 150);
0203
0204 phy->ops.release(hw);
0205
0206 out:
0207 return ret_val;
0208 }
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
0220 {
0221 struct igc_phy_info *phy = &hw->phy;
0222 u16 aneg_multigbt_an_ctrl = 0;
0223 u16 mii_1000t_ctrl_reg = 0;
0224 u16 mii_autoneg_adv_reg;
0225 s32 ret_val;
0226
0227 phy->autoneg_advertised &= phy->autoneg_mask;
0228
0229
0230 ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
0231 if (ret_val)
0232 return ret_val;
0233
0234 if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
0235
0236 ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
0237 &mii_1000t_ctrl_reg);
0238 if (ret_val)
0239 return ret_val;
0240 }
0241
0242 if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
0243
0244 ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
0245 MMD_DEVADDR_SHIFT) |
0246 ANEG_MULTIGBT_AN_CTRL,
0247 &aneg_multigbt_an_ctrl);
0248
0249 if (ret_val)
0250 return ret_val;
0251 }
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
0265 NWAY_AR_100TX_HD_CAPS |
0266 NWAY_AR_10T_FD_CAPS |
0267 NWAY_AR_10T_HD_CAPS);
0268 mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
0269
0270 hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
0271
0272
0273 if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
0274 hw_dbg("Advertise 10mb Half duplex\n");
0275 mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
0276 }
0277
0278
0279 if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
0280 hw_dbg("Advertise 10mb Full duplex\n");
0281 mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
0282 }
0283
0284
0285 if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
0286 hw_dbg("Advertise 100mb Half duplex\n");
0287 mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
0288 }
0289
0290
0291 if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
0292 hw_dbg("Advertise 100mb Full duplex\n");
0293 mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
0294 }
0295
0296
0297 if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
0298 hw_dbg("Advertise 1000mb Half duplex request denied!\n");
0299
0300
0301 if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
0302 hw_dbg("Advertise 1000mb Full duplex\n");
0303 mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
0304 }
0305
0306
0307 if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
0308 hw_dbg("Advertise 2500mb Half duplex request denied!\n");
0309
0310
0311 if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
0312 hw_dbg("Advertise 2500mb Full duplex\n");
0313 aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
0314 } else {
0315 aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
0316 }
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335 switch (hw->fc.current_mode) {
0336 case igc_fc_none:
0337
0338
0339
0340 mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
0341 break;
0342 case igc_fc_rx_pause:
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352 mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
0353 break;
0354 case igc_fc_tx_pause:
0355
0356
0357
0358 mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
0359 mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
0360 break;
0361 case igc_fc_full:
0362
0363
0364
0365 mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
0366 break;
0367 default:
0368 hw_dbg("Flow control param set incorrectly\n");
0369 return -IGC_ERR_CONFIG;
0370 }
0371
0372 ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
0373 if (ret_val)
0374 return ret_val;
0375
0376 hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
0377
0378 if (phy->autoneg_mask & ADVERTISE_1000_FULL)
0379 ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
0380 mii_1000t_ctrl_reg);
0381
0382 if (phy->autoneg_mask & ADVERTISE_2500_FULL)
0383 ret_val = phy->ops.write_reg(hw,
0384 (STANDARD_AN_REG_MASK <<
0385 MMD_DEVADDR_SHIFT) |
0386 ANEG_MULTIGBT_AN_CTRL,
0387 aneg_multigbt_an_ctrl);
0388
0389 return ret_val;
0390 }
0391
0392
0393
0394
0395
0396
0397
0398
0399 static s32 igc_wait_autoneg(struct igc_hw *hw)
0400 {
0401 u16 i, phy_status;
0402 s32 ret_val = 0;
0403
0404
0405 for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
0406 ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
0407 if (ret_val)
0408 break;
0409 ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
0410 if (ret_val)
0411 break;
0412 if (phy_status & MII_SR_AUTONEG_COMPLETE)
0413 break;
0414 msleep(100);
0415 }
0416
0417
0418
0419
0420 return ret_val;
0421 }
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432 static s32 igc_copper_link_autoneg(struct igc_hw *hw)
0433 {
0434 struct igc_phy_info *phy = &hw->phy;
0435 u16 phy_ctrl;
0436 s32 ret_val;
0437
0438
0439
0440
0441 phy->autoneg_advertised &= phy->autoneg_mask;
0442
0443
0444
0445
0446 if (phy->autoneg_advertised == 0)
0447 phy->autoneg_advertised = phy->autoneg_mask;
0448
0449 hw_dbg("Reconfiguring auto-neg advertisement params\n");
0450 ret_val = igc_phy_setup_autoneg(hw);
0451 if (ret_val) {
0452 hw_dbg("Error Setting up Auto-Negotiation\n");
0453 goto out;
0454 }
0455 hw_dbg("Restarting Auto-Neg\n");
0456
0457
0458
0459
0460 ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
0461 if (ret_val)
0462 goto out;
0463
0464 phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
0465 ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
0466 if (ret_val)
0467 goto out;
0468
0469
0470
0471
0472 if (phy->autoneg_wait_to_complete) {
0473 ret_val = igc_wait_autoneg(hw);
0474 if (ret_val) {
0475 hw_dbg("Error while waiting for autoneg to complete\n");
0476 goto out;
0477 }
0478 }
0479
0480 hw->mac.get_link_status = true;
0481
0482 out:
0483 return ret_val;
0484 }
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495 s32 igc_setup_copper_link(struct igc_hw *hw)
0496 {
0497 s32 ret_val = 0;
0498 bool link;
0499
0500 if (hw->mac.autoneg) {
0501
0502
0503
0504 ret_val = igc_copper_link_autoneg(hw);
0505 if (ret_val)
0506 goto out;
0507 } else {
0508
0509
0510
0511 hw_dbg("Forcing Speed and Duplex\n");
0512 ret_val = hw->phy.ops.force_speed_duplex(hw);
0513 if (ret_val) {
0514 hw_dbg("Error Forcing Speed and Duplex\n");
0515 goto out;
0516 }
0517 }
0518
0519
0520
0521
0522 ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
0523 if (ret_val)
0524 goto out;
0525
0526 if (link) {
0527 hw_dbg("Valid link established!!!\n");
0528 igc_config_collision_dist(hw);
0529 ret_val = igc_config_fc_after_link_up(hw);
0530 } else {
0531 hw_dbg("Unable to establish link!!!\n");
0532 }
0533
0534 out:
0535 return ret_val;
0536 }
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547 static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
0548 {
0549 struct igc_phy_info *phy = &hw->phy;
0550 u32 i, mdic = 0;
0551 s32 ret_val = 0;
0552
0553 if (offset > MAX_PHY_REG_ADDRESS) {
0554 hw_dbg("PHY Address %d is out of range\n", offset);
0555 ret_val = -IGC_ERR_PARAM;
0556 goto out;
0557 }
0558
0559
0560
0561
0562
0563 mdic = ((offset << IGC_MDIC_REG_SHIFT) |
0564 (phy->addr << IGC_MDIC_PHY_SHIFT) |
0565 (IGC_MDIC_OP_READ));
0566
0567 wr32(IGC_MDIC, mdic);
0568
0569
0570
0571
0572
0573 for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
0574 udelay(50);
0575 mdic = rd32(IGC_MDIC);
0576 if (mdic & IGC_MDIC_READY)
0577 break;
0578 }
0579 if (!(mdic & IGC_MDIC_READY)) {
0580 hw_dbg("MDI Read did not complete\n");
0581 ret_val = -IGC_ERR_PHY;
0582 goto out;
0583 }
0584 if (mdic & IGC_MDIC_ERROR) {
0585 hw_dbg("MDI Error\n");
0586 ret_val = -IGC_ERR_PHY;
0587 goto out;
0588 }
0589 *data = (u16)mdic;
0590
0591 out:
0592 return ret_val;
0593 }
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603 static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
0604 {
0605 struct igc_phy_info *phy = &hw->phy;
0606 u32 i, mdic = 0;
0607 s32 ret_val = 0;
0608
0609 if (offset > MAX_PHY_REG_ADDRESS) {
0610 hw_dbg("PHY Address %d is out of range\n", offset);
0611 ret_val = -IGC_ERR_PARAM;
0612 goto out;
0613 }
0614
0615
0616
0617
0618
0619 mdic = (((u32)data) |
0620 (offset << IGC_MDIC_REG_SHIFT) |
0621 (phy->addr << IGC_MDIC_PHY_SHIFT) |
0622 (IGC_MDIC_OP_WRITE));
0623
0624 wr32(IGC_MDIC, mdic);
0625
0626
0627
0628
0629
0630 for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
0631 udelay(50);
0632 mdic = rd32(IGC_MDIC);
0633 if (mdic & IGC_MDIC_READY)
0634 break;
0635 }
0636 if (!(mdic & IGC_MDIC_READY)) {
0637 hw_dbg("MDI Write did not complete\n");
0638 ret_val = -IGC_ERR_PHY;
0639 goto out;
0640 }
0641 if (mdic & IGC_MDIC_ERROR) {
0642 hw_dbg("MDI Error\n");
0643 ret_val = -IGC_ERR_PHY;
0644 goto out;
0645 }
0646
0647 out:
0648 return ret_val;
0649 }
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659 static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
0660 u8 dev_addr, u16 *data, bool read)
0661 {
0662 s32 ret_val;
0663
0664 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
0665 if (ret_val)
0666 return ret_val;
0667
0668 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
0669 if (ret_val)
0670 return ret_val;
0671
0672 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
0673 dev_addr);
0674 if (ret_val)
0675 return ret_val;
0676
0677 if (read)
0678 ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
0679 else
0680 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
0681 if (ret_val)
0682 return ret_val;
0683
0684
0685 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
0686 if (ret_val)
0687 return ret_val;
0688
0689 return ret_val;
0690 }
0691
0692
0693
0694
0695
0696
0697
0698
0699 static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
0700 u8 dev_addr, u16 *data)
0701 {
0702 return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
0703 }
0704
0705
0706
0707
0708
0709
0710
0711
0712 static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
0713 u8 dev_addr, u16 data)
0714 {
0715 return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
0716 }
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727 s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
0728 {
0729 u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
0730 s32 ret_val;
0731
0732 offset = offset & GPY_REG_MASK;
0733
0734 if (!dev_addr) {
0735 ret_val = hw->phy.ops.acquire(hw);
0736 if (ret_val)
0737 return ret_val;
0738 ret_val = igc_write_phy_reg_mdic(hw, offset, data);
0739 hw->phy.ops.release(hw);
0740 } else {
0741 ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
0742 data);
0743 }
0744
0745 return ret_val;
0746 }
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758 s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
0759 {
0760 u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
0761 s32 ret_val;
0762
0763 offset = offset & GPY_REG_MASK;
0764
0765 if (!dev_addr) {
0766 ret_val = hw->phy.ops.acquire(hw);
0767 if (ret_val)
0768 return ret_val;
0769 ret_val = igc_read_phy_reg_mdic(hw, offset, data);
0770 hw->phy.ops.release(hw);
0771 } else {
0772 ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
0773 data);
0774 }
0775
0776 return ret_val;
0777 }
0778
0779
0780
0781
0782
0783 u16 igc_read_phy_fw_version(struct igc_hw *hw)
0784 {
0785 struct igc_phy_info *phy = &hw->phy;
0786 u16 gphy_version = 0;
0787 u16 ret_val;
0788
0789
0790 ret_val = phy->ops.read_reg(hw, IGC_GPHY_VERSION, &gphy_version);
0791 if (ret_val)
0792 hw_dbg("igc_phy: read wrong gphy version\n");
0793
0794 return gphy_version;
0795 }