diff -Nu a/drivers/net/ethernet/intel/igb/bcm_phy.c b/drivers/net/ethernet/intel/igb/bcm_phy.c
--- a/drivers/net/ethernet/intel/igb/bcm_phy.c	1970-01-01 08:00:00.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/bcm_phy.c	2017-06-20 17:00:46.000000000 +0800
@@ -0,0 +1,206 @@
+#include "e1000_hw.h"
+#include "linux/brcmphy.h"
+
+/*
+ * 1000Base-T Control Register
+ */
+#define MII_BCM54XX_AUX_CTL_ENCODE(val) (((val & 0x7) << 12)|(val & 0x7))
+
+/*
+ * MII Link Advertisment
+ */
+#define MII_ANA_ASF             (1 << 0) /* Advertise Selector Field */
+#define MII_ANA_HD_10           (1 << 5) /* Half duplex 10Mb/s supported */
+#define MII_ANA_FD_10           (1 << 6) /* Full duplex 10Mb/s supported */
+#define MII_ANA_HD_100          (1 << 7) /* Half duplex 100Mb/s supported */
+#define MII_ANA_FD_100          (1 << 8) /* Full duplex 100Mb/s supported */
+#define MII_ANA_T4              (1 << 9) /* T4 */
+#define MII_ANA_PAUSE           (1 << 10)/* Pause supported */
+#define MII_ANA_ASYM_PAUSE      (1 << 11)/* Asymmetric pause supported */
+#define MII_ANA_RF              (1 << 13)/* Remote fault */
+#define MII_ANA_NP              (1 << 15)/* Next Page */
+
+#define MII_ANA_ASF_802_3       (1)      /* 802.3 PHY */
+
+/*
+ * BCM54XX: Shadow registers
+ * Shadow values go into bits [14:10] of register 0x1c to select a shadow
+ * register to access.
+ */
+#define BCM54XX_SHD_AUTODETECT  0x1e    /* 11110: Auto detect Regisrer */
+#define BCM54XX_SHD_MODE        0x1f    /* 11111: Mode Control Register */
+#define BCM54XX_SHD_MODE_SER    1<<6
+
+/*
+ * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
+ * 0x1c shadow registers.
+ */
+
+int bcmphy_write(struct e1000_hw *hw,u32 reg, u16 regval)
+{
+    u32 ret;
+    struct e1000_phy_info *phy = &hw->phy;
+
+    ret = phy->ops.write_reg(hw,reg, regval);
+    return ret;
+}
+
+u16 bcmphy_read(struct e1000_hw *hw, u32 reg)
+{
+    u16 val;
+    struct e1000_phy_info *phy = &hw->phy;
+
+    phy->ops.read_reg(hw,reg, &val);
+    return val;
+}
+
+static int bcm54xx_shadow_read(struct e1000_hw *hw, u16 shadow)
+{
+    bcmphy_write(hw, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+    return MII_BCM54XX_SHD_DATA(bcmphy_read(hw, MII_BCM54XX_SHD));
+}
+
+static int bcm54xx_shadow_write(struct e1000_hw *hw, u16 shadow, u16 val)
+{
+    return bcmphy_write(hw, MII_BCM54XX_SHD,
+                            MII_BCM54XX_SHD_WRITE |
+                            MII_BCM54XX_SHD_VAL(shadow) |
+                            MII_BCM54XX_SHD_DATA(val));
+}
+
+static int bcm54xx_auxctl_write(struct e1000_hw *hw, u16 regnum, u16 val)
+{
+    return bcmphy_write(hw, MII_BCM54XX_AUX_CTL, (regnum | val));
+}
+
+static int bcm54xx_config_init(struct e1000_hw *hw)
+{
+    int reg, err;
+
+    reg = bcmphy_read(hw, MII_BCM54XX_ECR);
+    if (reg < 0)
+        return reg;
+
+    /* Mask interrupts globally.  */
+    reg |= MII_BCM54XX_ECR_IM;
+    err = bcmphy_write(hw, MII_BCM54XX_ECR, reg);
+    if (err < 0)
+        return err;
+
+    /* Unmask events we are interested in.  */
+    reg = ~(MII_BCM54XX_INT_DUPLEX |
+            MII_BCM54XX_INT_SPEED |
+            MII_BCM54XX_INT_LINK);
+    err = bcmphy_write(hw, MII_BCM54XX_IMR, reg);
+    if (err < 0)
+        return err;
+
+    return 0;
+}
+
+void bcm54616s_linkup(struct e1000_hw *hw, int speed, int duplex)
+{
+    u16 regval;
+
+    /* set speed and full duplex*/
+    regval = bcmphy_read(hw,PHY_CONTROL);
+    regval &= ~(MII_CR_SPEED_SELECT_MSB |
+                MII_CR_SPEED_SELECT_LSB |
+                MII_CR_FULL_DUPLEX);
+
+    switch(speed) {
+        case SPEED_10:
+            regval |= MII_CR_SPEED_10;
+            break;
+        case SPEED_100:
+            regval |= MII_CR_SPEED_100;
+            break;
+        case SPEED_1000:
+        default:
+            regval |= MII_CR_SPEED_1000;
+            break;
+    }
+
+    switch(duplex) {
+        case FULL_DUPLEX:
+            regval |= MII_CR_FULL_DUPLEX;
+            break;
+    }
+
+    bcmphy_write(hw,PHY_CONTROL, regval);
+
+    regval = bcmphy_read(hw, PHY_CONTROL);
+    regval &= ~(MII_CR_ISOLATE);
+    bcmphy_write(hw, PHY_CONTROL, regval);
+}
+
+int bcm54616s_config_init(struct e1000_hw *hw)
+{
+    int err, reg;
+    u16 regval;
+    int i;
+
+    /* reset PHY */
+    regval = (1<<15);
+    bcmphy_write(hw, PHY_CONTROL, regval);
+
+    mdelay(10);
+
+    /* disable Power down and iso */
+    regval = bcmphy_read(hw,PHY_CONTROL);
+    regval &= ~(MII_CR_POWER_DOWN | MII_CR_ISOLATE);
+    bcmphy_write(hw, PHY_CONTROL, regval);
+
+    /* disable suport I */
+    /*0000 0100 1100 0010 */
+    bcm54xx_auxctl_write(hw, 0, 0x04c2);
+
+    regval = bcmphy_read(hw, MII_BCM54XX_AUX_CTL);
+
+    /* set 1000base-T */
+    regval = bcmphy_read(hw, PHY_1000T_CTRL);
+    regval |= (CR_1000T_FD_CAPS | CR_1000T_REPEATER_DTE);
+    bcmphy_write(hw, PHY_1000T_CTRL, regval);
+
+    /* set ctrl  */
+    regval = (MII_CR_SPEED_1000 |
+              MII_CR_FULL_DUPLEX |
+              MII_CR_SPEED_SELECT_MSB);
+    bcmphy_write(hw, PHY_CONTROL, regval);
+
+    /* Setup read from auxilary control shadow register 7 */
+    bcmphy_write(hw, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUX_CTL_ENCODE(7));
+
+    /* Read Misc Control register */
+    reg = ((bcmphy_read(hw, MII_BCM54XX_AUX_CTL) & 0x8FFF) | 0x8010);
+    bcmphy_write(hw, MII_BCM54XX_AUX_CTL, reg);
+
+    /* Enable auto-detect and copper prefer */
+    bcm54xx_shadow_write(hw, BCM54XX_SHD_AUTODETECT, 0x31);
+
+    err = bcm54xx_config_init(hw);
+
+    /* set link parner */
+    regval = MII_ANA_ASF_802_3;
+    regval |= MII_ANA_HD_10;
+    regval |= MII_ANA_HD_100;
+    regval |= MII_ANA_FD_10;
+    regval |= MII_ANA_FD_100;
+    regval |= MII_ANA_ASYM_PAUSE;
+    regval |= (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE);
+    regval |= MII_ANA_PAUSE;
+    bcmphy_write(hw, PHY_AUTONEG_ADV, reg);
+
+    i=0;
+    while (1) {
+        regval = bcm54xx_shadow_read(hw,BCM54XX_SHD_MODE);
+        if (regval & BCM54XX_SHD_MODE_SER)
+            break;
+        if (i++ > 500) {
+            //printk("SERDES no link %x\n",regval);
+            break;
+        }
+        mdelay(1);   /* 1 ms */
+    }
+    return err;
+}
diff -Nu 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	2017-06-20 16:44:29.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c	2017-06-20 17:00:52.000000000 +0800
@@ -317,6 +317,10 @@
 		break;
 	case BCM54616_E_PHY_ID:
 		phy->type = e1000_phy_bcm54616;
+		phy->ops.check_polarity     = NULL;
+		phy->ops.get_info       	= igb_get_phy_info_bcm;
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_bcm;
+		bcm54616s_config_init(hw);
 		break;
     case BCM50210S_E_PHY_ID:
         break;
@@ -1636,6 +1640,7 @@
 		ret_val = igb_e1000_copper_link_setup_82577(hw);
 		break;
 	case e1000_phy_bcm54616:
+		ret_val = igb_copper_link_setup_bcm(hw);
 		break;
 	case e1000_phy_bcm5461s:
 		break;
diff -Nu a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h	2017-06-20 16:44:27.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h	2017-06-20 17:00:57.000000000 +0800
@@ -25,6 +25,8 @@
 #ifndef _E1000_82575_H_
 #define _E1000_82575_H_
 
+extern void bcm54616s_linkup(struct e1000_hw *hw,int speed , int duplex);
+extern int bcm54616s_config_init(struct e1000_hw *hw);
 #define ID_LED_DEFAULT_82575_SERDES	((ID_LED_DEF1_DEF2 << 12) | \
 					 (ID_LED_DEF1_DEF2 <<  8) | \
 					 (ID_LED_DEF1_DEF2 <<  4) | \
diff -Nu 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	2017-06-20 16:44:27.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c	2017-06-20 17:01:05.000000000 +0800
@@ -1187,6 +1187,19 @@
 	return E1000_SUCCESS;
 }
 
+s32 igb_copper_link_setup_bcm(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+        ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+        phy_data &= ~(MII_CR_ISOLATE);
+        ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+
+	return 0;
+}
+
 /**
  *  e1000_copper_link_setup_m88_gen2 - Setup m88 PHY's for copper link
  *  @hw: pointer to the HW structure
@@ -1720,6 +1733,62 @@
 	return ret_val;
 }
 
+s32 igb_phy_force_speed_duplex_bcm(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	phy_data &= ~(MII_CR_POWER_DOWN | MII_CR_ISOLATE);
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	/* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	* forced whenever speed and duplex are forced.
+	*/
+	#if 0
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	hw_dbg("IGP PSCR: %X\n", phy_data);
+	#endif
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGFUNC("Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+						     100000, &link);
+		if (ret_val)
+			return ret_val;
+
+		if (!link)
+			DEBUGFUNC("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+						     100000, &link);
+	}
+
+	return ret_val;
+}
+
 /**
  *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
  *  @hw: pointer to the HW structure
@@ -2614,6 +2683,29 @@
 	}
 
 	return ret_val;
+}
+
+s32 igb_get_phy_info_bcm(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	bool link;
+
+	if (phy->media_type != e1000_media_type_copper) {
+		DEBUGFUNC("Phy info is only valid for copper media\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		return ret_val;
+
+	if (!link) {
+		DEBUGFUNC("Phy info is only valid if link is up\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	return ret_val;
 }
 
 /**
diff -Nu 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	2017-06-20 16:44:27.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h	2017-06-20 17:01:24.000000000 +0800
@@ -99,6 +99,9 @@
 s32 e1000_write_phy_reg_mphy(struct e1000_hw *hw, u32 address, u32 data,
 			     bool line_override);
 bool e1000_is_mphy_ready(struct e1000_hw *hw);
+s32  igb_copper_link_setup_bcm(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_bcm(struct e1000_hw *hw);
+s32  igb_get_phy_info_bcm(struct e1000_hw *hw);
 
 #define E1000_MAX_PHY_ADDR		8
 
diff -Nu 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	2017-06-20 16:44:27.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/igb_main.c	2017-06-20 17:01:29.000000000 +0800
@@ -4814,6 +4814,14 @@
 						   &adapter->link_speed,
 						   &adapter->link_duplex);
 
+			switch (hw->phy.type) {
+			       case e1000_phy_bcm54616:
+			           bcm54616s_linkup(hw, adapter->link_speed, adapter->link_duplex);
+			           break;
+			       default:
+			           break;
+			}
+
 			ctrl = E1000_READ_REG(hw, E1000_CTRL);
 			/* Links status message must follow this format */
 			netdev_info(netdev,
diff -Nu a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile
--- a/drivers/net/ethernet/intel/igb/Makefile	2017-06-20 16:44:27.000000000 +0800
+++ b/drivers/net/ethernet/intel/igb/Makefile	2017-06-20 17:01:34.000000000 +0800
@@ -35,4 +35,4 @@
 	e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
 	e1000_i210.o igb_ptp.o igb_hwmon.o \
 	e1000_manage.o igb_param.o kcompat.o e1000_api.o \
-	igb_vmdq.o igb_procfs.o igb_debugfs.o
+	igb_vmdq.o igb_procfs.o igb_debugfs.o bcm_phy.o
