aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/igb
diff options
context:
space:
mode:
authorJoseph Gasparakis <joseph.gasparakis@intel.com>2010-09-22 13:56:44 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-23 00:20:04 -0400
commit308fb39a860c816be8741fe783ae7c64e9c1af5d (patch)
tree8fabed4b3372c49b4d83dc1d0b72d4abf60f139e /drivers/net/igb
parentd85b9004bc2047d79248b167cc151ff9a4b509c3 (diff)
igb: Add support for DH89xxCC
This patch adds support for the Intel(r) DH89xxCC series. The new device will be using Intel(r) i347-AT4 and Marvell(r) M88E1322 and M88E1112 PHYs. Support for these devices has also been added here. Signed-off-by: Joseph Gasparakis <joseph.gasparakis@intel.com> Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/igb')
-rw-r--r--drivers/net/igb/e1000_82575.c18
-rw-r--r--drivers/net/igb/e1000_defines.h31
-rw-r--r--drivers/net/igb/e1000_hw.h2
-rw-r--r--drivers/net/igb/e1000_phy.c206
-rw-r--r--drivers/net/igb/e1000_phy.h2
-rw-r--r--drivers/net/igb/igb_main.c2
6 files changed, 247 insertions, 14 deletions
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 187622f1c816..bc183f5487cb 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -132,6 +132,8 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
132 case E1000_DEV_ID_82580_SERDES: 132 case E1000_DEV_ID_82580_SERDES:
133 case E1000_DEV_ID_82580_SGMII: 133 case E1000_DEV_ID_82580_SGMII:
134 case E1000_DEV_ID_82580_COPPER_DUAL: 134 case E1000_DEV_ID_82580_COPPER_DUAL:
135 case E1000_DEV_ID_DH89XXCC_SGMII:
136 case E1000_DEV_ID_DH89XXCC_SERDES:
135 mac->type = e1000_82580; 137 mac->type = e1000_82580;
136 break; 138 break;
137 case E1000_DEV_ID_I350_COPPER: 139 case E1000_DEV_ID_I350_COPPER:
@@ -282,10 +284,18 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
282 284
283 /* Verify phy id and set remaining function pointers */ 285 /* Verify phy id and set remaining function pointers */
284 switch (phy->id) { 286 switch (phy->id) {
287 case I347AT4_E_PHY_ID:
288 case M88E1112_E_PHY_ID:
285 case M88E1111_I_PHY_ID: 289 case M88E1111_I_PHY_ID:
286 phy->type = e1000_phy_m88; 290 phy->type = e1000_phy_m88;
287 phy->ops.get_phy_info = igb_get_phy_info_m88; 291 phy->ops.get_phy_info = igb_get_phy_info_m88;
288 phy->ops.get_cable_length = igb_get_cable_length_m88; 292
293 if (phy->id == I347AT4_E_PHY_ID ||
294 phy->id == M88E1112_E_PHY_ID)
295 phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
296 else
297 phy->ops.get_cable_length = igb_get_cable_length_m88;
298
289 phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; 299 phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
290 break; 300 break;
291 case IGP03E1000_E_PHY_ID: 301 case IGP03E1000_E_PHY_ID:
@@ -1058,7 +1068,11 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
1058 } 1068 }
1059 switch (hw->phy.type) { 1069 switch (hw->phy.type) {
1060 case e1000_phy_m88: 1070 case e1000_phy_m88:
1061 ret_val = igb_copper_link_setup_m88(hw); 1071 if (hw->phy.id == I347AT4_E_PHY_ID ||
1072 hw->phy.id == M88E1112_E_PHY_ID)
1073 ret_val = igb_copper_link_setup_m88_gen2(hw);
1074 else
1075 ret_val = igb_copper_link_setup_m88(hw);
1062 break; 1076 break;
1063 case e1000_phy_igp_3: 1077 case e1000_phy_igp_3:
1064 ret_val = igb_copper_link_setup_igp(hw); 1078 ret_val = igb_copper_link_setup_igp(hw);
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index bbd2ec308eb0..62222796a8b3 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -634,6 +634,8 @@
634 * E = External 634 * E = External
635 */ 635 */
636#define M88E1111_I_PHY_ID 0x01410CC0 636#define M88E1111_I_PHY_ID 0x01410CC0
637#define M88E1112_E_PHY_ID 0x01410C90
638#define I347AT4_E_PHY_ID 0x01410DC0
637#define IGP03E1000_E_PHY_ID 0x02A80390 639#define IGP03E1000_E_PHY_ID 0x02A80390
638#define I82580_I_PHY_ID 0x015403A0 640#define I82580_I_PHY_ID 0x015403A0
639#define I350_I_PHY_ID 0x015403B0 641#define I350_I_PHY_ID 0x015403B0
@@ -702,6 +704,35 @@
702#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 704#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
703#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ 705#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
704 706
707/* Intel i347-AT4 Registers */
708
709#define I347AT4_PCDL 0x10 /* PHY Cable Diagnostics Length */
710#define I347AT4_PCDC 0x15 /* PHY Cable Diagnostics Control */
711#define I347AT4_PAGE_SELECT 0x16
712
713/* i347-AT4 Extended PHY Specific Control Register */
714
715/*
716 * Number of times we will attempt to autonegotiate before downshifting if we
717 * are the master
718 */
719#define I347AT4_PSCR_DOWNSHIFT_ENABLE 0x0800
720#define I347AT4_PSCR_DOWNSHIFT_MASK 0x7000
721#define I347AT4_PSCR_DOWNSHIFT_1X 0x0000
722#define I347AT4_PSCR_DOWNSHIFT_2X 0x1000
723#define I347AT4_PSCR_DOWNSHIFT_3X 0x2000
724#define I347AT4_PSCR_DOWNSHIFT_4X 0x3000
725#define I347AT4_PSCR_DOWNSHIFT_5X 0x4000
726#define I347AT4_PSCR_DOWNSHIFT_6X 0x5000
727#define I347AT4_PSCR_DOWNSHIFT_7X 0x6000
728#define I347AT4_PSCR_DOWNSHIFT_8X 0x7000
729
730/* i347-AT4 PHY Cable Diagnostics Control */
731#define I347AT4_PCDC_CABLE_LENGTH_UNIT 0x0400 /* 0=cm 1=meters */
732
733/* Marvell 1112 only registers */
734#define M88E1112_VCT_DSP_DISTANCE 0x001A
735
705/* M88EC018 Rev 2 specific DownShift settings */ 736/* M88EC018 Rev 2 specific DownShift settings */
706#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 737#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
707#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 738#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index cb8db78b1a05..c0b017f8d782 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -54,6 +54,8 @@ struct e1000_hw;
54#define E1000_DEV_ID_82580_SERDES 0x1510 54#define E1000_DEV_ID_82580_SERDES 0x1510
55#define E1000_DEV_ID_82580_SGMII 0x1511 55#define E1000_DEV_ID_82580_SGMII 0x1511
56#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 56#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
57#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436
58#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438
57#define E1000_DEV_ID_I350_COPPER 0x1521 59#define E1000_DEV_ID_I350_COPPER 0x1521
58#define E1000_DEV_ID_I350_FIBER 0x1522 60#define E1000_DEV_ID_I350_FIBER 0x1522
59#define E1000_DEV_ID_I350_SERDES 0x1523 61#define E1000_DEV_ID_I350_SERDES 0x1523
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index cf1f32300923..ddd036a78999 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 **/
579s32 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
651out:
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;
@@ -1557,6 +1652,93 @@ out:
1557 return ret_val; 1652 return ret_val;
1558} 1653}
1559 1654
1655s32 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
1738out:
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
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
index 565a6dbb3714..2cc117705a31 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/igb/e1000_phy.h
@@ -45,9 +45,11 @@ s32 igb_check_downshift(struct e1000_hw *hw);
45s32 igb_check_reset_block(struct e1000_hw *hw); 45s32 igb_check_reset_block(struct e1000_hw *hw);
46s32 igb_copper_link_setup_igp(struct e1000_hw *hw); 46s32 igb_copper_link_setup_igp(struct e1000_hw *hw);
47s32 igb_copper_link_setup_m88(struct e1000_hw *hw); 47s32 igb_copper_link_setup_m88(struct e1000_hw *hw);
48s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw);
48s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw); 49s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
49s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw); 50s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
50s32 igb_get_cable_length_m88(struct e1000_hw *hw); 51s32 igb_get_cable_length_m88(struct e1000_hw *hw);
52s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw);
51s32 igb_get_cable_length_igp_2(struct e1000_hw *hw); 53s32 igb_get_cable_length_igp_2(struct e1000_hw *hw);
52s32 igb_get_phy_id(struct e1000_hw *hw); 54s32 igb_get_phy_id(struct e1000_hw *hw);
53s32 igb_get_phy_info_igp(struct e1000_hw *hw); 55s32 igb_get_phy_info_igp(struct e1000_hw *hw);
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index fd922e7db1d5..61892b80d7ad 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -71,6 +71,8 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
71 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 }, 71 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
72 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 }, 72 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
73 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 }, 73 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
74 { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 },
75 { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 },
74 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 }, 76 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
75 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 }, 77 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
76 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 }, 78 { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 },