ixgbe/base: support 5G link speed
[dpdk.git] / lib / librte_pmd_ixgbe / ixgbe / ixgbe_phy.c
index 60995dc..38c9909 100644 (file)
@@ -34,7 +34,6 @@ POSSIBILITY OF SUCH DAMAGE.
 #include "ixgbe_api.h"
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
-#ident "$Id: ixgbe_phy.c,v 1.155 2013/08/14 22:34:03 jtkirshe Exp $"
 
 STATIC void ixgbe_i2c_start(struct ixgbe_hw *hw);
 STATIC void ixgbe_i2c_stop(struct ixgbe_hw *hw);
@@ -46,10 +45,192 @@ STATIC s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
 STATIC void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
 STATIC void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
 STATIC s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
-STATIC bool ixgbe_get_i2c_data(u32 *i2cctl);
+STATIC bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl);
 STATIC s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                          u8 *sff8472_data);
 
+/**
+ * ixgbe_out_i2c_byte_ack - Send I2C byte with ack
+ * @hw: pointer to the hardware structure
+ * @byte: byte to send
+ *
+ * Returns an error code on error.
+ */
+STATIC s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte)
+{
+       s32 status;
+
+       status = ixgbe_clock_out_i2c_byte(hw, byte);
+       if (status)
+               return status;
+       return ixgbe_get_i2c_ack(hw);
+}
+
+/**
+ * ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack
+ * @hw: pointer to the hardware structure
+ * @byte: pointer to a u8 to receive the byte
+ *
+ * Returns an error code on error.
+ */
+STATIC s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte)
+{
+       s32 status;
+
+       status = ixgbe_clock_in_i2c_byte(hw, byte);
+       if (status)
+               return status;
+       /* ACK */
+       return ixgbe_clock_out_i2c_bit(hw, false);
+}
+
+/**
+ * ixgbe_ones_comp_byte_add - Perform one's complement addition
+ * @add1 - addend 1
+ * @add2 - addend 2
+ *
+ * Returns one's complement 8-bit sum.
+ */
+STATIC u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
+{
+       u16 sum = add1 + add2;
+
+       sum = (sum & 0xFF) + (sum >> 8);
+       return sum & 0xFF;
+}
+
+/**
+ * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to read from
+ * @reg: I2C device register to read from
+ * @val: pointer to location to receive read value
+ *
+ * Returns an error code on error.
+ */
+STATIC s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
+                                          u16 reg, u16 *val)
+{
+       u32 swfw_mask = hw->phy.phy_semaphore_mask;
+       int max_retry = 10;
+       int retry = 0;
+       u8 csum_byte;
+       u8 high_bits;
+       u8 low_bits;
+       u8 reg_high;
+       u8 csum;
+
+       reg_high = ((reg >> 7) & 0xFE) | 1;     /* Indicate read combined */
+       csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
+       csum = ~csum;
+       do {
+               if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+                       return IXGBE_ERR_SWFW_SYNC;
+               ixgbe_i2c_start(hw);
+               /* Device Address and write indication */
+               if (ixgbe_out_i2c_byte_ack(hw, addr))
+                       goto fail;
+               /* Write bits 14:8 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg_high))
+                       goto fail;
+               /* Write bits 7:0 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
+                       goto fail;
+               /* Write csum */
+               if (ixgbe_out_i2c_byte_ack(hw, csum))
+                       goto fail;
+               /* Re-start condition */
+               ixgbe_i2c_start(hw);
+               /* Device Address and read indication */
+               if (ixgbe_out_i2c_byte_ack(hw, addr | 1))
+                       goto fail;
+               /* Get upper bits */
+               if (ixgbe_in_i2c_byte_ack(hw, &high_bits))
+                       goto fail;
+               /* Get low bits */
+               if (ixgbe_in_i2c_byte_ack(hw, &low_bits))
+                       goto fail;
+               /* Get csum */
+               if (ixgbe_clock_in_i2c_byte(hw, &csum_byte))
+                       goto fail;
+               /* NACK */
+               if (ixgbe_clock_out_i2c_bit(hw, false))
+                       goto fail;
+               ixgbe_i2c_stop(hw);
+               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               *val = (high_bits << 8) | low_bits;
+               return 0;
+
+fail:
+               ixgbe_i2c_bus_clear(hw);
+               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               retry++;
+               if (retry < max_retry)
+                       DEBUGOUT("I2C byte read combined error - Retrying.\n");
+               else
+                       DEBUGOUT("I2C byte read combined error.\n");
+       } while (retry < max_retry);
+
+       return IXGBE_ERR_I2C;
+}
+
+/**
+ * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to write to
+ * @reg: I2C device register to write to
+ * @val: value to write
+ *
+ * Returns an error code on error.
+ */
+STATIC s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
+                                           u8 addr, u16 reg, u16 val)
+{
+       int max_retry = 1;
+       int retry = 0;
+       u8 reg_high;
+       u8 csum;
+
+       reg_high = (reg >> 7) & 0xFE;   /* Indicate write combined */
+       csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
+       csum = ixgbe_ones_comp_byte_add(csum, val >> 8);
+       csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
+       csum = ~csum;
+       do {
+               ixgbe_i2c_start(hw);
+               /* Device Address and write indication */
+               if (ixgbe_out_i2c_byte_ack(hw, addr))
+                       goto fail;
+               /* Write bits 14:8 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg_high))
+                       goto fail;
+               /* Write bits 7:0 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
+                       goto fail;
+               /* Write data 15:8 */
+               if (ixgbe_out_i2c_byte_ack(hw, val >> 8))
+                       goto fail;
+               /* Write data 7:0 */
+               if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF))
+                       goto fail;
+               /* Write csum */
+               if (ixgbe_out_i2c_byte_ack(hw, csum))
+                       goto fail;
+               ixgbe_i2c_stop(hw);
+               return 0;
+
+fail:
+               ixgbe_i2c_bus_clear(hw);
+               retry++;
+               if (retry < max_retry)
+                       DEBUGOUT("I2C byte write combined error - Retrying.\n");
+               else
+                       DEBUGOUT("I2C byte write combined error.\n");
+       } while (retry < max_retry);
+
+       return IXGBE_ERR_I2C;
+}
+
 /**
  *  ixgbe_init_phy_ops_generic - Inits PHY function ptrs
  *  @hw: pointer to the hardware structure
@@ -63,25 +244,27 @@ s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
        DEBUGFUNC("ixgbe_init_phy_ops_generic");
 
        /* PHY */
-       phy->ops.identify = &ixgbe_identify_phy_generic;
-       phy->ops.reset = &ixgbe_reset_phy_generic;
-       phy->ops.read_reg = &ixgbe_read_phy_reg_generic;
-       phy->ops.write_reg = &ixgbe_write_phy_reg_generic;
-       phy->ops.read_reg_mdi = &ixgbe_read_phy_reg_mdi;
-       phy->ops.write_reg_mdi = &ixgbe_write_phy_reg_mdi;
-       phy->ops.setup_link = &ixgbe_setup_phy_link_generic;
-       phy->ops.setup_link_speed = &ixgbe_setup_phy_link_speed_generic;
+       phy->ops.identify = ixgbe_identify_phy_generic;
+       phy->ops.reset = ixgbe_reset_phy_generic;
+       phy->ops.read_reg = ixgbe_read_phy_reg_generic;
+       phy->ops.write_reg = ixgbe_write_phy_reg_generic;
+       phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi;
+       phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi;
+       phy->ops.setup_link = ixgbe_setup_phy_link_generic;
+       phy->ops.setup_link_speed = ixgbe_setup_phy_link_speed_generic;
        phy->ops.check_link = NULL;
        phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic;
-       phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_generic;
-       phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_generic;
-       phy->ops.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic;
-       phy->ops.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic;
-       phy->ops.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic;
-       phy->ops.i2c_bus_clear = &ixgbe_i2c_bus_clear;
-       phy->ops.identify_sfp = &ixgbe_identify_module_generic;
+       phy->ops.read_i2c_byte = ixgbe_read_i2c_byte_generic;
+       phy->ops.write_i2c_byte = ixgbe_write_i2c_byte_generic;
+       phy->ops.read_i2c_sff8472 = ixgbe_read_i2c_sff8472_generic;
+       phy->ops.read_i2c_eeprom = ixgbe_read_i2c_eeprom_generic;
+       phy->ops.write_i2c_eeprom = ixgbe_write_i2c_eeprom_generic;
+       phy->ops.i2c_bus_clear = ixgbe_i2c_bus_clear;
+       phy->ops.identify_sfp = ixgbe_identify_module_generic;
        phy->sfp_type = ixgbe_sfp_type_unknown;
-       phy->ops.check_overtemp = &ixgbe_tn_check_overtemp;
+       phy->ops.read_i2c_combined = ixgbe_read_i2c_combined_generic;
+       phy->ops.write_i2c_combined = ixgbe_write_i2c_combined_generic;
+       phy->ops.check_overtemp = ixgbe_tn_check_overtemp;
        return IXGBE_SUCCESS;
 }
 
@@ -244,6 +427,7 @@ enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
        case TN1010_PHY_ID:
                phy_type = ixgbe_phy_tn;
                break;
+       case X550_PHY_ID:
        case X540_PHY_ID:
                phy_type = ixgbe_phy_aq;
                break;
@@ -560,6 +744,44 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
                                      autoneg_reg);
        }
 
+       if (hw->mac.type == ixgbe_mac_X550) {
+               if (speed & IXGBE_LINK_SPEED_5GB_FULL) {
+                       /* Set or unset auto-negotiation 1G advertisement */
+                       hw->phy.ops.read_reg(hw,
+                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                               &autoneg_reg);
+
+                       autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE;
+                       if (hw->phy.autoneg_advertised &
+                            IXGBE_LINK_SPEED_5GB_FULL)
+                               autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE;
+
+                       hw->phy.ops.write_reg(hw,
+                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                               autoneg_reg);
+               }
+
+               if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) {
+                       /* Set or unset auto-negotiation 1G advertisement */
+                       hw->phy.ops.read_reg(hw,
+                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                               &autoneg_reg);
+
+                       autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE;
+                       if (hw->phy.autoneg_advertised &
+                           IXGBE_LINK_SPEED_2_5GB_FULL)
+                               autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE;
+
+                       hw->phy.ops.write_reg(hw,
+                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                               autoneg_reg);
+               }
+       }
+
        if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
                /* Set or unset auto-negotiation 1G advertisement */
                hw->phy.ops.read_reg(hw,
@@ -631,6 +853,12 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
        if (speed & IXGBE_LINK_SPEED_10GB_FULL)
                hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
 
+       if (speed & IXGBE_LINK_SPEED_5GB_FULL)
+               hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL;
+
+       if (speed & IXGBE_LINK_SPEED_2_5GB_FULL)
+               hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
+
        if (speed & IXGBE_LINK_SPEED_1GB_FULL)
                hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
 
@@ -649,7 +877,8 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
  *  @speed: pointer to link speed
  *  @autoneg: boolean auto-negotiation value
  *
- *  Determines the link capabilities by reading the AUTOC register.
+ *  Determines the supported link capabilities by reading the PHY auto
+ *  negotiation register.
  **/
 s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
                                               ixgbe_link_speed *speed,
@@ -676,6 +905,15 @@ s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
                        *speed |= IXGBE_LINK_SPEED_100_FULL;
        }
 
+       /* Internal PHY does not support 100 Mbps */
+       if (hw->mac.type == ixgbe_mac_X550EM_x)
+               *speed &= ~IXGBE_LINK_SPEED_100_FULL;
+
+       if (hw->mac.type == ixgbe_mac_X550) {
+               *speed |= IXGBE_LINK_SPEED_2_5GB_FULL;
+               *speed |= IXGBE_LINK_SPEED_5GB_FULL;
+       }
+
        return status;
 }
 
@@ -1017,6 +1255,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                goto out;
        }
 
+       /* LAN ID is needed for I2C access */
+       hw->mac.ops.set_lan_id(hw);
+
        status = hw->phy.ops.read_i2c_eeprom(hw,
                                             IXGBE_SFF_IDENTIFIER,
                                             &identifier);
@@ -1024,9 +1265,6 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
        if (status != IXGBE_SUCCESS)
                goto err_read_i2c_eeprom;
 
-       /* LAN ID is needed for sfp_type determination */
-       hw->mac.ops.set_lan_id(hw);
-
        if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
                hw->phy.type = ixgbe_phy_sfp_unsupported;
                status = IXGBE_ERR_SFP_NOT_SUPPORTED;
@@ -1689,6 +1927,21 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                          eeprom_data);
 }
 
+/**
+ * ixgbe_is_sfp_probe - Returns true if SFP is being detected
+ * @hw: pointer to hardware structure
+ * @offset: eeprom offset to be read
+ * @addr: I2C address to be read
+ */
+STATIC bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr)
+{
+       if (addr == IXGBE_I2C_EEPROM_DEV_ADDR &&
+           offset == IXGBE_SFF_IDENTIFIER &&
+           hw->phy.sfp_type == ixgbe_sfp_type_not_present)
+               return true;
+       return false;
+}
+
 /**
  *  ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
  *  @hw: pointer to hardware structure
@@ -1710,6 +1963,9 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
 
        DEBUGFUNC("ixgbe_read_i2c_byte_generic");
 
+       if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr))
+               max_retry = IXGBE_SFP_DETECT_RETRIES;
+
        do {
                if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
                        return IXGBE_ERR_SWFW_SYNC;
@@ -1846,13 +2102,16 @@ write_byte_out:
  *  @hw: pointer to hardware structure
  *
  *  Sets I2C start condition (High -> Low on SDA while SCL is High)
+ *  Set bit-bang mode on X550 hardware.
  **/
 STATIC void ixgbe_i2c_start(struct ixgbe_hw *hw)
 {
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
 
        DEBUGFUNC("ixgbe_i2c_start");
 
+       i2cctl |= IXGBE_I2C_BB_EN_BY_MAC(hw);
+
        /* Start condition must begin with data and clock high */
        ixgbe_set_i2c_data(hw, &i2cctl, 1);
        ixgbe_raise_i2c_clk(hw, &i2cctl);
@@ -1877,10 +2136,15 @@ STATIC void ixgbe_i2c_start(struct ixgbe_hw *hw)
  *  @hw: pointer to hardware structure
  *
  *  Sets I2C stop condition (Low -> High on SDA while SCL is High)
+ *  Disables bit-bang mode and negates data output enable on X550
+ *  hardware.
  **/
 STATIC void ixgbe_i2c_stop(struct ixgbe_hw *hw)
 {
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+       u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
+       u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
+       u32 bb_en_bit = IXGBE_I2C_BB_EN_BY_MAC(hw);
 
        DEBUGFUNC("ixgbe_i2c_stop");
 
@@ -1895,6 +2159,13 @@ STATIC void ixgbe_i2c_stop(struct ixgbe_hw *hw)
 
        /* bus free time between stop and start (4.7us)*/
        usec_delay(IXGBE_I2C_T_BUF);
+
+       if (bb_en_bit || data_oe_bit || clk_oe_bit) {
+               i2cctl &= ~bb_en_bit;
+               i2cctl |= data_oe_bit | clk_oe_bit;
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
+               IXGBE_WRITE_FLUSH(hw);
+       }
 }
 
 /**
@@ -1911,6 +2182,7 @@ STATIC s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
 
        DEBUGFUNC("ixgbe_clock_in_i2c_byte");
 
+       *data = 0;
        for (i = 7; i >= 0; i--) {
                ixgbe_clock_in_i2c_bit(hw, &bit);
                *data |= bit << i;
@@ -1944,9 +2216,10 @@ STATIC s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
        }
 
        /* Release SDA line (set high) */
-       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
-       i2cctl |= IXGBE_I2C_DATA_OUT;
-       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl);
+       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+       i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
+       i2cctl |= IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
        IXGBE_WRITE_FLUSH(hw);
 
        return status;
@@ -1960,34 +2233,39 @@ STATIC s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
  **/
 STATIC s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
 {
+       u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
        s32 status = IXGBE_SUCCESS;
        u32 i = 0;
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
        u32 timeout = 10;
        bool ack = 1;
 
        DEBUGFUNC("ixgbe_get_i2c_ack");
 
+       if (data_oe_bit) {
+               i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
+               i2cctl |= data_oe_bit;
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
+               IXGBE_WRITE_FLUSH(hw);
+       }
        ixgbe_raise_i2c_clk(hw, &i2cctl);
 
-
        /* Minimum high period of clock is 4us */
        usec_delay(IXGBE_I2C_T_HIGH);
 
        /* Poll for ACK.  Note that ACK in I2C spec is
         * transition from 1 to 0 */
        for (i = 0; i < timeout; i++) {
-               i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
-               ack = ixgbe_get_i2c_data(&i2cctl);
+               i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+               ack = ixgbe_get_i2c_data(hw, &i2cctl);
 
                usec_delay(1);
                if (!ack)
                        break;
        }
 
-       if (ack == 1) {
-               ERROR_REPORT1(IXGBE_ERROR_POLLING,
-                            "I2C ack was not received.\n");
+       if (ack) {
+               DEBUGOUT("I2C ack was not received.\n");
                status = IXGBE_ERR_I2C;
        }
 
@@ -2008,17 +2286,24 @@ STATIC s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
  **/
 STATIC s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
 {
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+       u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
 
        DEBUGFUNC("ixgbe_clock_in_i2c_bit");
 
+       if (data_oe_bit) {
+               i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
+               i2cctl |= data_oe_bit;
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
+               IXGBE_WRITE_FLUSH(hw);
+       }
        ixgbe_raise_i2c_clk(hw, &i2cctl);
 
        /* Minimum high period of clock is 4us */
        usec_delay(IXGBE_I2C_T_HIGH);
 
-       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
-       *data = ixgbe_get_i2c_data(&i2cctl);
+       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+       *data = ixgbe_get_i2c_data(hw, &i2cctl);
 
        ixgbe_lower_i2c_clk(hw, &i2cctl);
 
@@ -2038,7 +2323,7 @@ STATIC s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
 STATIC s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
 {
        s32 status;
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
 
        DEBUGFUNC("ixgbe_clock_out_i2c_bit");
 
@@ -2070,25 +2355,32 @@ STATIC s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
  *  @i2cctl: Current value of I2CCTL register
  *
  *  Raises the I2C clock line '0'->'1'
+ *  Negates the I2C clock output enable on X550 hardware.
  **/
 STATIC void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
 {
+       u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
        u32 i = 0;
        u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT;
        u32 i2cctl_r = 0;
 
        DEBUGFUNC("ixgbe_raise_i2c_clk");
 
+       if (clk_oe_bit) {
+               *i2cctl |= clk_oe_bit;
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
+       }
+
        for (i = 0; i < timeout; i++) {
-               *i2cctl |= IXGBE_I2C_CLK_OUT;
+               *i2cctl |= IXGBE_I2C_CLK_OUT_BY_MAC(hw);
 
-               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
                IXGBE_WRITE_FLUSH(hw);
                /* SCL rise time (1000ns) */
                usec_delay(IXGBE_I2C_T_RISE);
 
-               i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
-               if (i2cctl_r & IXGBE_I2C_CLK_IN)
+               i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+               if (i2cctl_r & IXGBE_I2C_CLK_IN_BY_MAC(hw))
                        break;
        }
 }
@@ -2099,15 +2391,16 @@ STATIC void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
  *  @i2cctl: Current value of I2CCTL register
  *
  *  Lowers the I2C clock line '1'->'0'
+ *  Asserts the I2C clock output enable on X550 hardware.
  **/
 STATIC void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
 {
-
        DEBUGFUNC("ixgbe_lower_i2c_clk");
 
-       *i2cctl &= ~IXGBE_I2C_CLK_OUT;
+       *i2cctl &= ~(IXGBE_I2C_CLK_OUT_BY_MAC(hw));
+       *i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
 
-       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
        IXGBE_WRITE_FLUSH(hw);
 
        /* SCL fall time (300ns) */
@@ -2121,27 +2414,38 @@ STATIC void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
  *  @data: I2C data value (0 or 1) to set
  *
  *  Sets the I2C data bit
+ *  Asserts the I2C data output enable on X550 hardware.
  **/
 STATIC s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
 {
+       u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
        s32 status = IXGBE_SUCCESS;
 
        DEBUGFUNC("ixgbe_set_i2c_data");
 
        if (data)
-               *i2cctl |= IXGBE_I2C_DATA_OUT;
+               *i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
        else
-               *i2cctl &= ~IXGBE_I2C_DATA_OUT;
+               *i2cctl &= ~(IXGBE_I2C_DATA_OUT_BY_MAC(hw));
+       *i2cctl &= ~data_oe_bit;
 
-       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
        IXGBE_WRITE_FLUSH(hw);
 
        /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
        usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
 
+       if (!data)      /* Can't verify data in this case */
+               return IXGBE_SUCCESS;
+       if (data_oe_bit) {
+               *i2cctl |= data_oe_bit;
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
+               IXGBE_WRITE_FLUSH(hw);
+       }
+
        /* Verify data was set correctly */
-       *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
-       if (data != ixgbe_get_i2c_data(i2cctl)) {
+       *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+       if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
                status = IXGBE_ERR_I2C;
                ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
                             "Error - I2C data was not set to %X.\n",
@@ -2157,14 +2461,23 @@ STATIC s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
  *  @i2cctl: Current value of I2CCTL register
  *
  *  Returns the I2C data bit value
+ *  Negates the I2C data output enable on X550 hardware.
  **/
-STATIC bool ixgbe_get_i2c_data(u32 *i2cctl)
+STATIC bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
 {
+       u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
        bool data;
 
        DEBUGFUNC("ixgbe_get_i2c_data");
 
-       if (*i2cctl & IXGBE_I2C_DATA_IN)
+       if (data_oe_bit) {
+               *i2cctl |= data_oe_bit;
+               IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
+               IXGBE_WRITE_FLUSH(hw);
+               usec_delay(IXGBE_I2C_T_FALL);
+       }
+
+       if (*i2cctl & IXGBE_I2C_DATA_IN_BY_MAC(hw))
                data = 1;
        else
                data = 0;
@@ -2181,12 +2494,13 @@ STATIC bool ixgbe_get_i2c_data(u32 *i2cctl)
  **/
 void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
 {
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i2cctl;
        u32 i;
 
        DEBUGFUNC("ixgbe_i2c_bus_clear");
 
        ixgbe_i2c_start(hw);
+       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
 
        ixgbe_set_i2c_data(hw, &i2cctl, 1);