ixgbe/base: i2c bit-bang mode
authorOuyang Changchun <changchun.ouyang@intel.com>
Thu, 12 Feb 2015 12:01:03 +0000 (20:01 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Mon, 27 Apr 2015 07:55:24 +0000 (09:55 +0200)
Support the bit-bang mode on X550;
And negate I2C output enable;

Signed-off-by: Changchun Ouyang <changchun.ouyang@intel.com>
Acked-by: Jijiang Liu <jijiang.liu@intel.com>
lib/librte_pmd_ixgbe/ixgbe/ixgbe_phy.c
lib/librte_pmd_ixgbe/ixgbe/ixgbe_type.h

index 0c0b084..22a2899 100644 (file)
@@ -2030,6 +2030,7 @@ 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)
 {
@@ -2037,6 +2038,8 @@ STATIC void ixgbe_i2c_start(struct ixgbe_hw *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);
@@ -2061,10 +2064,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_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");
 
@@ -2079,6 +2087,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);
+       }
 }
 
 /**
@@ -2095,6 +2110,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;
@@ -2130,6 +2146,7 @@ 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_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);
 
@@ -2144,6 +2161,7 @@ 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_BY_MAC(hw));
@@ -2152,9 +2170,14 @@ STATIC s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
 
        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);
 
@@ -2192,9 +2215,16 @@ 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_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 */
@@ -2253,15 +2283,22 @@ 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_BY_MAC(hw);
 
@@ -2282,13 +2319,14 @@ 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_BY_MAC(hw));
+       *i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
 
        IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
        IXGBE_WRITE_FLUSH(hw);
@@ -2304,9 +2342,11 @@ 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");
@@ -2315,6 +2355,7 @@ STATIC s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
                *i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
        else
                *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);
@@ -2322,6 +2363,14 @@ STATIC s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
        /* 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_BY_MAC(hw));
        if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
@@ -2340,14 +2389,22 @@ 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(struct ixgbe_hw *hw, u32 *i2cctl)
 {
+       u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
        bool data;
-       UNREFERENCED_1PARAMETER(hw);
 
        DEBUGFUNC("ixgbe_get_i2c_data");
 
+       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
@@ -2365,12 +2422,13 @@ STATIC bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
  **/
 void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
 {
-       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+       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);
 
index 5a2580a..0dba7d9 100644 (file)
@@ -187,6 +187,12 @@ POSSIBILITY OF SUCH DAMAGE.
                                        0x00001000 : 0x00000004)
 #define IXGBE_I2C_DATA_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
                                        0x00000400 : 0x00000008)
+#define IXGBE_I2C_BB_EN_BY_MAC(hw) ((hw)->mac.type >= ixgbe_mac_X550 ? \
+                                   0x00000100 : 0)
+#define IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw) ((hw)->mac.type >= ixgbe_mac_X550 ? \
+                                          0x00000800 : 0)
+#define IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw) ((hw)->mac.type >= ixgbe_mac_X550 ? \
+                                         0x00002000 : 0)
 #define IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT     500
 
 #define IXGBE_I2C_THERMAL_SENSOR_ADDR  0xF8