Support the BCM54616 and BCM5461S.

This commit is contained in:
Jeffrey Townsend
2016-09-15 20:34:56 +00:00
parent 793b7c1fc3
commit f32316c63c
2 changed files with 283 additions and 0 deletions

View File

@@ -0,0 +1,280 @@
+ 0x75diff -urpN a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c 2016-03-02 10:31:21.000000000 +0000
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c 2016-09-15 19:55:02.680725611 +0000
@@ -179,8 +179,11 @@ static s32 igb_init_phy_params_82575(str
ctrl_ext = rd32(E1000_CTRL_EXT);
if (igb_sgmii_active_82575(hw)) {
- phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
- ctrl_ext |= E1000_CTRL_I2C_ENA;
+ if(phy->type == e1000_phy_bcm5461s)
+ phy->ops.reset = igb_phy_hw_reset;
+ else
+ phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
} else {
phy->ops.reset = igb_phy_hw_reset;
ctrl_ext &= ~E1000_CTRL_I2C_ENA;
@@ -286,6 +289,19 @@ static s32 igb_init_phy_params_82575(str
phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
break;
+
+ case BCM5461S_PHY_ID:
+ phy->type = e1000_phy_bcm5461s;
+ phy->ops.check_polarity = NULL;
+ phy->ops.get_phy_info = igb_get_phy_info_5461s;
+ phy->ops.get_cable_length = NULL;
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;
+ break;
+
+ case BCM54616_E_PHY_ID:
+ phy->type = e1000_phy_bcm54616;
+ break;
+
default:
ret_val = -E1000_ERR_PHY;
goto out;
@@ -827,9 +843,9 @@ static s32 igb_get_phy_id_82575(struct e
break;
case e1000_82580:
case e1000_i350:
- case e1000_i354:
case e1000_i210:
case e1000_i211:
+ case e1000_i354:
mdic = rd32(E1000_MDICNFG);
mdic &= E1000_MDICNFG_PHY_MASK;
phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
@@ -840,6 +856,17 @@ static s32 igb_get_phy_id_82575(struct e
break;
}
ret_val = igb_get_phy_id(hw);
+
+ if (ret_val && hw->mac.type == e1000_i354) {
+ /* we do a special check for bcm5461s phy by setting
+ * the phy->addr to 5 and doing the phy check again. This
+ * call will succeed and retrieve a valid phy id if we have
+ * the bcm5461s phy
+ */
+ phy->addr = 5;
+ phy->type = e1000_phy_bcm5461s;
+ ret_val = igb_get_phy_id(hw);
+ }
goto out;
}
@@ -1220,6 +1247,9 @@ static s32 igb_get_cfg_done_82575(struct
(hw->phy.type == e1000_phy_igp_3))
igb_phy_init_script_igp3(hw);
+ if (hw->phy.type == e1000_phy_bcm5461s)
+ igb_phy_init_script_5461s(hw);
+
return 0;
}
@@ -1552,6 +1582,7 @@ static s32 igb_setup_copper_link_82575(s
case e1000_i350:
case e1000_i210:
case e1000_i211:
+ case e1000_i354:
phpm_reg = rd32(E1000_82580_PHY_POWER_MGMT);
phpm_reg &= ~E1000_82580_PM_GO_LINKD;
wr32(E1000_82580_PHY_POWER_MGMT, phpm_reg);
@@ -1595,6 +1626,10 @@ static s32 igb_setup_copper_link_82575(s
case e1000_phy_82580:
ret_val = igb_copper_link_setup_82580(hw);
break;
+ case e1000_phy_bcm54616:
+ break;
+ case e1000_phy_bcm5461s:
+ break;
default:
ret_val = -E1000_ERR_PHY;
break;
diff -urpN a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h 2016-03-02 10:31:21.000000000 +0000
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h 2016-09-15 19:55:27.068726140 +0000
@@ -860,6 +860,8 @@
#define M88_VENDOR 0x0141
#define I210_I_PHY_ID 0x01410C00
#define M88E1543_E_PHY_ID 0x01410EA0
+#define BCM54616_E_PHY_ID 0x3625D10
+#define BCM5461S_PHY_ID 0x002060C0
/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
diff -urpN a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h 2016-03-02 10:31:21.000000000 +0000
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h 2016-09-15 19:55:44.584726520 +0000
@@ -128,6 +128,8 @@ enum e1000_phy_type {
e1000_phy_ife,
e1000_phy_82580,
e1000_phy_i210,
+ e1000_phy_bcm54616,
+ e1000_phy_bcm5461s,
};
enum e1000_bus_type {
diff -urpN a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c 2016-03-02 10:31:21.000000000 +0000
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c 2016-09-15 20:07:34.964741935 +0000
@@ -148,6 +148,14 @@ s32 igb_read_phy_reg_mdic(struct e1000_h
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
+
+ if (phy->type == e1000_phy_bcm5461s) {
+ mdic = rd32(E1000_MDICNFG);
+ mdic &= ~E1000_MDICNFG_PHY_MASK;
+ mdic |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+ wr32(E1000_MDICNFG, mdic);
+ }
+
mdic = ((offset << E1000_MDIC_REG_SHIFT) |
(phy->addr << E1000_MDIC_PHY_SHIFT) |
(E1000_MDIC_OP_READ));
@@ -204,6 +212,14 @@ s32 igb_write_phy_reg_mdic(struct e1000_
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
+
+ if (phy->type == e1000_phy_bcm5461s) {
+ mdic = rd32(E1000_MDICNFG);
+ mdic &= ~E1000_MDICNFG_PHY_MASK;
+ mdic |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+ wr32(E1000_MDICNFG, mdic);
+ }
+
mdic = (((u32)data) |
(offset << E1000_MDIC_REG_SHIFT) |
(phy->addr << E1000_MDIC_PHY_SHIFT) |
@@ -1115,11 +1131,13 @@ s32 igb_setup_copper_link(struct e1000_h
* depending on user settings.
*/
hw_dbg("Forcing Speed and Duplex\n");
- ret_val = hw->phy.ops.force_speed_duplex(hw);
- if (ret_val) {
+ if(hw->phy.ops.force_speed_duplex) {
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
hw_dbg("Error Forcing Speed and Duplex\n");
goto out;
- }
+ }
+ }
}
/* Check link status. Wait up to 100 microseconds for link to become
@@ -2509,3 +2527,67 @@ static s32 igb_set_master_slave_mode(str
return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data);
}
+
+/**
+ * igb_phy_init_script_5461s - Inits the BCM5461S PHY
+ * @hw: pointer to the HW structure
+ *
+ * Initializes a Broadcom Gigabit PHY.
+ **/
+s32 igb_phy_init_script_5461s(struct e1000_hw *hw)
+{
+ u16 mii_reg_led = 0;
+
+ /* 1. Speed LED (Set the Link LED mode), Shadow 00010, 0x1C.bit2=1 */
+ hw->phy.ops.write_reg(hw, 0x1C, 0x0800);
+ hw->phy.ops.read_reg(hw, 0x1C, &mii_reg_led);
+ mii_reg_led |= 0x0004;
+ hw->phy.ops.write_reg(hw, 0x1C, mii_reg_led | 0x8000);
+
+ /* 2. Active LED (Set the Link LED mode), Shadow 01001, 0x1C.bit4=1, 0x10.bit5=0 */
+ hw->phy.ops.write_reg(hw, 0x1C, 0x2400);
+ hw->phy.ops.read_reg(hw, 0x1C, &mii_reg_led);
+ mii_reg_led |= 0x0010;
+ hw->phy.ops.write_reg(hw, 0x1C, mii_reg_led | 0x8000);
+ hw->phy.ops.read_reg(hw, 0x10, &mii_reg_led);
+ mii_reg_led &= 0xffdf;
+ hw->phy.ops.write_reg(hw, 0x10, mii_reg_led);
+
+ return 0;
+}
+
+
+/**
+ * igb_get_phy_info_5461s - Retrieve 5461s PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_5461s(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ bool link;
+
+ ret_val = igb_phy_has_link(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ phy->polarity_correction = true;
+
+ phy->is_mdix = true;
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_ok;
+ phy->remote_rx = e1000_1000t_rx_status_ok;
+
+out:
+ return ret_val;
+}
diff -urpN a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h 2016-03-02 10:31:21.000000000 +0000
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h 2016-09-15 19:41:43.584708271 +0000
@@ -61,6 +61,8 @@ s32 igb_phy_has_link(struct e1000_hw *h
void igb_power_up_phy_copper(struct e1000_hw *hw);
void igb_power_down_phy_copper(struct e1000_hw *hw);
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
+s32 igb_phy_init_script_5461s(struct e1000_hw *hw);
+s32 igb_get_phy_info_5461s(struct e1000_hw *hw);
s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
diff -urpN a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
--- a/drivers/net/ethernet/intel/igb/igb_main.c 2016-03-02 10:31:21.000000000 +0000
+++ b/drivers/net/ethernet/intel/igb/igb_main.c 2016-09-15 19:56:53.276728011 +0000
@@ -108,6 +108,7 @@ static const struct pci_device_id igb_pc
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII), board_82575 },
/* required last entry */
{0, }
};
@@ -7198,11 +7199,19 @@ static int igb_mii_ioctl(struct net_devi
data->phy_id = adapter->hw.phy.addr;
break;
case SIOCGMIIREG:
+ adapter->hw.phy.addr = data->phy_id;
if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
&data->val_out))
return -EIO;
break;
case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ adapter->hw.phy.addr = data->phy_id;
+ if (igb_write_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+ data->val_in))
+ return -EIO;
+ break;
default:
return -EOPNOTSUPP;
}

View File

@@ -11,3 +11,6 @@ driver-hwmon-pmbus-add-dps460-support.patch
driver-hwmon-pmbus-ucd9200-mlnx.patch
driver-arista-piix4-mux-patch.patch
3.16-fs-overlayfs.patch
driver-support-intel-igb-bcm5461X-phy.patch