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>
This commit is contained in:
parent
d85b9004bc
commit
308fb39a86
6 changed files with 247 additions and 14 deletions
|
@ -132,6 +132,8 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
|
|||
case E1000_DEV_ID_82580_SERDES:
|
||||
case E1000_DEV_ID_82580_SGMII:
|
||||
case E1000_DEV_ID_82580_COPPER_DUAL:
|
||||
case E1000_DEV_ID_DH89XXCC_SGMII:
|
||||
case E1000_DEV_ID_DH89XXCC_SERDES:
|
||||
mac->type = e1000_82580;
|
||||
break;
|
||||
case E1000_DEV_ID_I350_COPPER:
|
||||
|
@ -282,10 +284,18 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
|
|||
|
||||
/* Verify phy id and set remaining function pointers */
|
||||
switch (phy->id) {
|
||||
case I347AT4_E_PHY_ID:
|
||||
case M88E1112_E_PHY_ID:
|
||||
case M88E1111_I_PHY_ID:
|
||||
phy->type = e1000_phy_m88;
|
||||
phy->ops.get_phy_info = igb_get_phy_info_m88;
|
||||
phy->ops.get_cable_length = igb_get_cable_length_m88;
|
||||
|
||||
if (phy->id == I347AT4_E_PHY_ID ||
|
||||
phy->id == M88E1112_E_PHY_ID)
|
||||
phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
|
||||
else
|
||||
phy->ops.get_cable_length = igb_get_cable_length_m88;
|
||||
|
||||
phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
|
||||
break;
|
||||
case IGP03E1000_E_PHY_ID:
|
||||
|
@ -1058,7 +1068,11 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
|
|||
}
|
||||
switch (hw->phy.type) {
|
||||
case e1000_phy_m88:
|
||||
ret_val = igb_copper_link_setup_m88(hw);
|
||||
if (hw->phy.id == I347AT4_E_PHY_ID ||
|
||||
hw->phy.id == M88E1112_E_PHY_ID)
|
||||
ret_val = igb_copper_link_setup_m88_gen2(hw);
|
||||
else
|
||||
ret_val = igb_copper_link_setup_m88(hw);
|
||||
break;
|
||||
case e1000_phy_igp_3:
|
||||
ret_val = igb_copper_link_setup_igp(hw);
|
||||
|
|
|
@ -634,6 +634,8 @@
|
|||
* E = External
|
||||
*/
|
||||
#define M88E1111_I_PHY_ID 0x01410CC0
|
||||
#define M88E1112_E_PHY_ID 0x01410C90
|
||||
#define I347AT4_E_PHY_ID 0x01410DC0
|
||||
#define IGP03E1000_E_PHY_ID 0x02A80390
|
||||
#define I82580_I_PHY_ID 0x015403A0
|
||||
#define I350_I_PHY_ID 0x015403B0
|
||||
|
@ -702,6 +704,35 @@
|
|||
#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
|
||||
#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
|
||||
|
||||
/* Intel i347-AT4 Registers */
|
||||
|
||||
#define I347AT4_PCDL 0x10 /* PHY Cable Diagnostics Length */
|
||||
#define I347AT4_PCDC 0x15 /* PHY Cable Diagnostics Control */
|
||||
#define I347AT4_PAGE_SELECT 0x16
|
||||
|
||||
/* i347-AT4 Extended PHY Specific Control Register */
|
||||
|
||||
/*
|
||||
* Number of times we will attempt to autonegotiate before downshifting if we
|
||||
* are the master
|
||||
*/
|
||||
#define I347AT4_PSCR_DOWNSHIFT_ENABLE 0x0800
|
||||
#define I347AT4_PSCR_DOWNSHIFT_MASK 0x7000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_1X 0x0000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_2X 0x1000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_3X 0x2000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_4X 0x3000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_5X 0x4000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_6X 0x5000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_7X 0x6000
|
||||
#define I347AT4_PSCR_DOWNSHIFT_8X 0x7000
|
||||
|
||||
/* i347-AT4 PHY Cable Diagnostics Control */
|
||||
#define I347AT4_PCDC_CABLE_LENGTH_UNIT 0x0400 /* 0=cm 1=meters */
|
||||
|
||||
/* Marvell 1112 only registers */
|
||||
#define M88E1112_VCT_DSP_DISTANCE 0x001A
|
||||
|
||||
/* M88EC018 Rev 2 specific DownShift settings */
|
||||
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
|
||||
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
|
||||
|
|
|
@ -54,6 +54,8 @@ struct e1000_hw;
|
|||
#define E1000_DEV_ID_82580_SERDES 0x1510
|
||||
#define E1000_DEV_ID_82580_SGMII 0x1511
|
||||
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
|
||||
#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436
|
||||
#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438
|
||||
#define E1000_DEV_ID_I350_COPPER 0x1521
|
||||
#define E1000_DEV_ID_I350_FIBER 0x1522
|
||||
#define E1000_DEV_ID_I350_SERDES 0x1523
|
||||
|
|
|
@ -569,6 +569,89 @@ out:
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_copper_link_setup_m88_gen2 - Setup m88 PHY's for copper link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Sets up MDI/MDI-X and polarity for i347-AT4, m88e1322 and m88e1112 PHY's.
|
||||
* Also enables and sets the downshift parameters.
|
||||
**/
|
||||
s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_phy_info *phy = &hw->phy;
|
||||
s32 ret_val;
|
||||
u16 phy_data;
|
||||
|
||||
if (phy->reset_disable) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Enable CRS on Tx. This must be set for half-duplex operation. */
|
||||
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Options:
|
||||
* MDI/MDI-X = 0 (default)
|
||||
* 0 - Auto for all speeds
|
||||
* 1 - MDI mode
|
||||
* 2 - MDI-X mode
|
||||
* 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
|
||||
*/
|
||||
phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
|
||||
|
||||
switch (phy->mdix) {
|
||||
case 1:
|
||||
phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
|
||||
break;
|
||||
case 2:
|
||||
phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
|
||||
break;
|
||||
case 3:
|
||||
/* M88E1112 does not support this mode) */
|
||||
if (phy->id != M88E1112_E_PHY_ID) {
|
||||
phy_data |= M88E1000_PSCR_AUTO_X_1000T;
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
default:
|
||||
phy_data |= M88E1000_PSCR_AUTO_X_MODE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Options:
|
||||
* disable_polarity_correction = 0 (default)
|
||||
* Automatic Correction for Reversed Cable Polarity
|
||||
* 0 - Disabled
|
||||
* 1 - Enabled
|
||||
*/
|
||||
phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
|
||||
if (phy->disable_polarity_correction == 1)
|
||||
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
|
||||
|
||||
/* Enable downshift and setting it to X6 */
|
||||
phy_data &= ~I347AT4_PSCR_DOWNSHIFT_MASK;
|
||||
phy_data |= I347AT4_PSCR_DOWNSHIFT_6X;
|
||||
phy_data |= I347AT4_PSCR_DOWNSHIFT_ENABLE;
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Commit the changes. */
|
||||
ret_val = igb_phy_sw_reset(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error committing the PHY changes\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_copper_link_setup_igp - Setup igp PHY's for copper link
|
||||
* @hw: pointer to the HW structure
|
||||
|
@ -1124,18 +1207,25 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
|
|||
goto out;
|
||||
|
||||
if (!link) {
|
||||
/*
|
||||
* We didn't get link.
|
||||
* Reset the DSP and cross our fingers.
|
||||
*/
|
||||
ret_val = phy->ops.write_reg(hw,
|
||||
M88E1000_PHY_PAGE_SELECT,
|
||||
0x001d);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = igb_phy_reset_dsp(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
if (hw->phy.type != e1000_phy_m88 ||
|
||||
hw->phy.id == I347AT4_E_PHY_ID ||
|
||||
hw->phy.id == M88E1112_E_PHY_ID) {
|
||||
hw_dbg("Link taking longer than expected.\n");
|
||||
} else {
|
||||
|
||||
/*
|
||||
* We didn't get link.
|
||||
* Reset the DSP and cross our fingers.
|
||||
*/
|
||||
ret_val = phy->ops.write_reg(hw,
|
||||
M88E1000_PHY_PAGE_SELECT,
|
||||
0x001d);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = igb_phy_reset_dsp(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try once more */
|
||||
|
@ -1145,6 +1235,11 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (hw->phy.type != e1000_phy_m88 ||
|
||||
hw->phy.id == I347AT4_E_PHY_ID ||
|
||||
hw->phy.id == M88E1112_E_PHY_ID)
|
||||
goto out;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
@ -1557,6 +1652,93 @@ out:
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_phy_info *phy = &hw->phy;
|
||||
s32 ret_val;
|
||||
u16 phy_data, phy_data2, index, default_page, is_cm;
|
||||
|
||||
switch (hw->phy.id) {
|
||||
case I347AT4_E_PHY_ID:
|
||||
/* Remember the original page select and set it to 7 */
|
||||
ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
|
||||
&default_page);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Get cable length from PHY Cable Diagnostics Control Reg */
|
||||
ret_val = phy->ops.read_reg(hw, (I347AT4_PCDL + phy->addr),
|
||||
&phy_data);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Check if the unit of cable length is meters or cm */
|
||||
ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
is_cm = !(phy_data & I347AT4_PCDC_CABLE_LENGTH_UNIT);
|
||||
|
||||
/* Populate the phy structure with cable length in meters */
|
||||
phy->min_cable_length = phy_data / (is_cm ? 100 : 1);
|
||||
phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
|
||||
phy->cable_length = phy_data / (is_cm ? 100 : 1);
|
||||
|
||||
/* Reset the page selec to its original value */
|
||||
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
|
||||
default_page);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
break;
|
||||
case M88E1112_E_PHY_ID:
|
||||
/* Remember the original page select and set it to 5 */
|
||||
ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
|
||||
&default_page);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x05);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, M88E1112_VCT_DSP_DISTANCE,
|
||||
&phy_data);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
|
||||
M88E1000_PSSR_CABLE_LENGTH_SHIFT;
|
||||
if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
|
||||
ret_val = -E1000_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy->min_cable_length = e1000_m88_cable_length_table[index];
|
||||
phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
|
||||
|
||||
phy->cable_length = (phy->min_cable_length +
|
||||
phy->max_cable_length) / 2;
|
||||
|
||||
/* Reset the page select to its original value */
|
||||
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
|
||||
default_page);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
break;
|
||||
default:
|
||||
ret_val = -E1000_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
|
@ -45,9 +45,11 @@ s32 igb_check_downshift(struct e1000_hw *hw);
|
|||
s32 igb_check_reset_block(struct e1000_hw *hw);
|
||||
s32 igb_copper_link_setup_igp(struct e1000_hw *hw);
|
||||
s32 igb_copper_link_setup_m88(struct e1000_hw *hw);
|
||||
s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw);
|
||||
s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
|
||||
s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_m88(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_igp_2(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_id(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_info_igp(struct e1000_hw *hw);
|
||||
|
|
|
@ -71,6 +71,8 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
|
|||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 },
|
||||
|
|
Loading…
Reference in a new issue