net/txgbe: add module identify
Add sfp anf qsfp module identify, i2c start and stop. Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com> Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
parent
5364a1ce30
commit
8f09fb4642
@ -23,6 +23,7 @@
|
||||
#define TXGBE_EEPROM_VERSION_H 0x1E
|
||||
#define TXGBE_ISCSI_BOOT_CONFIG 0x07
|
||||
|
||||
#define TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1
|
||||
|
||||
s32 txgbe_init_eeprom_params(struct txgbe_hw *hw);
|
||||
s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw);
|
||||
|
@ -291,6 +291,10 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw)
|
||||
/* PHY */
|
||||
phy->identify = txgbe_identify_phy;
|
||||
phy->init = txgbe_init_phy_raptor;
|
||||
phy->read_i2c_byte = txgbe_read_i2c_byte;
|
||||
phy->write_i2c_byte = txgbe_write_i2c_byte;
|
||||
phy->read_i2c_eeprom = txgbe_read_i2c_eeprom;
|
||||
phy->write_i2c_eeprom = txgbe_write_i2c_eeprom;
|
||||
|
||||
/* MAC */
|
||||
mac->init_hw = txgbe_init_hw;
|
||||
|
@ -7,6 +7,9 @@
|
||||
#include "txgbe_mng.h"
|
||||
#include "txgbe_phy.h"
|
||||
|
||||
static void txgbe_i2c_start(struct txgbe_hw *hw);
|
||||
static void txgbe_i2c_stop(struct txgbe_hw *hw);
|
||||
|
||||
/**
|
||||
* txgbe_identify_extphy - Identify a single address for a PHY
|
||||
* @hw: pointer to hardware structure
|
||||
@ -234,8 +237,204 @@ s32 txgbe_identify_module(struct txgbe_hw *hw)
|
||||
**/
|
||||
s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
|
||||
{
|
||||
RTE_SET_USED(hw);
|
||||
return 0;
|
||||
s32 err = TXGBE_ERR_PHY_ADDR_INVALID;
|
||||
u32 vendor_oui = 0;
|
||||
enum txgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
|
||||
u8 identifier = 0;
|
||||
u8 comp_codes_1g = 0;
|
||||
u8 comp_codes_10g = 0;
|
||||
u8 oui_bytes[3] = {0, 0, 0};
|
||||
u8 cable_tech = 0;
|
||||
u8 cable_spec = 0;
|
||||
u16 enforce_sfp = 0;
|
||||
|
||||
DEBUGFUNC("txgbe_identify_sfp_module");
|
||||
|
||||
if (hw->phy.media_type != txgbe_media_type_fiber) {
|
||||
hw->phy.sfp_type = txgbe_sfp_type_not_present;
|
||||
return TXGBE_ERR_SFP_NOT_PRESENT;
|
||||
}
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER,
|
||||
&identifier);
|
||||
if (err != 0) {
|
||||
ERR_I2C:
|
||||
hw->phy.sfp_type = txgbe_sfp_type_not_present;
|
||||
if (hw->phy.type != txgbe_phy_nl) {
|
||||
hw->phy.id = 0;
|
||||
hw->phy.type = txgbe_phy_unknown;
|
||||
}
|
||||
return TXGBE_ERR_SFP_NOT_PRESENT;
|
||||
}
|
||||
|
||||
if (identifier != TXGBE_SFF_IDENTIFIER_SFP) {
|
||||
hw->phy.type = txgbe_phy_sfp_unsupported;
|
||||
return TXGBE_ERR_SFP_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_1GBE_COMP_CODES,
|
||||
&comp_codes_1g);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_10GBE_COMP_CODES,
|
||||
&comp_codes_10g);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_CABLE_TECHNOLOGY,
|
||||
&cable_tech);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
/* ID Module
|
||||
* =========
|
||||
* 0 SFP_DA_CU
|
||||
* 1 SFP_SR
|
||||
* 2 SFP_LR
|
||||
* 3 SFP_DA_CORE0 - chip-specific
|
||||
* 4 SFP_DA_CORE1 - chip-specific
|
||||
* 5 SFP_SR/LR_CORE0 - chip-specific
|
||||
* 6 SFP_SR/LR_CORE1 - chip-specific
|
||||
* 7 SFP_act_lmt_DA_CORE0 - chip-specific
|
||||
* 8 SFP_act_lmt_DA_CORE1 - chip-specific
|
||||
* 9 SFP_1g_cu_CORE0 - chip-specific
|
||||
* 10 SFP_1g_cu_CORE1 - chip-specific
|
||||
* 11 SFP_1g_sx_CORE0 - chip-specific
|
||||
* 12 SFP_1g_sx_CORE1 - chip-specific
|
||||
*/
|
||||
if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE) {
|
||||
if (hw->bus.lan_id == 0)
|
||||
hw->phy.sfp_type = txgbe_sfp_type_da_cu_core0;
|
||||
else
|
||||
hw->phy.sfp_type = txgbe_sfp_type_da_cu_core1;
|
||||
} else if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE) {
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_CABLE_SPEC_COMP, &cable_spec);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
if (cable_spec & TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
|
||||
hw->phy.sfp_type = (hw->bus.lan_id == 0
|
||||
? txgbe_sfp_type_da_act_lmt_core0
|
||||
: txgbe_sfp_type_da_act_lmt_core1);
|
||||
} else {
|
||||
hw->phy.sfp_type = txgbe_sfp_type_unknown;
|
||||
}
|
||||
} else if (comp_codes_10g &
|
||||
(TXGBE_SFF_10GBASESR_CAPABLE |
|
||||
TXGBE_SFF_10GBASELR_CAPABLE)) {
|
||||
hw->phy.sfp_type = (hw->bus.lan_id == 0
|
||||
? txgbe_sfp_type_srlr_core0
|
||||
: txgbe_sfp_type_srlr_core1);
|
||||
} else if (comp_codes_1g & TXGBE_SFF_1GBASET_CAPABLE) {
|
||||
hw->phy.sfp_type = (hw->bus.lan_id == 0
|
||||
? txgbe_sfp_type_1g_cu_core0
|
||||
: txgbe_sfp_type_1g_cu_core1);
|
||||
} else if (comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) {
|
||||
hw->phy.sfp_type = (hw->bus.lan_id == 0
|
||||
? txgbe_sfp_type_1g_sx_core0
|
||||
: txgbe_sfp_type_1g_sx_core1);
|
||||
} else if (comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) {
|
||||
hw->phy.sfp_type = (hw->bus.lan_id == 0
|
||||
? txgbe_sfp_type_1g_lx_core0
|
||||
: txgbe_sfp_type_1g_lx_core1);
|
||||
} else {
|
||||
hw->phy.sfp_type = txgbe_sfp_type_unknown;
|
||||
}
|
||||
|
||||
if (hw->phy.sfp_type != stored_sfp_type)
|
||||
hw->phy.sfp_setup_needed = true;
|
||||
|
||||
/* Determine if the SFP+ PHY is dual speed or not. */
|
||||
hw->phy.multispeed_fiber = false;
|
||||
if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) &&
|
||||
(comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) ||
|
||||
((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) &&
|
||||
(comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE)))
|
||||
hw->phy.multispeed_fiber = true;
|
||||
|
||||
/* Determine PHY vendor */
|
||||
if (hw->phy.type != txgbe_phy_nl) {
|
||||
hw->phy.id = identifier;
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]);
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
vendor_oui = ((u32)oui_bytes[0] << 24) |
|
||||
((u32)oui_bytes[1] << 16) |
|
||||
((u32)oui_bytes[2] << 8);
|
||||
switch (vendor_oui) {
|
||||
case TXGBE_SFF_VENDOR_OUI_TYCO:
|
||||
if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE)
|
||||
hw->phy.type = txgbe_phy_sfp_tyco_passive;
|
||||
break;
|
||||
case TXGBE_SFF_VENDOR_OUI_FTL:
|
||||
if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE)
|
||||
hw->phy.type = txgbe_phy_sfp_ftl_active;
|
||||
else
|
||||
hw->phy.type = txgbe_phy_sfp_ftl;
|
||||
break;
|
||||
case TXGBE_SFF_VENDOR_OUI_AVAGO:
|
||||
hw->phy.type = txgbe_phy_sfp_avago;
|
||||
break;
|
||||
case TXGBE_SFF_VENDOR_OUI_INTEL:
|
||||
hw->phy.type = txgbe_phy_sfp_intel;
|
||||
break;
|
||||
default:
|
||||
if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE)
|
||||
hw->phy.type = txgbe_phy_sfp_unknown_passive;
|
||||
else if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE)
|
||||
hw->phy.type = txgbe_phy_sfp_unknown_active;
|
||||
else
|
||||
hw->phy.type = txgbe_phy_sfp_unknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow any DA cable vendor */
|
||||
if (cable_tech & (TXGBE_SFF_CABLE_DA_PASSIVE |
|
||||
TXGBE_SFF_CABLE_DA_ACTIVE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify supported 1G SFP modules */
|
||||
if (comp_codes_10g == 0 &&
|
||||
!(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) {
|
||||
hw->phy.type = txgbe_phy_sfp_unsupported;
|
||||
return TXGBE_ERR_SFP_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
hw->mac.get_device_caps(hw, &enforce_sfp);
|
||||
if (!(enforce_sfp & TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
|
||||
!hw->allow_unsupported_sfp &&
|
||||
!(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 ||
|
||||
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) {
|
||||
DEBUGOUT("SFP+ module not supported\n");
|
||||
hw->phy.type = txgbe_phy_sfp_unsupported;
|
||||
return TXGBE_ERR_SFP_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,7 +445,390 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
|
||||
**/
|
||||
s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
|
||||
{
|
||||
RTE_SET_USED(hw);
|
||||
s32 err = TXGBE_ERR_PHY_ADDR_INVALID;
|
||||
u32 vendor_oui = 0;
|
||||
enum txgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
|
||||
u8 identifier = 0;
|
||||
u8 comp_codes_1g = 0;
|
||||
u8 comp_codes_10g = 0;
|
||||
u8 oui_bytes[3] = {0, 0, 0};
|
||||
u16 enforce_sfp = 0;
|
||||
u8 connector = 0;
|
||||
u8 cable_length = 0;
|
||||
u8 device_tech = 0;
|
||||
bool active_cable = false;
|
||||
|
||||
DEBUGFUNC("txgbe_identify_qsfp_module");
|
||||
|
||||
if (hw->phy.media_type != txgbe_media_type_fiber_qsfp) {
|
||||
hw->phy.sfp_type = txgbe_sfp_type_not_present;
|
||||
err = TXGBE_ERR_SFP_NOT_PRESENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER,
|
||||
&identifier);
|
||||
ERR_I2C:
|
||||
if (err != 0) {
|
||||
hw->phy.sfp_type = txgbe_sfp_type_not_present;
|
||||
hw->phy.id = 0;
|
||||
hw->phy.type = txgbe_phy_unknown;
|
||||
return TXGBE_ERR_SFP_NOT_PRESENT;
|
||||
}
|
||||
if (identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
|
||||
hw->phy.type = txgbe_phy_sfp_unsupported;
|
||||
err = TXGBE_ERR_SFP_NOT_SUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hw->phy.id = identifier;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_QSFP_10GBE_COMP,
|
||||
&comp_codes_10g);
|
||||
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_QSFP_1GBE_COMP,
|
||||
&comp_codes_1g);
|
||||
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
if (comp_codes_10g & TXGBE_SFF_QSFP_DA_PASSIVE_CABLE) {
|
||||
hw->phy.type = txgbe_phy_qsfp_unknown_passive;
|
||||
if (hw->bus.lan_id == 0)
|
||||
hw->phy.sfp_type = txgbe_sfp_type_da_cu_core0;
|
||||
else
|
||||
hw->phy.sfp_type = txgbe_sfp_type_da_cu_core1;
|
||||
} else if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE |
|
||||
TXGBE_SFF_10GBASELR_CAPABLE)) {
|
||||
if (hw->bus.lan_id == 0)
|
||||
hw->phy.sfp_type = txgbe_sfp_type_srlr_core0;
|
||||
else
|
||||
hw->phy.sfp_type = txgbe_sfp_type_srlr_core1;
|
||||
} else {
|
||||
if (comp_codes_10g & TXGBE_SFF_QSFP_DA_ACTIVE_CABLE)
|
||||
active_cable = true;
|
||||
|
||||
if (!active_cable) {
|
||||
hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_QSFP_CONNECTOR,
|
||||
&connector);
|
||||
|
||||
hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_QSFP_CABLE_LENGTH,
|
||||
&cable_length);
|
||||
|
||||
hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_QSFP_DEVICE_TECH,
|
||||
&device_tech);
|
||||
|
||||
if (connector ==
|
||||
TXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE &&
|
||||
cable_length > 0 &&
|
||||
((device_tech >> 4) ==
|
||||
TXGBE_SFF_QSFP_TRANSMITTER_850NM_VCSEL))
|
||||
active_cable = true;
|
||||
}
|
||||
|
||||
if (active_cable) {
|
||||
hw->phy.type = txgbe_phy_qsfp_unknown_active;
|
||||
if (hw->bus.lan_id == 0)
|
||||
hw->phy.sfp_type =
|
||||
txgbe_sfp_type_da_act_lmt_core0;
|
||||
else
|
||||
hw->phy.sfp_type =
|
||||
txgbe_sfp_type_da_act_lmt_core1;
|
||||
} else {
|
||||
/* unsupported module type */
|
||||
hw->phy.type = txgbe_phy_sfp_unsupported;
|
||||
err = TXGBE_ERR_SFP_NOT_SUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (hw->phy.sfp_type != stored_sfp_type)
|
||||
hw->phy.sfp_setup_needed = true;
|
||||
|
||||
/* Determine if the QSFP+ PHY is dual speed or not. */
|
||||
hw->phy.multispeed_fiber = false;
|
||||
if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) &&
|
||||
(comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) ||
|
||||
((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) &&
|
||||
(comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE)))
|
||||
hw->phy.multispeed_fiber = true;
|
||||
|
||||
/* Determine PHY vendor for optical modules */
|
||||
if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE |
|
||||
TXGBE_SFF_10GBASELR_CAPABLE)) {
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_QSFP_VENDOR_OUI_BYTE0,
|
||||
&oui_bytes[0]);
|
||||
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_QSFP_VENDOR_OUI_BYTE1,
|
||||
&oui_bytes[1]);
|
||||
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
err = hw->phy.read_i2c_eeprom(hw,
|
||||
TXGBE_SFF_QSFP_VENDOR_OUI_BYTE2,
|
||||
&oui_bytes[2]);
|
||||
|
||||
if (err != 0)
|
||||
goto ERR_I2C;
|
||||
|
||||
vendor_oui =
|
||||
((oui_bytes[0] << 24) |
|
||||
(oui_bytes[1] << 16) |
|
||||
(oui_bytes[2] << 8));
|
||||
|
||||
if (vendor_oui == TXGBE_SFF_VENDOR_OUI_INTEL)
|
||||
hw->phy.type = txgbe_phy_qsfp_intel;
|
||||
else
|
||||
hw->phy.type = txgbe_phy_qsfp_unknown;
|
||||
|
||||
hw->mac.get_device_caps(hw, &enforce_sfp);
|
||||
if (!(enforce_sfp & TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
|
||||
/* Make sure we're a supported PHY type */
|
||||
if (hw->phy.type == txgbe_phy_qsfp_intel) {
|
||||
err = 0;
|
||||
} else {
|
||||
if (hw->allow_unsupported_sfp) {
|
||||
DEBUGOUT("WARNING: Wangxun (R) Network Connections are quality tested using Wangxun (R) Ethernet Optics. "
|
||||
"Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. "
|
||||
"Wangxun Corporation is not responsible for any harm caused by using untested modules.\n");
|
||||
err = 0;
|
||||
} else {
|
||||
DEBUGOUT("QSFP module not supported\n");
|
||||
hw->phy.type =
|
||||
txgbe_phy_sfp_unsupported;
|
||||
err = TXGBE_ERR_SFP_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_read_i2c_eeprom - Reads 8 bit EEPROM word over I2C interface
|
||||
* @hw: pointer to hardware structure
|
||||
* @byte_offset: EEPROM byte offset to read
|
||||
* @eeprom_data: value read
|
||||
*
|
||||
* Performs byte read operation to SFP module's EEPROM over I2C interface.
|
||||
**/
|
||||
s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 *eeprom_data)
|
||||
{
|
||||
DEBUGFUNC("txgbe_read_i2c_eeprom");
|
||||
|
||||
return hw->phy.read_i2c_byte(hw, byte_offset,
|
||||
TXGBE_I2C_EEPROM_DEV_ADDR,
|
||||
eeprom_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_write_i2c_eeprom - Writes 8 bit EEPROM word over I2C interface
|
||||
* @hw: pointer to hardware structure
|
||||
* @byte_offset: EEPROM byte offset to write
|
||||
* @eeprom_data: value to write
|
||||
*
|
||||
* Performs byte write operation to SFP module's EEPROM over I2C interface.
|
||||
**/
|
||||
s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 eeprom_data)
|
||||
{
|
||||
DEBUGFUNC("txgbe_write_i2c_eeprom");
|
||||
|
||||
return hw->phy.write_i2c_byte(hw, byte_offset,
|
||||
TXGBE_I2C_EEPROM_DEV_ADDR,
|
||||
eeprom_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_read_i2c_byte_unlocked - Reads 8 bit word over I2C
|
||||
* @hw: pointer to hardware structure
|
||||
* @byte_offset: byte offset to read
|
||||
* @dev_addr: address to read from
|
||||
* @data: value read
|
||||
*
|
||||
* Performs byte read operation to SFP module's EEPROM over I2C interface at
|
||||
* a specified device address.
|
||||
**/
|
||||
s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 *data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dev_addr);
|
||||
|
||||
DEBUGFUNC("txgbe_read_i2c_byte");
|
||||
|
||||
txgbe_i2c_start(hw);
|
||||
|
||||
/* wait tx empty */
|
||||
if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_TXEMPTY,
|
||||
TXGBE_I2CICR_TXEMPTY, NULL, 100, 100)) {
|
||||
return -TERR_TIMEOUT;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
wr32(hw, TXGBE_I2CDATA,
|
||||
byte_offset | TXGBE_I2CDATA_STOP);
|
||||
wr32(hw, TXGBE_I2CDATA, TXGBE_I2CDATA_READ);
|
||||
|
||||
/* wait for read complete */
|
||||
if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_RXFULL,
|
||||
TXGBE_I2CICR_RXFULL, NULL, 100, 100)) {
|
||||
return -TERR_TIMEOUT;
|
||||
}
|
||||
|
||||
txgbe_i2c_stop(hw);
|
||||
|
||||
*data = 0xFF & rd32(hw, TXGBE_I2CDATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_read_i2c_byte - Reads 8 bit word over I2C
|
||||
* @hw: pointer to hardware structure
|
||||
* @byte_offset: byte offset to read
|
||||
* @dev_addr: address to read from
|
||||
* @data: value read
|
||||
*
|
||||
* Performs byte read operation to SFP module's EEPROM over I2C interface at
|
||||
* a specified device address.
|
||||
**/
|
||||
s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 *data)
|
||||
{
|
||||
u32 swfw_mask = hw->phy.phy_semaphore_mask;
|
||||
int err = 0;
|
||||
|
||||
if (hw->mac.acquire_swfw_sync(hw, swfw_mask))
|
||||
return TXGBE_ERR_SWFW_SYNC;
|
||||
err = txgbe_read_i2c_byte_unlocked(hw, byte_offset, dev_addr, data);
|
||||
hw->mac.release_swfw_sync(hw, swfw_mask);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_write_i2c_byte_unlocked - Writes 8 bit word over I2C
|
||||
* @hw: pointer to hardware structure
|
||||
* @byte_offset: byte offset to write
|
||||
* @dev_addr: address to write to
|
||||
* @data: value to write
|
||||
*
|
||||
* Performs byte write operation to SFP module's EEPROM over I2C interface at
|
||||
* a specified device address.
|
||||
**/
|
||||
s32 txgbe_write_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dev_addr);
|
||||
|
||||
DEBUGFUNC("txgbe_write_i2c_byte");
|
||||
|
||||
txgbe_i2c_start(hw);
|
||||
|
||||
/* wait tx empty */
|
||||
if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_TXEMPTY,
|
||||
TXGBE_I2CICR_TXEMPTY, NULL, 100, 100)) {
|
||||
return -TERR_TIMEOUT;
|
||||
}
|
||||
|
||||
wr32(hw, TXGBE_I2CDATA, byte_offset | TXGBE_I2CDATA_STOP);
|
||||
wr32(hw, TXGBE_I2CDATA, data | TXGBE_I2CDATA_WRITE);
|
||||
|
||||
/* wait for write complete */
|
||||
if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_RXFULL,
|
||||
TXGBE_I2CICR_RXFULL, NULL, 100, 100)) {
|
||||
return -TERR_TIMEOUT;
|
||||
}
|
||||
txgbe_i2c_stop(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_write_i2c_byte - Writes 8 bit word over I2C
|
||||
* @hw: pointer to hardware structure
|
||||
* @byte_offset: byte offset to write
|
||||
* @dev_addr: address to write to
|
||||
* @data: value to write
|
||||
*
|
||||
* Performs byte write operation to SFP module's EEPROM over I2C interface at
|
||||
* a specified device address.
|
||||
**/
|
||||
s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 data)
|
||||
{
|
||||
u32 swfw_mask = hw->phy.phy_semaphore_mask;
|
||||
int err = 0;
|
||||
|
||||
if (hw->mac.acquire_swfw_sync(hw, swfw_mask))
|
||||
return TXGBE_ERR_SWFW_SYNC;
|
||||
err = txgbe_write_i2c_byte_unlocked(hw, byte_offset, dev_addr, data);
|
||||
hw->mac.release_swfw_sync(hw, swfw_mask);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_i2c_start - Sets I2C start condition
|
||||
* @hw: pointer to hardware structure
|
||||
*
|
||||
* Sets I2C start condition (High -> Low on SDA while SCL is High)
|
||||
**/
|
||||
static void txgbe_i2c_start(struct txgbe_hw *hw)
|
||||
{
|
||||
DEBUGFUNC("txgbe_i2c_start");
|
||||
|
||||
wr32(hw, TXGBE_I2CENA, 0);
|
||||
|
||||
wr32(hw, TXGBE_I2CCON,
|
||||
(TXGBE_I2CCON_MENA |
|
||||
TXGBE_I2CCON_SPEED(1) |
|
||||
TXGBE_I2CCON_RESTART |
|
||||
TXGBE_I2CCON_SDIA));
|
||||
wr32(hw, TXGBE_I2CTAR, TXGBE_I2C_SLAVEADDR);
|
||||
wr32(hw, TXGBE_I2CSSSCLHCNT, 600);
|
||||
wr32(hw, TXGBE_I2CSSSCLLCNT, 600);
|
||||
wr32(hw, TXGBE_I2CRXTL, 0); /* 1byte for rx full signal */
|
||||
wr32(hw, TXGBE_I2CTXTL, 4);
|
||||
wr32(hw, TXGBE_I2CSCLTMOUT, 0xFFFFFF);
|
||||
wr32(hw, TXGBE_I2CSDATMOUT, 0xFFFFFF);
|
||||
|
||||
wr32(hw, TXGBE_I2CICM, 0);
|
||||
wr32(hw, TXGBE_I2CENA, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_i2c_stop - Sets I2C stop condition
|
||||
* @hw: pointer to hardware structure
|
||||
*
|
||||
* Sets I2C stop condition (Low -> High on SDA while SCL is High)
|
||||
**/
|
||||
static void txgbe_i2c_stop(struct txgbe_hw *hw)
|
||||
{
|
||||
DEBUGFUNC("txgbe_i2c_stop");
|
||||
|
||||
/* wait for completion */
|
||||
if (!po32m(hw, TXGBE_I2CSTAT, TXGBE_I2CSTAT_MST,
|
||||
0, NULL, 100, 100)) {
|
||||
DEBUGFUNC("i2c stop timeout.");
|
||||
}
|
||||
|
||||
wr32(hw, TXGBE_I2CENA, 0);
|
||||
}
|
||||
|
||||
|
@ -332,5 +332,17 @@ s32 txgbe_identify_phy(struct txgbe_hw *hw);
|
||||
s32 txgbe_identify_module(struct txgbe_hw *hw);
|
||||
s32 txgbe_identify_sfp_module(struct txgbe_hw *hw);
|
||||
s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw);
|
||||
s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 *data);
|
||||
s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 *data);
|
||||
s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 data);
|
||||
s32 txgbe_write_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 dev_addr, u8 data);
|
||||
s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 *eeprom_data);
|
||||
s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
|
||||
u8 eeprom_data);
|
||||
|
||||
#endif /* _TXGBE_PHY_H_ */
|
||||
|
@ -358,6 +358,7 @@ struct txgbe_phy_info {
|
||||
u32 media_type;
|
||||
u32 phy_semaphore_mask;
|
||||
bool reset_disable;
|
||||
bool multispeed_fiber;
|
||||
bool qsfp_shared_i2c_bus;
|
||||
u32 nw_mng_if_sel;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user