diff options
Diffstat (limited to 'drivers/net/igb/e1000_phy.c')
-rw-r--r-- | drivers/net/igb/e1000_phy.c | 219 |
1 files changed, 201 insertions, 18 deletions
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index cf1f32300923..d639706eb3f6 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c | |||
@@ -570,6 +570,89 @@ out: | |||
570 | } | 570 | } |
571 | 571 | ||
572 | /** | 572 | /** |
573 | * igb_copper_link_setup_m88_gen2 - Setup m88 PHY's for copper link | ||
574 | * @hw: pointer to the HW structure | ||
575 | * | ||
576 | * Sets up MDI/MDI-X and polarity for i347-AT4, m88e1322 and m88e1112 PHY's. | ||
577 | * Also enables and sets the downshift parameters. | ||
578 | **/ | ||
579 | s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw) | ||
580 | { | ||
581 | struct e1000_phy_info *phy = &hw->phy; | ||
582 | s32 ret_val; | ||
583 | u16 phy_data; | ||
584 | |||
585 | if (phy->reset_disable) { | ||
586 | ret_val = 0; | ||
587 | goto out; | ||
588 | } | ||
589 | |||
590 | /* Enable CRS on Tx. This must be set for half-duplex operation. */ | ||
591 | ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); | ||
592 | if (ret_val) | ||
593 | goto out; | ||
594 | |||
595 | /* | ||
596 | * Options: | ||
597 | * MDI/MDI-X = 0 (default) | ||
598 | * 0 - Auto for all speeds | ||
599 | * 1 - MDI mode | ||
600 | * 2 - MDI-X mode | ||
601 | * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) | ||
602 | */ | ||
603 | phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; | ||
604 | |||
605 | switch (phy->mdix) { | ||
606 | case 1: | ||
607 | phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; | ||
608 | break; | ||
609 | case 2: | ||
610 | phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; | ||
611 | break; | ||
612 | case 3: | ||
613 | /* M88E1112 does not support this mode) */ | ||
614 | if (phy->id != M88E1112_E_PHY_ID) { | ||
615 | phy_data |= M88E1000_PSCR_AUTO_X_1000T; | ||
616 | break; | ||
617 | } | ||
618 | case 0: | ||
619 | default: | ||
620 | phy_data |= M88E1000_PSCR_AUTO_X_MODE; | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * Options: | ||
626 | * disable_polarity_correction = 0 (default) | ||
627 | * Automatic Correction for Reversed Cable Polarity | ||
628 | * 0 - Disabled | ||
629 | * 1 - Enabled | ||
630 | */ | ||
631 | phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; | ||
632 | if (phy->disable_polarity_correction == 1) | ||
633 | phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; | ||
634 | |||
635 | /* Enable downshift and setting it to X6 */ | ||
636 | phy_data &= ~I347AT4_PSCR_DOWNSHIFT_MASK; | ||
637 | phy_data |= I347AT4_PSCR_DOWNSHIFT_6X; | ||
638 | phy_data |= I347AT4_PSCR_DOWNSHIFT_ENABLE; | ||
639 | |||
640 | ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); | ||
641 | if (ret_val) | ||
642 | goto out; | ||
643 | |||
644 | /* Commit the changes. */ | ||
645 | ret_val = igb_phy_sw_reset(hw); | ||
646 | if (ret_val) { | ||
647 | hw_dbg("Error committing the PHY changes\n"); | ||
648 | goto out; | ||
649 | } | ||
650 | |||
651 | out: | ||
652 | return ret_val; | ||
653 | } | ||
654 | |||
655 | /** | ||
573 | * igb_copper_link_setup_igp - Setup igp PHY's for copper link | 656 | * igb_copper_link_setup_igp - Setup igp PHY's for copper link |
574 | * @hw: pointer to the HW structure | 657 | * @hw: pointer to the HW structure |
575 | * | 658 | * |
@@ -1124,18 +1207,25 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) | |||
1124 | goto out; | 1207 | goto out; |
1125 | 1208 | ||
1126 | if (!link) { | 1209 | if (!link) { |
1127 | /* | 1210 | if (hw->phy.type != e1000_phy_m88 || |
1128 | * We didn't get link. | 1211 | hw->phy.id == I347AT4_E_PHY_ID || |
1129 | * Reset the DSP and cross our fingers. | 1212 | hw->phy.id == M88E1112_E_PHY_ID) { |
1130 | */ | 1213 | hw_dbg("Link taking longer than expected.\n"); |
1131 | ret_val = phy->ops.write_reg(hw, | 1214 | } else { |
1132 | M88E1000_PHY_PAGE_SELECT, | 1215 | |
1133 | 0x001d); | 1216 | /* |
1134 | if (ret_val) | 1217 | * We didn't get link. |
1135 | goto out; | 1218 | * Reset the DSP and cross our fingers. |
1136 | ret_val = igb_phy_reset_dsp(hw); | 1219 | */ |
1137 | if (ret_val) | 1220 | ret_val = phy->ops.write_reg(hw, |
1138 | goto out; | 1221 | M88E1000_PHY_PAGE_SELECT, |
1222 | 0x001d); | ||
1223 | if (ret_val) | ||
1224 | goto out; | ||
1225 | ret_val = igb_phy_reset_dsp(hw); | ||
1226 | if (ret_val) | ||
1227 | goto out; | ||
1228 | } | ||
1139 | } | 1229 | } |
1140 | 1230 | ||
1141 | /* Try once more */ | 1231 | /* Try once more */ |
@@ -1145,6 +1235,11 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) | |||
1145 | goto out; | 1235 | goto out; |
1146 | } | 1236 | } |
1147 | 1237 | ||
1238 | if (hw->phy.type != e1000_phy_m88 || | ||
1239 | hw->phy.id == I347AT4_E_PHY_ID || | ||
1240 | hw->phy.id == M88E1112_E_PHY_ID) | ||
1241 | goto out; | ||
1242 | |||
1148 | ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); | 1243 | ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); |
1149 | if (ret_val) | 1244 | if (ret_val) |
1150 | goto out; | 1245 | goto out; |
@@ -1326,7 +1421,7 @@ out: | |||
1326 | } | 1421 | } |
1327 | 1422 | ||
1328 | /** | 1423 | /** |
1329 | * igb_check_downshift - Checks whether a downshift in speed occured | 1424 | * igb_check_downshift - Checks whether a downshift in speed occurred |
1330 | * @hw: pointer to the HW structure | 1425 | * @hw: pointer to the HW structure |
1331 | * | 1426 | * |
1332 | * Success returns 0, Failure returns 1 | 1427 | * Success returns 0, Failure returns 1 |
@@ -1557,6 +1652,93 @@ out: | |||
1557 | return ret_val; | 1652 | return ret_val; |
1558 | } | 1653 | } |
1559 | 1654 | ||
1655 | s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) | ||
1656 | { | ||
1657 | struct e1000_phy_info *phy = &hw->phy; | ||
1658 | s32 ret_val; | ||
1659 | u16 phy_data, phy_data2, index, default_page, is_cm; | ||
1660 | |||
1661 | switch (hw->phy.id) { | ||
1662 | case I347AT4_E_PHY_ID: | ||
1663 | /* Remember the original page select and set it to 7 */ | ||
1664 | ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, | ||
1665 | &default_page); | ||
1666 | if (ret_val) | ||
1667 | goto out; | ||
1668 | |||
1669 | ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07); | ||
1670 | if (ret_val) | ||
1671 | goto out; | ||
1672 | |||
1673 | /* Get cable length from PHY Cable Diagnostics Control Reg */ | ||
1674 | ret_val = phy->ops.read_reg(hw, (I347AT4_PCDL + phy->addr), | ||
1675 | &phy_data); | ||
1676 | if (ret_val) | ||
1677 | goto out; | ||
1678 | |||
1679 | /* Check if the unit of cable length is meters or cm */ | ||
1680 | ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2); | ||
1681 | if (ret_val) | ||
1682 | goto out; | ||
1683 | |||
1684 | is_cm = !(phy_data & I347AT4_PCDC_CABLE_LENGTH_UNIT); | ||
1685 | |||
1686 | /* Populate the phy structure with cable length in meters */ | ||
1687 | phy->min_cable_length = phy_data / (is_cm ? 100 : 1); | ||
1688 | phy->max_cable_length = phy_data / (is_cm ? 100 : 1); | ||
1689 | phy->cable_length = phy_data / (is_cm ? 100 : 1); | ||
1690 | |||
1691 | /* Reset the page selec to its original value */ | ||
1692 | ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, | ||
1693 | default_page); | ||
1694 | if (ret_val) | ||
1695 | goto out; | ||
1696 | break; | ||
1697 | case M88E1112_E_PHY_ID: | ||
1698 | /* Remember the original page select and set it to 5 */ | ||
1699 | ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, | ||
1700 | &default_page); | ||
1701 | if (ret_val) | ||
1702 | goto out; | ||
1703 | |||
1704 | ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x05); | ||
1705 | if (ret_val) | ||
1706 | goto out; | ||
1707 | |||
1708 | ret_val = phy->ops.read_reg(hw, M88E1112_VCT_DSP_DISTANCE, | ||
1709 | &phy_data); | ||
1710 | if (ret_val) | ||
1711 | goto out; | ||
1712 | |||
1713 | index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> | ||
1714 | M88E1000_PSSR_CABLE_LENGTH_SHIFT; | ||
1715 | if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { | ||
1716 | ret_val = -E1000_ERR_PHY; | ||
1717 | goto out; | ||
1718 | } | ||
1719 | |||
1720 | phy->min_cable_length = e1000_m88_cable_length_table[index]; | ||
1721 | phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; | ||
1722 | |||
1723 | phy->cable_length = (phy->min_cable_length + | ||
1724 | phy->max_cable_length) / 2; | ||
1725 | |||
1726 | /* Reset the page select to its original value */ | ||
1727 | ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, | ||
1728 | default_page); | ||
1729 | if (ret_val) | ||
1730 | goto out; | ||
1731 | |||
1732 | break; | ||
1733 | default: | ||
1734 | ret_val = -E1000_ERR_PHY; | ||
1735 | goto out; | ||
1736 | } | ||
1737 | |||
1738 | out: | ||
1739 | return ret_val; | ||
1740 | } | ||
1741 | |||
1560 | /** | 1742 | /** |
1561 | * igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY | 1743 | * igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY |
1562 | * @hw: pointer to the HW structure | 1744 | * @hw: pointer to the HW structure |
@@ -1575,11 +1757,12 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) | |||
1575 | u16 phy_data, i, agc_value = 0; | 1757 | u16 phy_data, i, agc_value = 0; |
1576 | u16 cur_agc_index, max_agc_index = 0; | 1758 | u16 cur_agc_index, max_agc_index = 0; |
1577 | u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; | 1759 | u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; |
1578 | u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = | 1760 | static const u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = { |
1579 | {IGP02E1000_PHY_AGC_A, | 1761 | IGP02E1000_PHY_AGC_A, |
1580 | IGP02E1000_PHY_AGC_B, | 1762 | IGP02E1000_PHY_AGC_B, |
1581 | IGP02E1000_PHY_AGC_C, | 1763 | IGP02E1000_PHY_AGC_C, |
1582 | IGP02E1000_PHY_AGC_D}; | 1764 | IGP02E1000_PHY_AGC_D |
1765 | }; | ||
1583 | 1766 | ||
1584 | /* Read the AGC registers for all channels */ | 1767 | /* Read the AGC registers for all channels */ |
1585 | for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { | 1768 | for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { |