162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/pci.h> 562306a36Sopenharmony_ci#include <linux/delay.h> 662306a36Sopenharmony_ci#include <linux/iopoll.h> 762306a36Sopenharmony_ci#include <linux/sched.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "ixgbe.h" 1062306a36Sopenharmony_ci#include "ixgbe_phy.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic void ixgbe_i2c_start(struct ixgbe_hw *hw); 1362306a36Sopenharmony_cistatic void ixgbe_i2c_stop(struct ixgbe_hw *hw); 1462306a36Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data); 1562306a36Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data); 1662306a36Sopenharmony_cistatic s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw); 1762306a36Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data); 1862306a36Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data); 1962306a36Sopenharmony_cistatic void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); 2062306a36Sopenharmony_cistatic void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); 2162306a36Sopenharmony_cistatic s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); 2262306a36Sopenharmony_cistatic bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl); 2362306a36Sopenharmony_cistatic void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw); 2462306a36Sopenharmony_cistatic enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); 2562306a36Sopenharmony_cistatic s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); 2662306a36Sopenharmony_cistatic s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * ixgbe_out_i2c_byte_ack - Send I2C byte with ack 3062306a36Sopenharmony_ci * @hw: pointer to the hardware structure 3162306a36Sopenharmony_ci * @byte: byte to send 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Returns an error code on error. 3462306a36Sopenharmony_ci **/ 3562306a36Sopenharmony_cistatic s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci s32 status; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, byte); 4062306a36Sopenharmony_ci if (status) 4162306a36Sopenharmony_ci return status; 4262306a36Sopenharmony_ci return ixgbe_get_i2c_ack(hw); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack 4762306a36Sopenharmony_ci * @hw: pointer to the hardware structure 4862306a36Sopenharmony_ci * @byte: pointer to a u8 to receive the byte 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Returns an error code on error. 5162306a36Sopenharmony_ci **/ 5262306a36Sopenharmony_cistatic s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci s32 status; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci status = ixgbe_clock_in_i2c_byte(hw, byte); 5762306a36Sopenharmony_ci if (status) 5862306a36Sopenharmony_ci return status; 5962306a36Sopenharmony_ci /* ACK */ 6062306a36Sopenharmony_ci return ixgbe_clock_out_i2c_bit(hw, false); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/** 6462306a36Sopenharmony_ci * ixgbe_ones_comp_byte_add - Perform one's complement addition 6562306a36Sopenharmony_ci * @add1: addend 1 6662306a36Sopenharmony_ci * @add2: addend 2 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * Returns one's complement 8-bit sum. 6962306a36Sopenharmony_ci **/ 7062306a36Sopenharmony_cistatic u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci u16 sum = add1 + add2; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci sum = (sum & 0xFF) + (sum >> 8); 7562306a36Sopenharmony_ci return sum & 0xFF; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/** 7962306a36Sopenharmony_ci * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation 8062306a36Sopenharmony_ci * @hw: pointer to the hardware structure 8162306a36Sopenharmony_ci * @addr: I2C bus address to read from 8262306a36Sopenharmony_ci * @reg: I2C device register to read from 8362306a36Sopenharmony_ci * @val: pointer to location to receive read value 8462306a36Sopenharmony_ci * @lock: true if to take and release semaphore 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Returns an error code on error. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cis32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, 8962306a36Sopenharmony_ci u16 reg, u16 *val, bool lock) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 9262306a36Sopenharmony_ci int max_retry = 3; 9362306a36Sopenharmony_ci int retry = 0; 9462306a36Sopenharmony_ci u8 csum_byte; 9562306a36Sopenharmony_ci u8 high_bits; 9662306a36Sopenharmony_ci u8 low_bits; 9762306a36Sopenharmony_ci u8 reg_high; 9862306a36Sopenharmony_ci u8 csum; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci reg_high = ((reg >> 7) & 0xFE) | 1; /* Indicate read combined */ 10162306a36Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); 10262306a36Sopenharmony_ci csum = ~csum; 10362306a36Sopenharmony_ci do { 10462306a36Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 10562306a36Sopenharmony_ci return -EBUSY; 10662306a36Sopenharmony_ci ixgbe_i2c_start(hw); 10762306a36Sopenharmony_ci /* Device Address and write indication */ 10862306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, addr)) 10962306a36Sopenharmony_ci goto fail; 11062306a36Sopenharmony_ci /* Write bits 14:8 */ 11162306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg_high)) 11262306a36Sopenharmony_ci goto fail; 11362306a36Sopenharmony_ci /* Write bits 7:0 */ 11462306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) 11562306a36Sopenharmony_ci goto fail; 11662306a36Sopenharmony_ci /* Write csum */ 11762306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, csum)) 11862306a36Sopenharmony_ci goto fail; 11962306a36Sopenharmony_ci /* Re-start condition */ 12062306a36Sopenharmony_ci ixgbe_i2c_start(hw); 12162306a36Sopenharmony_ci /* Device Address and read indication */ 12262306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, addr | 1)) 12362306a36Sopenharmony_ci goto fail; 12462306a36Sopenharmony_ci /* Get upper bits */ 12562306a36Sopenharmony_ci if (ixgbe_in_i2c_byte_ack(hw, &high_bits)) 12662306a36Sopenharmony_ci goto fail; 12762306a36Sopenharmony_ci /* Get low bits */ 12862306a36Sopenharmony_ci if (ixgbe_in_i2c_byte_ack(hw, &low_bits)) 12962306a36Sopenharmony_ci goto fail; 13062306a36Sopenharmony_ci /* Get csum */ 13162306a36Sopenharmony_ci if (ixgbe_clock_in_i2c_byte(hw, &csum_byte)) 13262306a36Sopenharmony_ci goto fail; 13362306a36Sopenharmony_ci /* NACK */ 13462306a36Sopenharmony_ci if (ixgbe_clock_out_i2c_bit(hw, false)) 13562306a36Sopenharmony_ci goto fail; 13662306a36Sopenharmony_ci ixgbe_i2c_stop(hw); 13762306a36Sopenharmony_ci if (lock) 13862306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 13962306a36Sopenharmony_ci *val = (high_bits << 8) | low_bits; 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cifail: 14362306a36Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 14462306a36Sopenharmony_ci if (lock) 14562306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 14662306a36Sopenharmony_ci retry++; 14762306a36Sopenharmony_ci if (retry < max_retry) 14862306a36Sopenharmony_ci hw_dbg(hw, "I2C byte read combined error - Retry.\n"); 14962306a36Sopenharmony_ci else 15062306a36Sopenharmony_ci hw_dbg(hw, "I2C byte read combined error.\n"); 15162306a36Sopenharmony_ci } while (retry < max_retry); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return -EIO; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/** 15762306a36Sopenharmony_ci * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation 15862306a36Sopenharmony_ci * @hw: pointer to the hardware structure 15962306a36Sopenharmony_ci * @addr: I2C bus address to write to 16062306a36Sopenharmony_ci * @reg: I2C device register to write to 16162306a36Sopenharmony_ci * @val: value to write 16262306a36Sopenharmony_ci * @lock: true if to take and release semaphore 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * Returns an error code on error. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cis32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, 16762306a36Sopenharmony_ci u16 reg, u16 val, bool lock) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 17062306a36Sopenharmony_ci int max_retry = 1; 17162306a36Sopenharmony_ci int retry = 0; 17262306a36Sopenharmony_ci u8 reg_high; 17362306a36Sopenharmony_ci u8 csum; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci reg_high = (reg >> 7) & 0xFE; /* Indicate write combined */ 17662306a36Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); 17762306a36Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(csum, val >> 8); 17862306a36Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF); 17962306a36Sopenharmony_ci csum = ~csum; 18062306a36Sopenharmony_ci do { 18162306a36Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 18262306a36Sopenharmony_ci return -EBUSY; 18362306a36Sopenharmony_ci ixgbe_i2c_start(hw); 18462306a36Sopenharmony_ci /* Device Address and write indication */ 18562306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, addr)) 18662306a36Sopenharmony_ci goto fail; 18762306a36Sopenharmony_ci /* Write bits 14:8 */ 18862306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg_high)) 18962306a36Sopenharmony_ci goto fail; 19062306a36Sopenharmony_ci /* Write bits 7:0 */ 19162306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) 19262306a36Sopenharmony_ci goto fail; 19362306a36Sopenharmony_ci /* Write data 15:8 */ 19462306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, val >> 8)) 19562306a36Sopenharmony_ci goto fail; 19662306a36Sopenharmony_ci /* Write data 7:0 */ 19762306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF)) 19862306a36Sopenharmony_ci goto fail; 19962306a36Sopenharmony_ci /* Write csum */ 20062306a36Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, csum)) 20162306a36Sopenharmony_ci goto fail; 20262306a36Sopenharmony_ci ixgbe_i2c_stop(hw); 20362306a36Sopenharmony_ci if (lock) 20462306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cifail: 20862306a36Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 20962306a36Sopenharmony_ci if (lock) 21062306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 21162306a36Sopenharmony_ci retry++; 21262306a36Sopenharmony_ci if (retry < max_retry) 21362306a36Sopenharmony_ci hw_dbg(hw, "I2C byte write combined error - Retry.\n"); 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci hw_dbg(hw, "I2C byte write combined error.\n"); 21662306a36Sopenharmony_ci } while (retry < max_retry); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return -EIO; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/** 22262306a36Sopenharmony_ci * ixgbe_probe_phy - Probe a single address for a PHY 22362306a36Sopenharmony_ci * @hw: pointer to hardware structure 22462306a36Sopenharmony_ci * @phy_addr: PHY address to probe 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Returns true if PHY found 22762306a36Sopenharmony_ci **/ 22862306a36Sopenharmony_cistatic bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci u16 ext_ability = 0; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci hw->phy.mdio.prtad = phy_addr; 23362306a36Sopenharmony_ci if (mdio45_probe(&hw->phy.mdio, phy_addr) != 0) 23462306a36Sopenharmony_ci return false; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (ixgbe_get_phy_id(hw)) 23762306a36Sopenharmony_ci return false; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_unknown) { 24262306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, 24362306a36Sopenharmony_ci MDIO_PMA_EXTABLE, 24462306a36Sopenharmony_ci MDIO_MMD_PMAPMD, 24562306a36Sopenharmony_ci &ext_ability); 24662306a36Sopenharmony_ci if (ext_ability & 24762306a36Sopenharmony_ci (MDIO_PMA_EXTABLE_10GBT | 24862306a36Sopenharmony_ci MDIO_PMA_EXTABLE_1000BT)) 24962306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_cu_unknown; 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_generic; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return true; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * ixgbe_identify_phy_generic - Get physical layer module 25962306a36Sopenharmony_ci * @hw: pointer to hardware structure 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Determines the physical layer module found on the current adapter. 26262306a36Sopenharmony_ci **/ 26362306a36Sopenharmony_cis32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u32 status = -EFAULT; 26662306a36Sopenharmony_ci u32 phy_addr; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!hw->phy.phy_semaphore_mask) { 26962306a36Sopenharmony_ci if (hw->bus.lan_id) 27062306a36Sopenharmony_ci hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; 27162306a36Sopenharmony_ci else 27262306a36Sopenharmony_ci hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (hw->phy.type != ixgbe_phy_unknown) 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (hw->phy.nw_mng_if_sel) { 27962306a36Sopenharmony_ci phy_addr = (hw->phy.nw_mng_if_sel & 28062306a36Sopenharmony_ci IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >> 28162306a36Sopenharmony_ci IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT; 28262306a36Sopenharmony_ci if (ixgbe_probe_phy(hw, phy_addr)) 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci else 28562306a36Sopenharmony_ci return -EFAULT; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { 28962306a36Sopenharmony_ci if (ixgbe_probe_phy(hw, phy_addr)) { 29062306a36Sopenharmony_ci status = 0; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Certain media types do not have a phy so an address will not 29662306a36Sopenharmony_ci * be found and the code will take this path. Caller has to 29762306a36Sopenharmony_ci * decide if it is an error or not. 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci if (status) 30062306a36Sopenharmony_ci hw->phy.mdio.prtad = MDIO_PRTAD_NONE; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return status; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/** 30662306a36Sopenharmony_ci * ixgbe_check_reset_blocked - check status of MNG FW veto bit 30762306a36Sopenharmony_ci * @hw: pointer to the hardware structure 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * This function checks the MMNGC.MNG_VETO bit to see if there are 31062306a36Sopenharmony_ci * any constraints on link from manageability. For MAC's that don't 31162306a36Sopenharmony_ci * have this bit just return false since the link can not be blocked 31262306a36Sopenharmony_ci * via this method. 31362306a36Sopenharmony_ci **/ 31462306a36Sopenharmony_cibool ixgbe_check_reset_blocked(struct ixgbe_hw *hw) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci u32 mmngc; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* If we don't have this bit, it can't be blocking */ 31962306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 32062306a36Sopenharmony_ci return false; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC); 32362306a36Sopenharmony_ci if (mmngc & IXGBE_MMNGC_MNG_VETO) { 32462306a36Sopenharmony_ci hw_dbg(hw, "MNG_VETO bit detected.\n"); 32562306a36Sopenharmony_ci return true; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return false; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/** 33262306a36Sopenharmony_ci * ixgbe_get_phy_id - Get the phy type 33362306a36Sopenharmony_ci * @hw: pointer to hardware structure 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci **/ 33662306a36Sopenharmony_cistatic s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci s32 status; 33962306a36Sopenharmony_ci u16 phy_id_high = 0; 34062306a36Sopenharmony_ci u16 phy_id_low = 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD, 34362306a36Sopenharmony_ci &phy_id_high); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (!status) { 34662306a36Sopenharmony_ci hw->phy.id = (u32)(phy_id_high << 16); 34762306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_DEVID2, MDIO_MMD_PMAPMD, 34862306a36Sopenharmony_ci &phy_id_low); 34962306a36Sopenharmony_ci hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); 35062306a36Sopenharmony_ci hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci return status; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/** 35662306a36Sopenharmony_ci * ixgbe_get_phy_type_from_id - Get the phy type 35762306a36Sopenharmony_ci * @phy_id: hardware phy id 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci **/ 36062306a36Sopenharmony_cistatic enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci enum ixgbe_phy_type phy_type; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci switch (phy_id) { 36562306a36Sopenharmony_ci case TN1010_PHY_ID: 36662306a36Sopenharmony_ci phy_type = ixgbe_phy_tn; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci case X550_PHY_ID2: 36962306a36Sopenharmony_ci case X550_PHY_ID3: 37062306a36Sopenharmony_ci case X540_PHY_ID: 37162306a36Sopenharmony_ci phy_type = ixgbe_phy_aq; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case QT2022_PHY_ID: 37462306a36Sopenharmony_ci phy_type = ixgbe_phy_qt; 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case ATH_PHY_ID: 37762306a36Sopenharmony_ci phy_type = ixgbe_phy_nl; 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci case X557_PHY_ID: 38062306a36Sopenharmony_ci case X557_PHY_ID2: 38162306a36Sopenharmony_ci phy_type = ixgbe_phy_x550em_ext_t; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case BCM54616S_E_PHY_ID: 38462306a36Sopenharmony_ci phy_type = ixgbe_phy_ext_1g_t; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci default: 38762306a36Sopenharmony_ci phy_type = ixgbe_phy_unknown; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return phy_type; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/** 39562306a36Sopenharmony_ci * ixgbe_reset_phy_generic - Performs a PHY reset 39662306a36Sopenharmony_ci * @hw: pointer to hardware structure 39762306a36Sopenharmony_ci **/ 39862306a36Sopenharmony_cis32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci u32 i; 40162306a36Sopenharmony_ci u16 ctrl = 0; 40262306a36Sopenharmony_ci s32 status = 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_unknown) 40562306a36Sopenharmony_ci status = ixgbe_identify_phy_generic(hw); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (status != 0 || hw->phy.type == ixgbe_phy_none) 40862306a36Sopenharmony_ci return status; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Don't reset PHY if it's shut down due to overtemp. */ 41162306a36Sopenharmony_ci if (!hw->phy.reset_if_overtemp && hw->phy.ops.check_overtemp(hw)) 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Blocked by MNG FW so bail */ 41562306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* 41962306a36Sopenharmony_ci * Perform soft PHY reset to the PHY_XS. 42062306a36Sopenharmony_ci * This will cause a soft reset to the PHY 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, 42362306a36Sopenharmony_ci MDIO_MMD_PHYXS, 42462306a36Sopenharmony_ci MDIO_CTRL1_RESET); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * Poll for reset bit to self-clear indicating reset is complete. 42862306a36Sopenharmony_ci * Some PHYs could take up to 3 seconds to complete and need about 42962306a36Sopenharmony_ci * 1.7 usec delay after the reset is complete. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci for (i = 0; i < 30; i++) { 43262306a36Sopenharmony_ci msleep(100); 43362306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_x550em_ext_t) { 43462306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, 43562306a36Sopenharmony_ci IXGBE_MDIO_TX_VENDOR_ALARMS_3, 43662306a36Sopenharmony_ci MDIO_MMD_PMAPMD, &ctrl); 43762306a36Sopenharmony_ci if (status) 43862306a36Sopenharmony_ci return status; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) { 44162306a36Sopenharmony_ci udelay(2); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci } else { 44562306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_CTRL1, 44662306a36Sopenharmony_ci MDIO_MMD_PHYXS, &ctrl); 44762306a36Sopenharmony_ci if (status) 44862306a36Sopenharmony_ci return status; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (!(ctrl & MDIO_CTRL1_RESET)) { 45162306a36Sopenharmony_ci udelay(2); 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (ctrl & MDIO_CTRL1_RESET) { 45862306a36Sopenharmony_ci hw_dbg(hw, "PHY reset polling failed to complete.\n"); 45962306a36Sopenharmony_ci return -EIO; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci/** 46662306a36Sopenharmony_ci * ixgbe_read_phy_reg_mdi - read PHY register 46762306a36Sopenharmony_ci * @hw: pointer to hardware structure 46862306a36Sopenharmony_ci * @reg_addr: 32 bit address of PHY register to read 46962306a36Sopenharmony_ci * @device_type: 5 bit device type 47062306a36Sopenharmony_ci * @phy_data: Pointer to read data from PHY register 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * Reads a value from a specified PHY register without the SWFW lock 47362306a36Sopenharmony_ci **/ 47462306a36Sopenharmony_cis32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, 47562306a36Sopenharmony_ci u16 *phy_data) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci u32 i, data, command; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Setup and write the address cycle command */ 48062306a36Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 48162306a36Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 48262306a36Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 48362306a36Sopenharmony_ci (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Check every 10 usec to see if the address cycle completed. 48862306a36Sopenharmony_ci * The MDI Command bit will clear when the operation is 48962306a36Sopenharmony_ci * complete 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 49262306a36Sopenharmony_ci udelay(10); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 49562306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 50162306a36Sopenharmony_ci hw_dbg(hw, "PHY address command did not complete.\n"); 50262306a36Sopenharmony_ci return -EIO; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Address cycle complete, setup and write the read 50662306a36Sopenharmony_ci * command 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 50962306a36Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 51062306a36Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 51162306a36Sopenharmony_ci (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* Check every 10 usec to see if the address cycle 51662306a36Sopenharmony_ci * completed. The MDI Command bit will clear when the 51762306a36Sopenharmony_ci * operation is complete 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 52062306a36Sopenharmony_ci udelay(10); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 52362306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 52862306a36Sopenharmony_ci hw_dbg(hw, "PHY read command didn't complete\n"); 52962306a36Sopenharmony_ci return -EIO; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Read operation is complete. Get the data 53362306a36Sopenharmony_ci * from MSRWD 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 53662306a36Sopenharmony_ci data >>= IXGBE_MSRWD_READ_DATA_SHIFT; 53762306a36Sopenharmony_ci *phy_data = (u16)(data); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/** 54362306a36Sopenharmony_ci * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register 54462306a36Sopenharmony_ci * using the SWFW lock - this function is needed in most cases 54562306a36Sopenharmony_ci * @hw: pointer to hardware structure 54662306a36Sopenharmony_ci * @reg_addr: 32 bit address of PHY register to read 54762306a36Sopenharmony_ci * @device_type: 5 bit device type 54862306a36Sopenharmony_ci * @phy_data: Pointer to read data from PHY register 54962306a36Sopenharmony_ci **/ 55062306a36Sopenharmony_cis32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 55162306a36Sopenharmony_ci u32 device_type, u16 *phy_data) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci s32 status; 55462306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { 55762306a36Sopenharmony_ci status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, 55862306a36Sopenharmony_ci phy_data); 55962306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 56062306a36Sopenharmony_ci } else { 56162306a36Sopenharmony_ci return -EBUSY; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return status; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/** 56862306a36Sopenharmony_ci * ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register 56962306a36Sopenharmony_ci * without SWFW lock 57062306a36Sopenharmony_ci * @hw: pointer to hardware structure 57162306a36Sopenharmony_ci * @reg_addr: 32 bit PHY register to write 57262306a36Sopenharmony_ci * @device_type: 5 bit device type 57362306a36Sopenharmony_ci * @phy_data: Data to write to the PHY register 57462306a36Sopenharmony_ci **/ 57562306a36Sopenharmony_cis32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, 57662306a36Sopenharmony_ci u32 device_type, u16 phy_data) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci u32 i, command; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Put the data in the MDI single read and write data register*/ 58162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* Setup and write the address cycle command */ 58462306a36Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 58562306a36Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 58662306a36Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 58762306a36Sopenharmony_ci (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* 59262306a36Sopenharmony_ci * Check every 10 usec to see if the address cycle completed. 59362306a36Sopenharmony_ci * The MDI Command bit will clear when the operation is 59462306a36Sopenharmony_ci * complete 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 59762306a36Sopenharmony_ci udelay(10); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 60062306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 60562306a36Sopenharmony_ci hw_dbg(hw, "PHY address cmd didn't complete\n"); 60662306a36Sopenharmony_ci return -EIO; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* 61062306a36Sopenharmony_ci * Address cycle complete, setup and write the write 61162306a36Sopenharmony_ci * command 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 61462306a36Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 61562306a36Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 61662306a36Sopenharmony_ci (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Check every 10 usec to see if the address cycle 62162306a36Sopenharmony_ci * completed. The MDI Command bit will clear when the 62262306a36Sopenharmony_ci * operation is complete 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 62562306a36Sopenharmony_ci udelay(10); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 62862306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 63362306a36Sopenharmony_ci hw_dbg(hw, "PHY write cmd didn't complete\n"); 63462306a36Sopenharmony_ci return -EIO; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/** 64162306a36Sopenharmony_ci * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register 64262306a36Sopenharmony_ci * using SWFW lock- this function is needed in most cases 64362306a36Sopenharmony_ci * @hw: pointer to hardware structure 64462306a36Sopenharmony_ci * @reg_addr: 32 bit PHY register to write 64562306a36Sopenharmony_ci * @device_type: 5 bit device type 64662306a36Sopenharmony_ci * @phy_data: Data to write to the PHY register 64762306a36Sopenharmony_ci **/ 64862306a36Sopenharmony_cis32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 64962306a36Sopenharmony_ci u32 device_type, u16 phy_data) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci s32 status; 65262306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { 65562306a36Sopenharmony_ci status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, 65662306a36Sopenharmony_ci phy_data); 65762306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 65862306a36Sopenharmony_ci } else { 65962306a36Sopenharmony_ci return -EBUSY; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci return status; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci#define IXGBE_HW_READ_REG(addr) IXGBE_READ_REG(hw, addr) 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci/** 66862306a36Sopenharmony_ci * ixgbe_msca_cmd - Write the command register and poll for completion/timeout 66962306a36Sopenharmony_ci * @hw: pointer to hardware structure 67062306a36Sopenharmony_ci * @cmd: command register value to write 67162306a36Sopenharmony_ci **/ 67262306a36Sopenharmony_cistatic s32 ixgbe_msca_cmd(struct ixgbe_hw *hw, u32 cmd) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, cmd); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return readx_poll_timeout(IXGBE_HW_READ_REG, IXGBE_MSCA, cmd, 67762306a36Sopenharmony_ci !(cmd & IXGBE_MSCA_MDI_COMMAND), 10, 67862306a36Sopenharmony_ci 10 * IXGBE_MDIO_COMMAND_TIMEOUT); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci/** 68262306a36Sopenharmony_ci * ixgbe_mii_bus_read_generic_c22 - Read a clause 22 register with gssr flags 68362306a36Sopenharmony_ci * @hw: pointer to hardware structure 68462306a36Sopenharmony_ci * @addr: address 68562306a36Sopenharmony_ci * @regnum: register number 68662306a36Sopenharmony_ci * @gssr: semaphore flags to acquire 68762306a36Sopenharmony_ci **/ 68862306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_read_generic_c22(struct ixgbe_hw *hw, int addr, 68962306a36Sopenharmony_ci int regnum, u32 gssr) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci u32 hwaddr, cmd; 69262306a36Sopenharmony_ci s32 data; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 69562306a36Sopenharmony_ci return -EBUSY; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT; 69862306a36Sopenharmony_ci hwaddr |= (regnum & GENMASK(5, 0)) << IXGBE_MSCA_DEV_TYPE_SHIFT; 69962306a36Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_OLD_PROTOCOL | 70062306a36Sopenharmony_ci IXGBE_MSCA_READ_AUTOINC | IXGBE_MSCA_MDI_COMMAND; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci data = ixgbe_msca_cmd(hw, cmd); 70362306a36Sopenharmony_ci if (data < 0) 70462306a36Sopenharmony_ci goto mii_bus_read_done; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 70762306a36Sopenharmony_ci data = (data >> IXGBE_MSRWD_READ_DATA_SHIFT) & GENMASK(16, 0); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cimii_bus_read_done: 71062306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 71162306a36Sopenharmony_ci return data; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/** 71562306a36Sopenharmony_ci * ixgbe_mii_bus_read_generic_c45 - Read a clause 45 register with gssr flags 71662306a36Sopenharmony_ci * @hw: pointer to hardware structure 71762306a36Sopenharmony_ci * @addr: address 71862306a36Sopenharmony_ci * @devad: device address to read 71962306a36Sopenharmony_ci * @regnum: register number 72062306a36Sopenharmony_ci * @gssr: semaphore flags to acquire 72162306a36Sopenharmony_ci **/ 72262306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_read_generic_c45(struct ixgbe_hw *hw, int addr, 72362306a36Sopenharmony_ci int devad, int regnum, u32 gssr) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci u32 hwaddr, cmd; 72662306a36Sopenharmony_ci s32 data; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 72962306a36Sopenharmony_ci return -EBUSY; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT; 73262306a36Sopenharmony_ci hwaddr |= devad << 16 | regnum; 73362306a36Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci data = ixgbe_msca_cmd(hw, cmd); 73662306a36Sopenharmony_ci if (data < 0) 73762306a36Sopenharmony_ci goto mii_bus_read_done; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND; 74062306a36Sopenharmony_ci data = ixgbe_msca_cmd(hw, cmd); 74162306a36Sopenharmony_ci if (data < 0) 74262306a36Sopenharmony_ci goto mii_bus_read_done; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 74562306a36Sopenharmony_ci data = (data >> IXGBE_MSRWD_READ_DATA_SHIFT) & GENMASK(16, 0); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cimii_bus_read_done: 74862306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 74962306a36Sopenharmony_ci return data; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci/** 75362306a36Sopenharmony_ci * ixgbe_mii_bus_write_generic_c22 - Write a clause 22 register with gssr flags 75462306a36Sopenharmony_ci * @hw: pointer to hardware structure 75562306a36Sopenharmony_ci * @addr: address 75662306a36Sopenharmony_ci * @regnum: register number 75762306a36Sopenharmony_ci * @val: value to write 75862306a36Sopenharmony_ci * @gssr: semaphore flags to acquire 75962306a36Sopenharmony_ci **/ 76062306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_write_generic_c22(struct ixgbe_hw *hw, int addr, 76162306a36Sopenharmony_ci int regnum, u16 val, u32 gssr) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci u32 hwaddr, cmd; 76462306a36Sopenharmony_ci s32 err; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 76762306a36Sopenharmony_ci return -EBUSY; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)val); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT; 77262306a36Sopenharmony_ci hwaddr |= (regnum & GENMASK(5, 0)) << IXGBE_MSCA_DEV_TYPE_SHIFT; 77362306a36Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE | 77462306a36Sopenharmony_ci IXGBE_MSCA_MDI_COMMAND; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci err = ixgbe_msca_cmd(hw, cmd); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 77962306a36Sopenharmony_ci return err; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci/** 78362306a36Sopenharmony_ci * ixgbe_mii_bus_write_generic_c45 - Write a clause 45 register with gssr flags 78462306a36Sopenharmony_ci * @hw: pointer to hardware structure 78562306a36Sopenharmony_ci * @addr: address 78662306a36Sopenharmony_ci * @devad: device address to read 78762306a36Sopenharmony_ci * @regnum: register number 78862306a36Sopenharmony_ci * @val: value to write 78962306a36Sopenharmony_ci * @gssr: semaphore flags to acquire 79062306a36Sopenharmony_ci **/ 79162306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_write_generic_c45(struct ixgbe_hw *hw, int addr, 79262306a36Sopenharmony_ci int devad, int regnum, u16 val, 79362306a36Sopenharmony_ci u32 gssr) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci u32 hwaddr, cmd; 79662306a36Sopenharmony_ci s32 err; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 79962306a36Sopenharmony_ci return -EBUSY; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)val); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT; 80462306a36Sopenharmony_ci hwaddr |= devad << 16 | regnum; 80562306a36Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci err = ixgbe_msca_cmd(hw, cmd); 80862306a36Sopenharmony_ci if (err < 0) 80962306a36Sopenharmony_ci goto mii_bus_write_done; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND; 81262306a36Sopenharmony_ci err = ixgbe_msca_cmd(hw, cmd); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cimii_bus_write_done: 81562306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 81662306a36Sopenharmony_ci return err; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/** 82062306a36Sopenharmony_ci * ixgbe_mii_bus_read_c22 - Read a clause 22 register 82162306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 82262306a36Sopenharmony_ci * @addr: address 82362306a36Sopenharmony_ci * @regnum: register number 82462306a36Sopenharmony_ci **/ 82562306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_read_c22(struct mii_bus *bus, int addr, int regnum) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 82862306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 82962306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return ixgbe_mii_bus_read_generic_c22(hw, addr, regnum, gssr); 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci/** 83562306a36Sopenharmony_ci * ixgbe_mii_bus_read_c45 - Read a clause 45 register 83662306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 83762306a36Sopenharmony_ci * @devad: device address to read 83862306a36Sopenharmony_ci * @addr: address 83962306a36Sopenharmony_ci * @regnum: register number 84062306a36Sopenharmony_ci **/ 84162306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_read_c45(struct mii_bus *bus, int devad, int addr, 84262306a36Sopenharmony_ci int regnum) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 84562306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 84662306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci return ixgbe_mii_bus_read_generic_c45(hw, addr, devad, regnum, gssr); 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci/** 85262306a36Sopenharmony_ci * ixgbe_mii_bus_write_c22 - Write a clause 22 register 85362306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 85462306a36Sopenharmony_ci * @addr: address 85562306a36Sopenharmony_ci * @regnum: register number 85662306a36Sopenharmony_ci * @val: value to write 85762306a36Sopenharmony_ci **/ 85862306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_write_c22(struct mii_bus *bus, int addr, int regnum, 85962306a36Sopenharmony_ci u16 val) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 86262306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 86362306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return ixgbe_mii_bus_write_generic_c22(hw, addr, regnum, val, gssr); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/** 86962306a36Sopenharmony_ci * ixgbe_mii_bus_write_c45 - Write a clause 45 register 87062306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 87162306a36Sopenharmony_ci * @addr: address 87262306a36Sopenharmony_ci * @devad: device address to read 87362306a36Sopenharmony_ci * @regnum: register number 87462306a36Sopenharmony_ci * @val: value to write 87562306a36Sopenharmony_ci **/ 87662306a36Sopenharmony_cistatic s32 ixgbe_mii_bus_write_c45(struct mii_bus *bus, int addr, int devad, 87762306a36Sopenharmony_ci int regnum, u16 val) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 88062306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 88162306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return ixgbe_mii_bus_write_generic_c45(hw, addr, devad, regnum, val, 88462306a36Sopenharmony_ci gssr); 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/** 88862306a36Sopenharmony_ci * ixgbe_x550em_a_mii_bus_read_c22 - Read a clause 22 register on x550em_a 88962306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 89062306a36Sopenharmony_ci * @addr: address 89162306a36Sopenharmony_ci * @regnum: register number 89262306a36Sopenharmony_ci **/ 89362306a36Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_read_c22(struct mii_bus *bus, int addr, 89462306a36Sopenharmony_ci int regnum) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 89762306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 89862306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM; 90162306a36Sopenharmony_ci return ixgbe_mii_bus_read_generic_c22(hw, addr, regnum, gssr); 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci/** 90562306a36Sopenharmony_ci * ixgbe_x550em_a_mii_bus_read_c45 - Read a clause 45 register on x550em_a 90662306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 90762306a36Sopenharmony_ci * @addr: address 90862306a36Sopenharmony_ci * @devad: device address to read 90962306a36Sopenharmony_ci * @regnum: register number 91062306a36Sopenharmony_ci **/ 91162306a36Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_read_c45(struct mii_bus *bus, int addr, 91262306a36Sopenharmony_ci int devad, int regnum) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 91562306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 91662306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM; 91962306a36Sopenharmony_ci return ixgbe_mii_bus_read_generic_c45(hw, addr, devad, regnum, gssr); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/** 92362306a36Sopenharmony_ci * ixgbe_x550em_a_mii_bus_write_c22 - Write a clause 22 register on x550em_a 92462306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 92562306a36Sopenharmony_ci * @addr: address 92662306a36Sopenharmony_ci * @regnum: register number 92762306a36Sopenharmony_ci * @val: value to write 92862306a36Sopenharmony_ci **/ 92962306a36Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_write_c22(struct mii_bus *bus, int addr, 93062306a36Sopenharmony_ci int regnum, u16 val) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 93362306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 93462306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM; 93762306a36Sopenharmony_ci return ixgbe_mii_bus_write_generic_c22(hw, addr, regnum, val, gssr); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci/** 94162306a36Sopenharmony_ci * ixgbe_x550em_a_mii_bus_write_c45 - Write a clause 45 register on x550em_a 94262306a36Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 94362306a36Sopenharmony_ci * @addr: address 94462306a36Sopenharmony_ci * @devad: device address to read 94562306a36Sopenharmony_ci * @regnum: register number 94662306a36Sopenharmony_ci * @val: value to write 94762306a36Sopenharmony_ci **/ 94862306a36Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_write_c45(struct mii_bus *bus, int addr, 94962306a36Sopenharmony_ci int devad, int regnum, u16 val) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 95262306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 95362306a36Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM; 95662306a36Sopenharmony_ci return ixgbe_mii_bus_write_generic_c45(hw, addr, devad, regnum, val, 95762306a36Sopenharmony_ci gssr); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci/** 96162306a36Sopenharmony_ci * ixgbe_get_first_secondary_devfn - get first device downstream of root port 96262306a36Sopenharmony_ci * @devfn: PCI_DEVFN of root port on domain 0, bus 0 96362306a36Sopenharmony_ci * 96462306a36Sopenharmony_ci * Returns pci_dev pointer to PCI_DEVFN(0, 0) on subordinate side of root 96562306a36Sopenharmony_ci * on domain 0, bus 0, devfn = 'devfn' 96662306a36Sopenharmony_ci **/ 96762306a36Sopenharmony_cistatic struct pci_dev *ixgbe_get_first_secondary_devfn(unsigned int devfn) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct pci_dev *rp_pdev; 97062306a36Sopenharmony_ci int bus; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn); 97362306a36Sopenharmony_ci if (rp_pdev && rp_pdev->subordinate) { 97462306a36Sopenharmony_ci bus = rp_pdev->subordinate->number; 97562306a36Sopenharmony_ci pci_dev_put(rp_pdev); 97662306a36Sopenharmony_ci return pci_get_domain_bus_and_slot(0, bus, 0); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci pci_dev_put(rp_pdev); 98062306a36Sopenharmony_ci return NULL; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci/** 98462306a36Sopenharmony_ci * ixgbe_x550em_a_has_mii - is this the first ixgbe x550em_a PCI function? 98562306a36Sopenharmony_ci * @hw: pointer to hardware structure 98662306a36Sopenharmony_ci * 98762306a36Sopenharmony_ci * Returns true if hw points to lowest numbered PCI B:D.F x550_em_a device in 98862306a36Sopenharmony_ci * the SoC. There are up to 4 MACs sharing a single MDIO bus on the x550em_a, 98962306a36Sopenharmony_ci * but we only want to register one MDIO bus. 99062306a36Sopenharmony_ci **/ 99162306a36Sopenharmony_cistatic bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 99462306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 99562306a36Sopenharmony_ci struct pci_dev *func0_pdev; 99662306a36Sopenharmony_ci bool has_mii = false; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices 99962306a36Sopenharmony_ci * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0 100062306a36Sopenharmony_ci * It's not valid for function 0 to be disabled and function 1 is up, 100162306a36Sopenharmony_ci * so the lowest numbered ixgbe dev will be device 0 function 0 on one 100262306a36Sopenharmony_ci * of those two root ports 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0)); 100562306a36Sopenharmony_ci if (func0_pdev) { 100662306a36Sopenharmony_ci if (func0_pdev == pdev) 100762306a36Sopenharmony_ci has_mii = true; 100862306a36Sopenharmony_ci goto out; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0)); 101162306a36Sopenharmony_ci if (func0_pdev == pdev) 101262306a36Sopenharmony_ci has_mii = true; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ciout: 101562306a36Sopenharmony_ci pci_dev_put(func0_pdev); 101662306a36Sopenharmony_ci return has_mii; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci/** 102062306a36Sopenharmony_ci * ixgbe_mii_bus_init - mii_bus structure setup 102162306a36Sopenharmony_ci * @hw: pointer to hardware structure 102262306a36Sopenharmony_ci * 102362306a36Sopenharmony_ci * Returns 0 on success, negative on failure 102462306a36Sopenharmony_ci * 102562306a36Sopenharmony_ci * ixgbe_mii_bus_init initializes a mii_bus structure in adapter 102662306a36Sopenharmony_ci **/ 102762306a36Sopenharmony_cis32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci s32 (*write_c22)(struct mii_bus *bus, int addr, int regnum, u16 val); 103062306a36Sopenharmony_ci s32 (*read_c22)(struct mii_bus *bus, int addr, int regnum); 103162306a36Sopenharmony_ci s32 (*write_c45)(struct mii_bus *bus, int addr, int devad, int regnum, 103262306a36Sopenharmony_ci u16 val); 103362306a36Sopenharmony_ci s32 (*read_c45)(struct mii_bus *bus, int addr, int devad, int regnum); 103462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 103562306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 103662306a36Sopenharmony_ci struct device *dev = &adapter->netdev->dev; 103762306a36Sopenharmony_ci struct mii_bus *bus; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci switch (hw->device_id) { 104062306a36Sopenharmony_ci /* C3000 SoCs */ 104162306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_KR: 104262306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_KR_L: 104362306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SFP_N: 104462306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SGMII: 104562306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SGMII_L: 104662306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_10G_T: 104762306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SFP: 104862306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_1G_T: 104962306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_1G_T_L: 105062306a36Sopenharmony_ci if (!ixgbe_x550em_a_has_mii(hw)) 105162306a36Sopenharmony_ci return 0; 105262306a36Sopenharmony_ci read_c22 = ixgbe_x550em_a_mii_bus_read_c22; 105362306a36Sopenharmony_ci write_c22 = ixgbe_x550em_a_mii_bus_write_c22; 105462306a36Sopenharmony_ci read_c45 = ixgbe_x550em_a_mii_bus_read_c45; 105562306a36Sopenharmony_ci write_c45 = ixgbe_x550em_a_mii_bus_write_c45; 105662306a36Sopenharmony_ci break; 105762306a36Sopenharmony_ci default: 105862306a36Sopenharmony_ci read_c22 = ixgbe_mii_bus_read_c22; 105962306a36Sopenharmony_ci write_c22 = ixgbe_mii_bus_write_c22; 106062306a36Sopenharmony_ci read_c45 = ixgbe_mii_bus_read_c45; 106162306a36Sopenharmony_ci write_c45 = ixgbe_mii_bus_write_c45; 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci bus = devm_mdiobus_alloc(dev); 106662306a36Sopenharmony_ci if (!bus) 106762306a36Sopenharmony_ci return -ENOMEM; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci bus->read = read_c22; 107062306a36Sopenharmony_ci bus->write = write_c22; 107162306a36Sopenharmony_ci bus->read_c45 = read_c45; 107262306a36Sopenharmony_ci bus->write_c45 = write_c45; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci /* Use the position of the device in the PCI hierarchy as the id */ 107562306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mdio-%s", ixgbe_driver_name, 107662306a36Sopenharmony_ci pci_name(pdev)); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci bus->name = "ixgbe-mdio"; 107962306a36Sopenharmony_ci bus->priv = adapter; 108062306a36Sopenharmony_ci bus->parent = dev; 108162306a36Sopenharmony_ci bus->phy_mask = GENMASK(31, 0); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Support clause 22/45 natively. ixgbe_probe() sets MDIO_EMULATE_C22 108462306a36Sopenharmony_ci * unfortunately that causes some clause 22 frames to be sent with 108562306a36Sopenharmony_ci * clause 45 addressing. We don't want that. 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci adapter->mii_bus = bus; 109062306a36Sopenharmony_ci return mdiobus_register(bus); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci/** 109462306a36Sopenharmony_ci * ixgbe_setup_phy_link_generic - Set and restart autoneg 109562306a36Sopenharmony_ci * @hw: pointer to hardware structure 109662306a36Sopenharmony_ci * 109762306a36Sopenharmony_ci * Restart autonegotiation and PHY and waits for completion. 109862306a36Sopenharmony_ci **/ 109962306a36Sopenharmony_cis32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci s32 status = 0; 110262306a36Sopenharmony_ci u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; 110362306a36Sopenharmony_ci bool autoneg = false; 110462306a36Sopenharmony_ci ixgbe_link_speed speed; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* Set or unset auto-negotiation 10G advertisement */ 110962306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_10GBT_CTRL, MDIO_MMD_AN, &autoneg_reg); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G; 111262306a36Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) && 111362306a36Sopenharmony_ci (speed & IXGBE_LINK_SPEED_10GB_FULL)) 111462306a36Sopenharmony_ci autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_10GBT_CTRL, MDIO_MMD_AN, autoneg_reg); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 111962306a36Sopenharmony_ci MDIO_MMD_AN, &autoneg_reg); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550) { 112262306a36Sopenharmony_ci /* Set or unset auto-negotiation 5G advertisement */ 112362306a36Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE; 112462306a36Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) && 112562306a36Sopenharmony_ci (speed & IXGBE_LINK_SPEED_5GB_FULL)) 112662306a36Sopenharmony_ci autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Set or unset auto-negotiation 2.5G advertisement */ 112962306a36Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE; 113062306a36Sopenharmony_ci if ((hw->phy.autoneg_advertised & 113162306a36Sopenharmony_ci IXGBE_LINK_SPEED_2_5GB_FULL) && 113262306a36Sopenharmony_ci (speed & IXGBE_LINK_SPEED_2_5GB_FULL)) 113362306a36Sopenharmony_ci autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* Set or unset auto-negotiation 1G advertisement */ 113762306a36Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE; 113862306a36Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) && 113962306a36Sopenharmony_ci (speed & IXGBE_LINK_SPEED_1GB_FULL)) 114062306a36Sopenharmony_ci autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 114362306a36Sopenharmony_ci MDIO_MMD_AN, autoneg_reg); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* Set or unset auto-negotiation 100M advertisement */ 114662306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, &autoneg_reg); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci autoneg_reg &= ~(ADVERTISE_100FULL | ADVERTISE_100HALF); 114962306a36Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) && 115062306a36Sopenharmony_ci (speed & IXGBE_LINK_SPEED_100_FULL)) 115162306a36Sopenharmony_ci autoneg_reg |= ADVERTISE_100FULL; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, autoneg_reg); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* Blocked by MNG FW so don't reset PHY */ 115662306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 115762306a36Sopenharmony_ci return 0; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Restart PHY autonegotiation and wait for completion */ 116062306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, 116162306a36Sopenharmony_ci MDIO_MMD_AN, &autoneg_reg); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci autoneg_reg |= MDIO_AN_CTRL1_RESTART; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, 116662306a36Sopenharmony_ci MDIO_MMD_AN, autoneg_reg); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci return status; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci/** 117262306a36Sopenharmony_ci * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities 117362306a36Sopenharmony_ci * @hw: pointer to hardware structure 117462306a36Sopenharmony_ci * @speed: new link speed 117562306a36Sopenharmony_ci * @autoneg_wait_to_complete: unused 117662306a36Sopenharmony_ci **/ 117762306a36Sopenharmony_cis32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, 117862306a36Sopenharmony_ci ixgbe_link_speed speed, 117962306a36Sopenharmony_ci bool autoneg_wait_to_complete) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci /* Clear autoneg_advertised and set new values based on input link 118262306a36Sopenharmony_ci * speed. 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci hw->phy.autoneg_advertised = 0; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) 118762306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_5GB_FULL) 119062306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) 119362306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) 119662306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_100_FULL) 119962306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10_FULL) 120262306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* Setup link based on the new speed settings */ 120562306a36Sopenharmony_ci if (hw->phy.ops.setup_link) 120662306a36Sopenharmony_ci hw->phy.ops.setup_link(hw); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return 0; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci/** 121262306a36Sopenharmony_ci * ixgbe_get_copper_speeds_supported - Get copper link speed from phy 121362306a36Sopenharmony_ci * @hw: pointer to hardware structure 121462306a36Sopenharmony_ci * 121562306a36Sopenharmony_ci * Determines the supported link capabilities by reading the PHY auto 121662306a36Sopenharmony_ci * negotiation register. 121762306a36Sopenharmony_ci */ 121862306a36Sopenharmony_cistatic s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci u16 speed_ability; 122162306a36Sopenharmony_ci s32 status; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, 122462306a36Sopenharmony_ci &speed_ability); 122562306a36Sopenharmony_ci if (status) 122662306a36Sopenharmony_ci return status; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (speed_ability & MDIO_SPEED_10G) 122962306a36Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL; 123062306a36Sopenharmony_ci if (speed_ability & MDIO_PMA_SPEED_1000) 123162306a36Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL; 123262306a36Sopenharmony_ci if (speed_ability & MDIO_PMA_SPEED_100) 123362306a36Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci switch (hw->mac.type) { 123662306a36Sopenharmony_ci case ixgbe_mac_X550: 123762306a36Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL; 123862306a36Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL; 123962306a36Sopenharmony_ci break; 124062306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 124162306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 124262306a36Sopenharmony_ci hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL; 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci default: 124562306a36Sopenharmony_ci break; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return 0; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci/** 125262306a36Sopenharmony_ci * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities 125362306a36Sopenharmony_ci * @hw: pointer to hardware structure 125462306a36Sopenharmony_ci * @speed: pointer to link speed 125562306a36Sopenharmony_ci * @autoneg: boolean auto-negotiation value 125662306a36Sopenharmony_ci */ 125762306a36Sopenharmony_cis32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, 125862306a36Sopenharmony_ci ixgbe_link_speed *speed, 125962306a36Sopenharmony_ci bool *autoneg) 126062306a36Sopenharmony_ci{ 126162306a36Sopenharmony_ci s32 status = 0; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci *autoneg = true; 126462306a36Sopenharmony_ci if (!hw->phy.speeds_supported) 126562306a36Sopenharmony_ci status = ixgbe_get_copper_speeds_supported(hw); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci *speed = hw->phy.speeds_supported; 126862306a36Sopenharmony_ci return status; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci/** 127262306a36Sopenharmony_ci * ixgbe_check_phy_link_tnx - Determine link and speed status 127362306a36Sopenharmony_ci * @hw: pointer to hardware structure 127462306a36Sopenharmony_ci * @speed: link speed 127562306a36Sopenharmony_ci * @link_up: status of link 127662306a36Sopenharmony_ci * 127762306a36Sopenharmony_ci * Reads the VS1 register to determine if link is up and the current speed for 127862306a36Sopenharmony_ci * the PHY. 127962306a36Sopenharmony_ci **/ 128062306a36Sopenharmony_cis32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, 128162306a36Sopenharmony_ci bool *link_up) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci s32 status; 128462306a36Sopenharmony_ci u32 time_out; 128562306a36Sopenharmony_ci u32 max_time_out = 10; 128662306a36Sopenharmony_ci u16 phy_link = 0; 128762306a36Sopenharmony_ci u16 phy_speed = 0; 128862306a36Sopenharmony_ci u16 phy_data = 0; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* Initialize speed and link to default case */ 129162306a36Sopenharmony_ci *link_up = false; 129262306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_10GB_FULL; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci /* 129562306a36Sopenharmony_ci * Check current speed and link status of the PHY register. 129662306a36Sopenharmony_ci * This is a vendor specific register and may have to 129762306a36Sopenharmony_ci * be changed for other copper PHYs. 129862306a36Sopenharmony_ci */ 129962306a36Sopenharmony_ci for (time_out = 0; time_out < max_time_out; time_out++) { 130062306a36Sopenharmony_ci udelay(10); 130162306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, 130262306a36Sopenharmony_ci MDIO_STAT1, 130362306a36Sopenharmony_ci MDIO_MMD_VEND1, 130462306a36Sopenharmony_ci &phy_data); 130562306a36Sopenharmony_ci phy_link = phy_data & 130662306a36Sopenharmony_ci IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; 130762306a36Sopenharmony_ci phy_speed = phy_data & 130862306a36Sopenharmony_ci IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; 130962306a36Sopenharmony_ci if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { 131062306a36Sopenharmony_ci *link_up = true; 131162306a36Sopenharmony_ci if (phy_speed == 131262306a36Sopenharmony_ci IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) 131362306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL; 131462306a36Sopenharmony_ci break; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci return status; 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci/** 132262306a36Sopenharmony_ci * ixgbe_setup_phy_link_tnx - Set and restart autoneg 132362306a36Sopenharmony_ci * @hw: pointer to hardware structure 132462306a36Sopenharmony_ci * 132562306a36Sopenharmony_ci * Restart autonegotiation and PHY and waits for completion. 132662306a36Sopenharmony_ci * This function always returns success, this is nessary since 132762306a36Sopenharmony_ci * it is called via a function pointer that could call other 132862306a36Sopenharmony_ci * functions that could return an error. 132962306a36Sopenharmony_ci **/ 133062306a36Sopenharmony_cis32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) 133162306a36Sopenharmony_ci{ 133262306a36Sopenharmony_ci u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; 133362306a36Sopenharmony_ci bool autoneg = false; 133462306a36Sopenharmony_ci ixgbe_link_speed speed; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) { 133962306a36Sopenharmony_ci /* Set or unset auto-negotiation 10G advertisement */ 134062306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_10GBT_CTRL, 134162306a36Sopenharmony_ci MDIO_MMD_AN, 134262306a36Sopenharmony_ci &autoneg_reg); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G; 134562306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) 134662306a36Sopenharmony_ci autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_10GBT_CTRL, 134962306a36Sopenharmony_ci MDIO_MMD_AN, 135062306a36Sopenharmony_ci autoneg_reg); 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) { 135462306a36Sopenharmony_ci /* Set or unset auto-negotiation 1G advertisement */ 135562306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG, 135662306a36Sopenharmony_ci MDIO_MMD_AN, 135762306a36Sopenharmony_ci &autoneg_reg); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; 136062306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) 136162306a36Sopenharmony_ci autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG, 136462306a36Sopenharmony_ci MDIO_MMD_AN, 136562306a36Sopenharmony_ci autoneg_reg); 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_100_FULL) { 136962306a36Sopenharmony_ci /* Set or unset auto-negotiation 100M advertisement */ 137062306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, 137162306a36Sopenharmony_ci MDIO_MMD_AN, 137262306a36Sopenharmony_ci &autoneg_reg); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci autoneg_reg &= ~(ADVERTISE_100FULL | 137562306a36Sopenharmony_ci ADVERTISE_100HALF); 137662306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) 137762306a36Sopenharmony_ci autoneg_reg |= ADVERTISE_100FULL; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, 138062306a36Sopenharmony_ci MDIO_MMD_AN, 138162306a36Sopenharmony_ci autoneg_reg); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci /* Blocked by MNG FW so don't reset PHY */ 138562306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 138662306a36Sopenharmony_ci return 0; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* Restart PHY autonegotiation and wait for completion */ 138962306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, 139062306a36Sopenharmony_ci MDIO_MMD_AN, &autoneg_reg); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci autoneg_reg |= MDIO_AN_CTRL1_RESTART; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, 139562306a36Sopenharmony_ci MDIO_MMD_AN, autoneg_reg); 139662306a36Sopenharmony_ci return 0; 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci/** 140062306a36Sopenharmony_ci * ixgbe_reset_phy_nl - Performs a PHY reset 140162306a36Sopenharmony_ci * @hw: pointer to hardware structure 140262306a36Sopenharmony_ci **/ 140362306a36Sopenharmony_cis32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci u16 phy_offset, control, eword, edata, block_crc; 140662306a36Sopenharmony_ci bool end_data = false; 140762306a36Sopenharmony_ci u16 list_offset, data_offset; 140862306a36Sopenharmony_ci u16 phy_data = 0; 140962306a36Sopenharmony_ci s32 ret_val; 141062306a36Sopenharmony_ci u32 i; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Blocked by MNG FW so bail */ 141362306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 141462306a36Sopenharmony_ci return 0; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* reset the PHY and poll for completion */ 141962306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, 142062306a36Sopenharmony_ci (phy_data | MDIO_CTRL1_RESET)); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci for (i = 0; i < 100; i++) { 142362306a36Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, 142462306a36Sopenharmony_ci &phy_data); 142562306a36Sopenharmony_ci if ((phy_data & MDIO_CTRL1_RESET) == 0) 142662306a36Sopenharmony_ci break; 142762306a36Sopenharmony_ci usleep_range(10000, 20000); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if ((phy_data & MDIO_CTRL1_RESET) != 0) { 143162306a36Sopenharmony_ci hw_dbg(hw, "PHY reset did not complete.\n"); 143262306a36Sopenharmony_ci return -EIO; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* Get init offsets */ 143662306a36Sopenharmony_ci ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, 143762306a36Sopenharmony_ci &data_offset); 143862306a36Sopenharmony_ci if (ret_val) 143962306a36Sopenharmony_ci return ret_val; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); 144262306a36Sopenharmony_ci data_offset++; 144362306a36Sopenharmony_ci while (!end_data) { 144462306a36Sopenharmony_ci /* 144562306a36Sopenharmony_ci * Read control word from PHY init contents offset 144662306a36Sopenharmony_ci */ 144762306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); 144862306a36Sopenharmony_ci if (ret_val) 144962306a36Sopenharmony_ci goto err_eeprom; 145062306a36Sopenharmony_ci control = (eword & IXGBE_CONTROL_MASK_NL) >> 145162306a36Sopenharmony_ci IXGBE_CONTROL_SHIFT_NL; 145262306a36Sopenharmony_ci edata = eword & IXGBE_DATA_MASK_NL; 145362306a36Sopenharmony_ci switch (control) { 145462306a36Sopenharmony_ci case IXGBE_DELAY_NL: 145562306a36Sopenharmony_ci data_offset++; 145662306a36Sopenharmony_ci hw_dbg(hw, "DELAY: %d MS\n", edata); 145762306a36Sopenharmony_ci usleep_range(edata * 1000, edata * 2000); 145862306a36Sopenharmony_ci break; 145962306a36Sopenharmony_ci case IXGBE_DATA_NL: 146062306a36Sopenharmony_ci hw_dbg(hw, "DATA:\n"); 146162306a36Sopenharmony_ci data_offset++; 146262306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset++, 146362306a36Sopenharmony_ci &phy_offset); 146462306a36Sopenharmony_ci if (ret_val) 146562306a36Sopenharmony_ci goto err_eeprom; 146662306a36Sopenharmony_ci for (i = 0; i < edata; i++) { 146762306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset, 146862306a36Sopenharmony_ci &eword); 146962306a36Sopenharmony_ci if (ret_val) 147062306a36Sopenharmony_ci goto err_eeprom; 147162306a36Sopenharmony_ci hw->phy.ops.write_reg(hw, phy_offset, 147262306a36Sopenharmony_ci MDIO_MMD_PMAPMD, eword); 147362306a36Sopenharmony_ci hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, 147462306a36Sopenharmony_ci phy_offset); 147562306a36Sopenharmony_ci data_offset++; 147662306a36Sopenharmony_ci phy_offset++; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci break; 147962306a36Sopenharmony_ci case IXGBE_CONTROL_NL: 148062306a36Sopenharmony_ci data_offset++; 148162306a36Sopenharmony_ci hw_dbg(hw, "CONTROL:\n"); 148262306a36Sopenharmony_ci if (edata == IXGBE_CONTROL_EOL_NL) { 148362306a36Sopenharmony_ci hw_dbg(hw, "EOL\n"); 148462306a36Sopenharmony_ci end_data = true; 148562306a36Sopenharmony_ci } else if (edata == IXGBE_CONTROL_SOL_NL) { 148662306a36Sopenharmony_ci hw_dbg(hw, "SOL\n"); 148762306a36Sopenharmony_ci } else { 148862306a36Sopenharmony_ci hw_dbg(hw, "Bad control value\n"); 148962306a36Sopenharmony_ci return -EIO; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci break; 149262306a36Sopenharmony_ci default: 149362306a36Sopenharmony_ci hw_dbg(hw, "Bad control type\n"); 149462306a36Sopenharmony_ci return -EIO; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return ret_val; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cierr_eeprom: 150162306a36Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", data_offset); 150262306a36Sopenharmony_ci return -EIO; 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci/** 150662306a36Sopenharmony_ci * ixgbe_identify_module_generic - Identifies module type 150762306a36Sopenharmony_ci * @hw: pointer to hardware structure 150862306a36Sopenharmony_ci * 150962306a36Sopenharmony_ci * Determines HW type and calls appropriate function. 151062306a36Sopenharmony_ci **/ 151162306a36Sopenharmony_cis32 ixgbe_identify_module_generic(struct ixgbe_hw *hw) 151262306a36Sopenharmony_ci{ 151362306a36Sopenharmony_ci switch (hw->mac.ops.get_media_type(hw)) { 151462306a36Sopenharmony_ci case ixgbe_media_type_fiber: 151562306a36Sopenharmony_ci return ixgbe_identify_sfp_module_generic(hw); 151662306a36Sopenharmony_ci case ixgbe_media_type_fiber_qsfp: 151762306a36Sopenharmony_ci return ixgbe_identify_qsfp_module_generic(hw); 151862306a36Sopenharmony_ci default: 151962306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 152062306a36Sopenharmony_ci return -ENOENT; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci return -ENOENT; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci/** 152762306a36Sopenharmony_ci * ixgbe_identify_sfp_module_generic - Identifies SFP modules 152862306a36Sopenharmony_ci * @hw: pointer to hardware structure 152962306a36Sopenharmony_ci * 153062306a36Sopenharmony_ci * Searches for and identifies the SFP module and assigns appropriate PHY type. 153162306a36Sopenharmony_ci **/ 153262306a36Sopenharmony_cis32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 153562306a36Sopenharmony_ci s32 status; 153662306a36Sopenharmony_ci u32 vendor_oui = 0; 153762306a36Sopenharmony_ci enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; 153862306a36Sopenharmony_ci u8 identifier = 0; 153962306a36Sopenharmony_ci u8 comp_codes_1g = 0; 154062306a36Sopenharmony_ci u8 comp_codes_10g = 0; 154162306a36Sopenharmony_ci u8 oui_bytes[3] = {0, 0, 0}; 154262306a36Sopenharmony_ci u8 cable_tech = 0; 154362306a36Sopenharmony_ci u8 cable_spec = 0; 154462306a36Sopenharmony_ci u16 enforce_sfp = 0; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { 154762306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 154862306a36Sopenharmony_ci return -ENOENT; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* LAN ID is needed for sfp_type determination */ 155262306a36Sopenharmony_ci hw->mac.ops.set_lan_id(hw); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 155562306a36Sopenharmony_ci IXGBE_SFF_IDENTIFIER, 155662306a36Sopenharmony_ci &identifier); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (status) 155962306a36Sopenharmony_ci goto err_read_i2c_eeprom; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { 156262306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 156362306a36Sopenharmony_ci return -EOPNOTSUPP; 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 156662306a36Sopenharmony_ci IXGBE_SFF_1GBE_COMP_CODES, 156762306a36Sopenharmony_ci &comp_codes_1g); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (status) 157062306a36Sopenharmony_ci goto err_read_i2c_eeprom; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 157362306a36Sopenharmony_ci IXGBE_SFF_10GBE_COMP_CODES, 157462306a36Sopenharmony_ci &comp_codes_10g); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (status) 157762306a36Sopenharmony_ci goto err_read_i2c_eeprom; 157862306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 157962306a36Sopenharmony_ci IXGBE_SFF_CABLE_TECHNOLOGY, 158062306a36Sopenharmony_ci &cable_tech); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci if (status) 158362306a36Sopenharmony_ci goto err_read_i2c_eeprom; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* ID Module 158662306a36Sopenharmony_ci * ========= 158762306a36Sopenharmony_ci * 0 SFP_DA_CU 158862306a36Sopenharmony_ci * 1 SFP_SR 158962306a36Sopenharmony_ci * 2 SFP_LR 159062306a36Sopenharmony_ci * 3 SFP_DA_CORE0 - 82599-specific 159162306a36Sopenharmony_ci * 4 SFP_DA_CORE1 - 82599-specific 159262306a36Sopenharmony_ci * 5 SFP_SR/LR_CORE0 - 82599-specific 159362306a36Sopenharmony_ci * 6 SFP_SR/LR_CORE1 - 82599-specific 159462306a36Sopenharmony_ci * 7 SFP_act_lmt_DA_CORE0 - 82599-specific 159562306a36Sopenharmony_ci * 8 SFP_act_lmt_DA_CORE1 - 82599-specific 159662306a36Sopenharmony_ci * 9 SFP_1g_cu_CORE0 - 82599-specific 159762306a36Sopenharmony_ci * 10 SFP_1g_cu_CORE1 - 82599-specific 159862306a36Sopenharmony_ci * 11 SFP_1g_sx_CORE0 - 82599-specific 159962306a36Sopenharmony_ci * 12 SFP_1g_sx_CORE1 - 82599-specific 160062306a36Sopenharmony_ci */ 160162306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) { 160262306a36Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 160362306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_da_cu; 160462306a36Sopenharmony_ci else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) 160562306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_sr; 160662306a36Sopenharmony_ci else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) 160762306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_lr; 160862306a36Sopenharmony_ci else 160962306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_unknown; 161062306a36Sopenharmony_ci } else { 161162306a36Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { 161262306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 161362306a36Sopenharmony_ci hw->phy.sfp_type = 161462306a36Sopenharmony_ci ixgbe_sfp_type_da_cu_core0; 161562306a36Sopenharmony_ci else 161662306a36Sopenharmony_ci hw->phy.sfp_type = 161762306a36Sopenharmony_ci ixgbe_sfp_type_da_cu_core1; 161862306a36Sopenharmony_ci } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) { 161962306a36Sopenharmony_ci hw->phy.ops.read_i2c_eeprom( 162062306a36Sopenharmony_ci hw, IXGBE_SFF_CABLE_SPEC_COMP, 162162306a36Sopenharmony_ci &cable_spec); 162262306a36Sopenharmony_ci if (cable_spec & 162362306a36Sopenharmony_ci IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { 162462306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 162562306a36Sopenharmony_ci hw->phy.sfp_type = 162662306a36Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core0; 162762306a36Sopenharmony_ci else 162862306a36Sopenharmony_ci hw->phy.sfp_type = 162962306a36Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core1; 163062306a36Sopenharmony_ci } else { 163162306a36Sopenharmony_ci hw->phy.sfp_type = 163262306a36Sopenharmony_ci ixgbe_sfp_type_unknown; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci } else if (comp_codes_10g & 163562306a36Sopenharmony_ci (IXGBE_SFF_10GBASESR_CAPABLE | 163662306a36Sopenharmony_ci IXGBE_SFF_10GBASELR_CAPABLE)) { 163762306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 163862306a36Sopenharmony_ci hw->phy.sfp_type = 163962306a36Sopenharmony_ci ixgbe_sfp_type_srlr_core0; 164062306a36Sopenharmony_ci else 164162306a36Sopenharmony_ci hw->phy.sfp_type = 164262306a36Sopenharmony_ci ixgbe_sfp_type_srlr_core1; 164362306a36Sopenharmony_ci } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) { 164462306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 164562306a36Sopenharmony_ci hw->phy.sfp_type = 164662306a36Sopenharmony_ci ixgbe_sfp_type_1g_cu_core0; 164762306a36Sopenharmony_ci else 164862306a36Sopenharmony_ci hw->phy.sfp_type = 164962306a36Sopenharmony_ci ixgbe_sfp_type_1g_cu_core1; 165062306a36Sopenharmony_ci } else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) { 165162306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 165262306a36Sopenharmony_ci hw->phy.sfp_type = 165362306a36Sopenharmony_ci ixgbe_sfp_type_1g_sx_core0; 165462306a36Sopenharmony_ci else 165562306a36Sopenharmony_ci hw->phy.sfp_type = 165662306a36Sopenharmony_ci ixgbe_sfp_type_1g_sx_core1; 165762306a36Sopenharmony_ci } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) { 165862306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 165962306a36Sopenharmony_ci hw->phy.sfp_type = 166062306a36Sopenharmony_ci ixgbe_sfp_type_1g_lx_core0; 166162306a36Sopenharmony_ci else 166262306a36Sopenharmony_ci hw->phy.sfp_type = 166362306a36Sopenharmony_ci ixgbe_sfp_type_1g_lx_core1; 166462306a36Sopenharmony_ci } else { 166562306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_unknown; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci if (hw->phy.sfp_type != stored_sfp_type) 167062306a36Sopenharmony_ci hw->phy.sfp_setup_needed = true; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci /* Determine if the SFP+ PHY is dual speed or not. */ 167362306a36Sopenharmony_ci hw->phy.multispeed_fiber = false; 167462306a36Sopenharmony_ci if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && 167562306a36Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || 167662306a36Sopenharmony_ci ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && 167762306a36Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) 167862306a36Sopenharmony_ci hw->phy.multispeed_fiber = true; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci /* Determine PHY vendor */ 168162306a36Sopenharmony_ci if (hw->phy.type != ixgbe_phy_nl) { 168262306a36Sopenharmony_ci hw->phy.id = identifier; 168362306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 168462306a36Sopenharmony_ci IXGBE_SFF_VENDOR_OUI_BYTE0, 168562306a36Sopenharmony_ci &oui_bytes[0]); 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (status != 0) 168862306a36Sopenharmony_ci goto err_read_i2c_eeprom; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 169162306a36Sopenharmony_ci IXGBE_SFF_VENDOR_OUI_BYTE1, 169262306a36Sopenharmony_ci &oui_bytes[1]); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci if (status != 0) 169562306a36Sopenharmony_ci goto err_read_i2c_eeprom; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 169862306a36Sopenharmony_ci IXGBE_SFF_VENDOR_OUI_BYTE2, 169962306a36Sopenharmony_ci &oui_bytes[2]); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci if (status != 0) 170262306a36Sopenharmony_ci goto err_read_i2c_eeprom; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci vendor_oui = 170562306a36Sopenharmony_ci ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | 170662306a36Sopenharmony_ci (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | 170762306a36Sopenharmony_ci (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci switch (vendor_oui) { 171062306a36Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_TYCO: 171162306a36Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 171262306a36Sopenharmony_ci hw->phy.type = 171362306a36Sopenharmony_ci ixgbe_phy_sfp_passive_tyco; 171462306a36Sopenharmony_ci break; 171562306a36Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_FTL: 171662306a36Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) 171762306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_ftl_active; 171862306a36Sopenharmony_ci else 171962306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_ftl; 172062306a36Sopenharmony_ci break; 172162306a36Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_AVAGO: 172262306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_avago; 172362306a36Sopenharmony_ci break; 172462306a36Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_INTEL: 172562306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_intel; 172662306a36Sopenharmony_ci break; 172762306a36Sopenharmony_ci default: 172862306a36Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 172962306a36Sopenharmony_ci hw->phy.type = 173062306a36Sopenharmony_ci ixgbe_phy_sfp_passive_unknown; 173162306a36Sopenharmony_ci else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) 173262306a36Sopenharmony_ci hw->phy.type = 173362306a36Sopenharmony_ci ixgbe_phy_sfp_active_unknown; 173462306a36Sopenharmony_ci else 173562306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unknown; 173662306a36Sopenharmony_ci break; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci /* Allow any DA cable vendor */ 174162306a36Sopenharmony_ci if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | 174262306a36Sopenharmony_ci IXGBE_SFF_DA_ACTIVE_CABLE)) 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci /* Verify supported 1G SFP modules */ 174662306a36Sopenharmony_ci if (comp_codes_10g == 0 && 174762306a36Sopenharmony_ci !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 174862306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 174962306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 175062306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 175162306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 175262306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { 175362306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 175462306a36Sopenharmony_ci return -EOPNOTSUPP; 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci /* Anything else 82598-based is supported */ 175862306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 175962306a36Sopenharmony_ci return 0; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci hw->mac.ops.get_device_caps(hw, &enforce_sfp); 176262306a36Sopenharmony_ci if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && 176362306a36Sopenharmony_ci !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 176462306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 176562306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 176662306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 176762306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 176862306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { 176962306a36Sopenharmony_ci /* Make sure we're a supported PHY type */ 177062306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_sfp_intel) 177162306a36Sopenharmony_ci return 0; 177262306a36Sopenharmony_ci if (hw->allow_unsupported_sfp) { 177362306a36Sopenharmony_ci e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); 177462306a36Sopenharmony_ci return 0; 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci hw_dbg(hw, "SFP+ module not supported\n"); 177762306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 177862306a36Sopenharmony_ci return -EOPNOTSUPP; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci return 0; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cierr_read_i2c_eeprom: 178362306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 178462306a36Sopenharmony_ci if (hw->phy.type != ixgbe_phy_nl) { 178562306a36Sopenharmony_ci hw->phy.id = 0; 178662306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_unknown; 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci return -ENOENT; 178962306a36Sopenharmony_ci} 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci/** 179262306a36Sopenharmony_ci * ixgbe_identify_qsfp_module_generic - Identifies QSFP modules 179362306a36Sopenharmony_ci * @hw: pointer to hardware structure 179462306a36Sopenharmony_ci * 179562306a36Sopenharmony_ci * Searches for and identifies the QSFP module and assigns appropriate PHY type 179662306a36Sopenharmony_ci **/ 179762306a36Sopenharmony_cistatic s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 180062306a36Sopenharmony_ci s32 status; 180162306a36Sopenharmony_ci u32 vendor_oui = 0; 180262306a36Sopenharmony_ci enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; 180362306a36Sopenharmony_ci u8 identifier = 0; 180462306a36Sopenharmony_ci u8 comp_codes_1g = 0; 180562306a36Sopenharmony_ci u8 comp_codes_10g = 0; 180662306a36Sopenharmony_ci u8 oui_bytes[3] = {0, 0, 0}; 180762306a36Sopenharmony_ci u16 enforce_sfp = 0; 180862306a36Sopenharmony_ci u8 connector = 0; 180962306a36Sopenharmony_ci u8 cable_length = 0; 181062306a36Sopenharmony_ci u8 device_tech = 0; 181162306a36Sopenharmony_ci bool active_cable = false; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) { 181462306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 181562306a36Sopenharmony_ci return -ENOENT; 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci /* LAN ID is needed for sfp_type determination */ 181962306a36Sopenharmony_ci hw->mac.ops.set_lan_id(hw); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, 182262306a36Sopenharmony_ci &identifier); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci if (status != 0) 182562306a36Sopenharmony_ci goto err_read_i2c_eeprom; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) { 182862306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 182962306a36Sopenharmony_ci return -EOPNOTSUPP; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci hw->phy.id = identifier; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP, 183562306a36Sopenharmony_ci &comp_codes_10g); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci if (status != 0) 183862306a36Sopenharmony_ci goto err_read_i2c_eeprom; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_1GBE_COMP, 184162306a36Sopenharmony_ci &comp_codes_1g); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci if (status != 0) 184462306a36Sopenharmony_ci goto err_read_i2c_eeprom; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) { 184762306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_passive_unknown; 184862306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 184962306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; 185062306a36Sopenharmony_ci else 185162306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1; 185262306a36Sopenharmony_ci } else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | 185362306a36Sopenharmony_ci IXGBE_SFF_10GBASELR_CAPABLE)) { 185462306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 185562306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0; 185662306a36Sopenharmony_ci else 185762306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1; 185862306a36Sopenharmony_ci } else { 185962306a36Sopenharmony_ci if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE) 186062306a36Sopenharmony_ci active_cable = true; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci if (!active_cable) { 186362306a36Sopenharmony_ci /* check for active DA cables that pre-date 186462306a36Sopenharmony_ci * SFF-8436 v3.6 186562306a36Sopenharmony_ci */ 186662306a36Sopenharmony_ci hw->phy.ops.read_i2c_eeprom(hw, 186762306a36Sopenharmony_ci IXGBE_SFF_QSFP_CONNECTOR, 186862306a36Sopenharmony_ci &connector); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci hw->phy.ops.read_i2c_eeprom(hw, 187162306a36Sopenharmony_ci IXGBE_SFF_QSFP_CABLE_LENGTH, 187262306a36Sopenharmony_ci &cable_length); 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci hw->phy.ops.read_i2c_eeprom(hw, 187562306a36Sopenharmony_ci IXGBE_SFF_QSFP_DEVICE_TECH, 187662306a36Sopenharmony_ci &device_tech); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if ((connector == 187962306a36Sopenharmony_ci IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE) && 188062306a36Sopenharmony_ci (cable_length > 0) && 188162306a36Sopenharmony_ci ((device_tech >> 4) == 188262306a36Sopenharmony_ci IXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL)) 188362306a36Sopenharmony_ci active_cable = true; 188462306a36Sopenharmony_ci } 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci if (active_cable) { 188762306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_active_unknown; 188862306a36Sopenharmony_ci if (hw->bus.lan_id == 0) 188962306a36Sopenharmony_ci hw->phy.sfp_type = 189062306a36Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core0; 189162306a36Sopenharmony_ci else 189262306a36Sopenharmony_ci hw->phy.sfp_type = 189362306a36Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core1; 189462306a36Sopenharmony_ci } else { 189562306a36Sopenharmony_ci /* unsupported module type */ 189662306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 189762306a36Sopenharmony_ci return -EOPNOTSUPP; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if (hw->phy.sfp_type != stored_sfp_type) 190262306a36Sopenharmony_ci hw->phy.sfp_setup_needed = true; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci /* Determine if the QSFP+ PHY is dual speed or not. */ 190562306a36Sopenharmony_ci hw->phy.multispeed_fiber = false; 190662306a36Sopenharmony_ci if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && 190762306a36Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || 190862306a36Sopenharmony_ci ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && 190962306a36Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) 191062306a36Sopenharmony_ci hw->phy.multispeed_fiber = true; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci /* Determine PHY vendor for optical modules */ 191362306a36Sopenharmony_ci if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | 191462306a36Sopenharmony_ci IXGBE_SFF_10GBASELR_CAPABLE)) { 191562306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 191662306a36Sopenharmony_ci IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0, 191762306a36Sopenharmony_ci &oui_bytes[0]); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (status != 0) 192062306a36Sopenharmony_ci goto err_read_i2c_eeprom; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 192362306a36Sopenharmony_ci IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1, 192462306a36Sopenharmony_ci &oui_bytes[1]); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci if (status != 0) 192762306a36Sopenharmony_ci goto err_read_i2c_eeprom; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 193062306a36Sopenharmony_ci IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2, 193162306a36Sopenharmony_ci &oui_bytes[2]); 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci if (status != 0) 193462306a36Sopenharmony_ci goto err_read_i2c_eeprom; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci vendor_oui = 193762306a36Sopenharmony_ci ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | 193862306a36Sopenharmony_ci (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | 193962306a36Sopenharmony_ci (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL) 194262306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_intel; 194362306a36Sopenharmony_ci else 194462306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_unknown; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci hw->mac.ops.get_device_caps(hw, &enforce_sfp); 194762306a36Sopenharmony_ci if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { 194862306a36Sopenharmony_ci /* Make sure we're a supported PHY type */ 194962306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_qsfp_intel) 195062306a36Sopenharmony_ci return 0; 195162306a36Sopenharmony_ci if (hw->allow_unsupported_sfp) { 195262306a36Sopenharmony_ci e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); 195362306a36Sopenharmony_ci return 0; 195462306a36Sopenharmony_ci } 195562306a36Sopenharmony_ci hw_dbg(hw, "QSFP module not supported\n"); 195662306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 195762306a36Sopenharmony_ci return -EOPNOTSUPP; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci return 0; 196062306a36Sopenharmony_ci } 196162306a36Sopenharmony_ci return 0; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_cierr_read_i2c_eeprom: 196462306a36Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 196562306a36Sopenharmony_ci hw->phy.id = 0; 196662306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_unknown; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci return -ENOENT; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci/** 197262306a36Sopenharmony_ci * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence 197362306a36Sopenharmony_ci * @hw: pointer to hardware structure 197462306a36Sopenharmony_ci * @list_offset: offset to the SFP ID list 197562306a36Sopenharmony_ci * @data_offset: offset to the SFP data block 197662306a36Sopenharmony_ci * 197762306a36Sopenharmony_ci * Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if 197862306a36Sopenharmony_ci * so it returns the offsets to the phy init sequence block. 197962306a36Sopenharmony_ci **/ 198062306a36Sopenharmony_cis32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, 198162306a36Sopenharmony_ci u16 *list_offset, 198262306a36Sopenharmony_ci u16 *data_offset) 198362306a36Sopenharmony_ci{ 198462306a36Sopenharmony_ci u16 sfp_id; 198562306a36Sopenharmony_ci u16 sfp_type = hw->phy.sfp_type; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) 198862306a36Sopenharmony_ci return -EOPNOTSUPP; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) 199162306a36Sopenharmony_ci return -ENOENT; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && 199462306a36Sopenharmony_ci (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) 199562306a36Sopenharmony_ci return -EOPNOTSUPP; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci /* 199862306a36Sopenharmony_ci * Limiting active cables and 1G Phys must be initialized as 199962306a36Sopenharmony_ci * SR modules 200062306a36Sopenharmony_ci */ 200162306a36Sopenharmony_ci if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 || 200262306a36Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_lx_core0 || 200362306a36Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_cu_core0 || 200462306a36Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_sx_core0) 200562306a36Sopenharmony_ci sfp_type = ixgbe_sfp_type_srlr_core0; 200662306a36Sopenharmony_ci else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 || 200762306a36Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_lx_core1 || 200862306a36Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_cu_core1 || 200962306a36Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_sx_core1) 201062306a36Sopenharmony_ci sfp_type = ixgbe_sfp_type_srlr_core1; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci /* Read offset to PHY init contents */ 201362306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) { 201462306a36Sopenharmony_ci hw_err(hw, "eeprom read at %d failed\n", 201562306a36Sopenharmony_ci IXGBE_PHY_INIT_OFFSET_NL); 201662306a36Sopenharmony_ci return -EIO; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci if ((!*list_offset) || (*list_offset == 0xFFFF)) 202062306a36Sopenharmony_ci return -EIO; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci /* Shift offset to first ID word */ 202362306a36Sopenharmony_ci (*list_offset)++; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci /* 202662306a36Sopenharmony_ci * Find the matching SFP ID in the EEPROM 202762306a36Sopenharmony_ci * and program the init sequence 202862306a36Sopenharmony_ci */ 202962306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) 203062306a36Sopenharmony_ci goto err_phy; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci while (sfp_id != IXGBE_PHY_INIT_END_NL) { 203362306a36Sopenharmony_ci if (sfp_id == sfp_type) { 203462306a36Sopenharmony_ci (*list_offset)++; 203562306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, *list_offset, data_offset)) 203662306a36Sopenharmony_ci goto err_phy; 203762306a36Sopenharmony_ci if ((!*data_offset) || (*data_offset == 0xFFFF)) { 203862306a36Sopenharmony_ci hw_dbg(hw, "SFP+ module not supported\n"); 203962306a36Sopenharmony_ci return -EOPNOTSUPP; 204062306a36Sopenharmony_ci } else { 204162306a36Sopenharmony_ci break; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci } else { 204462306a36Sopenharmony_ci (*list_offset) += 2; 204562306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) 204662306a36Sopenharmony_ci goto err_phy; 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci if (sfp_id == IXGBE_PHY_INIT_END_NL) { 205162306a36Sopenharmony_ci hw_dbg(hw, "No matching SFP+ module found\n"); 205262306a36Sopenharmony_ci return -EOPNOTSUPP; 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci return 0; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_cierr_phy: 205862306a36Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", *list_offset); 205962306a36Sopenharmony_ci return -EIO; 206062306a36Sopenharmony_ci} 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci/** 206362306a36Sopenharmony_ci * ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface 206462306a36Sopenharmony_ci * @hw: pointer to hardware structure 206562306a36Sopenharmony_ci * @byte_offset: EEPROM byte offset to read 206662306a36Sopenharmony_ci * @eeprom_data: value read 206762306a36Sopenharmony_ci * 206862306a36Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface. 206962306a36Sopenharmony_ci **/ 207062306a36Sopenharmony_cis32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, 207162306a36Sopenharmony_ci u8 *eeprom_data) 207262306a36Sopenharmony_ci{ 207362306a36Sopenharmony_ci return hw->phy.ops.read_i2c_byte(hw, byte_offset, 207462306a36Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR, 207562306a36Sopenharmony_ci eeprom_data); 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci/** 207962306a36Sopenharmony_ci * ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface 208062306a36Sopenharmony_ci * @hw: pointer to hardware structure 208162306a36Sopenharmony_ci * @byte_offset: byte offset at address 0xA2 208262306a36Sopenharmony_ci * @sff8472_data: value read 208362306a36Sopenharmony_ci * 208462306a36Sopenharmony_ci * Performs byte read operation to SFP module's SFF-8472 data over I2C 208562306a36Sopenharmony_ci **/ 208662306a36Sopenharmony_cis32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, 208762306a36Sopenharmony_ci u8 *sff8472_data) 208862306a36Sopenharmony_ci{ 208962306a36Sopenharmony_ci return hw->phy.ops.read_i2c_byte(hw, byte_offset, 209062306a36Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR2, 209162306a36Sopenharmony_ci sff8472_data); 209262306a36Sopenharmony_ci} 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci/** 209562306a36Sopenharmony_ci * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface 209662306a36Sopenharmony_ci * @hw: pointer to hardware structure 209762306a36Sopenharmony_ci * @byte_offset: EEPROM byte offset to write 209862306a36Sopenharmony_ci * @eeprom_data: value to write 209962306a36Sopenharmony_ci * 210062306a36Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface. 210162306a36Sopenharmony_ci **/ 210262306a36Sopenharmony_cis32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, 210362306a36Sopenharmony_ci u8 eeprom_data) 210462306a36Sopenharmony_ci{ 210562306a36Sopenharmony_ci return hw->phy.ops.write_i2c_byte(hw, byte_offset, 210662306a36Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR, 210762306a36Sopenharmony_ci eeprom_data); 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci/** 211162306a36Sopenharmony_ci * ixgbe_is_sfp_probe - Returns true if SFP is being detected 211262306a36Sopenharmony_ci * @hw: pointer to hardware structure 211362306a36Sopenharmony_ci * @offset: eeprom offset to be read 211462306a36Sopenharmony_ci * @addr: I2C address to be read 211562306a36Sopenharmony_ci */ 211662306a36Sopenharmony_cistatic bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr) 211762306a36Sopenharmony_ci{ 211862306a36Sopenharmony_ci if (addr == IXGBE_I2C_EEPROM_DEV_ADDR && 211962306a36Sopenharmony_ci offset == IXGBE_SFF_IDENTIFIER && 212062306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_not_present) 212162306a36Sopenharmony_ci return true; 212262306a36Sopenharmony_ci return false; 212362306a36Sopenharmony_ci} 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci/** 212662306a36Sopenharmony_ci * ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C 212762306a36Sopenharmony_ci * @hw: pointer to hardware structure 212862306a36Sopenharmony_ci * @byte_offset: byte offset to read 212962306a36Sopenharmony_ci * @dev_addr: device address 213062306a36Sopenharmony_ci * @data: value read 213162306a36Sopenharmony_ci * @lock: true if to take and release semaphore 213262306a36Sopenharmony_ci * 213362306a36Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 213462306a36Sopenharmony_ci * a specified device address. 213562306a36Sopenharmony_ci */ 213662306a36Sopenharmony_cistatic s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, 213762306a36Sopenharmony_ci u8 dev_addr, u8 *data, bool lock) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci s32 status; 214062306a36Sopenharmony_ci u32 max_retry = 10; 214162306a36Sopenharmony_ci u32 retry = 0; 214262306a36Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 214362306a36Sopenharmony_ci bool nack = true; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_X550) 214662306a36Sopenharmony_ci max_retry = 3; 214762306a36Sopenharmony_ci if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr)) 214862306a36Sopenharmony_ci max_retry = IXGBE_SFP_DETECT_RETRIES; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci *data = 0; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci do { 215362306a36Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 215462306a36Sopenharmony_ci return -EBUSY; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci ixgbe_i2c_start(hw); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci /* Device Address and write indication */ 215962306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, dev_addr); 216062306a36Sopenharmony_ci if (status != 0) 216162306a36Sopenharmony_ci goto fail; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 216462306a36Sopenharmony_ci if (status != 0) 216562306a36Sopenharmony_ci goto fail; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, byte_offset); 216862306a36Sopenharmony_ci if (status != 0) 216962306a36Sopenharmony_ci goto fail; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 217262306a36Sopenharmony_ci if (status != 0) 217362306a36Sopenharmony_ci goto fail; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci ixgbe_i2c_start(hw); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci /* Device Address and read indication */ 217862306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1)); 217962306a36Sopenharmony_ci if (status != 0) 218062306a36Sopenharmony_ci goto fail; 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 218362306a36Sopenharmony_ci if (status != 0) 218462306a36Sopenharmony_ci goto fail; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci status = ixgbe_clock_in_i2c_byte(hw, data); 218762306a36Sopenharmony_ci if (status != 0) 218862306a36Sopenharmony_ci goto fail; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_bit(hw, nack); 219162306a36Sopenharmony_ci if (status != 0) 219262306a36Sopenharmony_ci goto fail; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci ixgbe_i2c_stop(hw); 219562306a36Sopenharmony_ci if (lock) 219662306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 219762306a36Sopenharmony_ci return 0; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cifail: 220062306a36Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 220162306a36Sopenharmony_ci if (lock) { 220262306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 220362306a36Sopenharmony_ci msleep(100); 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci retry++; 220662306a36Sopenharmony_ci if (retry < max_retry) 220762306a36Sopenharmony_ci hw_dbg(hw, "I2C byte read error - Retrying.\n"); 220862306a36Sopenharmony_ci else 220962306a36Sopenharmony_ci hw_dbg(hw, "I2C byte read error.\n"); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci } while (retry < max_retry); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci return status; 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci/** 221762306a36Sopenharmony_ci * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C 221862306a36Sopenharmony_ci * @hw: pointer to hardware structure 221962306a36Sopenharmony_ci * @byte_offset: byte offset to read 222062306a36Sopenharmony_ci * @dev_addr: device address 222162306a36Sopenharmony_ci * @data: value read 222262306a36Sopenharmony_ci * 222362306a36Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 222462306a36Sopenharmony_ci * a specified device address. 222562306a36Sopenharmony_ci */ 222662306a36Sopenharmony_cis32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, 222762306a36Sopenharmony_ci u8 dev_addr, u8 *data) 222862306a36Sopenharmony_ci{ 222962306a36Sopenharmony_ci return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, 223062306a36Sopenharmony_ci data, true); 223162306a36Sopenharmony_ci} 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci/** 223462306a36Sopenharmony_ci * ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C 223562306a36Sopenharmony_ci * @hw: pointer to hardware structure 223662306a36Sopenharmony_ci * @byte_offset: byte offset to read 223762306a36Sopenharmony_ci * @dev_addr: device address 223862306a36Sopenharmony_ci * @data: value read 223962306a36Sopenharmony_ci * 224062306a36Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 224162306a36Sopenharmony_ci * a specified device address. 224262306a36Sopenharmony_ci */ 224362306a36Sopenharmony_cis32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, 224462306a36Sopenharmony_ci u8 dev_addr, u8 *data) 224562306a36Sopenharmony_ci{ 224662306a36Sopenharmony_ci return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, 224762306a36Sopenharmony_ci data, false); 224862306a36Sopenharmony_ci} 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci/** 225162306a36Sopenharmony_ci * ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C 225262306a36Sopenharmony_ci * @hw: pointer to hardware structure 225362306a36Sopenharmony_ci * @byte_offset: byte offset to write 225462306a36Sopenharmony_ci * @dev_addr: device address 225562306a36Sopenharmony_ci * @data: value to write 225662306a36Sopenharmony_ci * @lock: true if to take and release semaphore 225762306a36Sopenharmony_ci * 225862306a36Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 225962306a36Sopenharmony_ci * a specified device address. 226062306a36Sopenharmony_ci */ 226162306a36Sopenharmony_cistatic s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, 226262306a36Sopenharmony_ci u8 dev_addr, u8 data, bool lock) 226362306a36Sopenharmony_ci{ 226462306a36Sopenharmony_ci s32 status; 226562306a36Sopenharmony_ci u32 max_retry = 1; 226662306a36Sopenharmony_ci u32 retry = 0; 226762306a36Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 227062306a36Sopenharmony_ci return -EBUSY; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci do { 227362306a36Sopenharmony_ci ixgbe_i2c_start(hw); 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, dev_addr); 227662306a36Sopenharmony_ci if (status != 0) 227762306a36Sopenharmony_ci goto fail; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 228062306a36Sopenharmony_ci if (status != 0) 228162306a36Sopenharmony_ci goto fail; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, byte_offset); 228462306a36Sopenharmony_ci if (status != 0) 228562306a36Sopenharmony_ci goto fail; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 228862306a36Sopenharmony_ci if (status != 0) 228962306a36Sopenharmony_ci goto fail; 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, data); 229262306a36Sopenharmony_ci if (status != 0) 229362306a36Sopenharmony_ci goto fail; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 229662306a36Sopenharmony_ci if (status != 0) 229762306a36Sopenharmony_ci goto fail; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci ixgbe_i2c_stop(hw); 230062306a36Sopenharmony_ci if (lock) 230162306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 230262306a36Sopenharmony_ci return 0; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_cifail: 230562306a36Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 230662306a36Sopenharmony_ci retry++; 230762306a36Sopenharmony_ci if (retry < max_retry) 230862306a36Sopenharmony_ci hw_dbg(hw, "I2C byte write error - Retrying.\n"); 230962306a36Sopenharmony_ci else 231062306a36Sopenharmony_ci hw_dbg(hw, "I2C byte write error.\n"); 231162306a36Sopenharmony_ci } while (retry < max_retry); 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci if (lock) 231462306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci return status; 231762306a36Sopenharmony_ci} 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci/** 232062306a36Sopenharmony_ci * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C 232162306a36Sopenharmony_ci * @hw: pointer to hardware structure 232262306a36Sopenharmony_ci * @byte_offset: byte offset to write 232362306a36Sopenharmony_ci * @dev_addr: device address 232462306a36Sopenharmony_ci * @data: value to write 232562306a36Sopenharmony_ci * 232662306a36Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 232762306a36Sopenharmony_ci * a specified device address. 232862306a36Sopenharmony_ci */ 232962306a36Sopenharmony_cis32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, 233062306a36Sopenharmony_ci u8 dev_addr, u8 data) 233162306a36Sopenharmony_ci{ 233262306a36Sopenharmony_ci return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, 233362306a36Sopenharmony_ci data, true); 233462306a36Sopenharmony_ci} 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci/** 233762306a36Sopenharmony_ci * ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C 233862306a36Sopenharmony_ci * @hw: pointer to hardware structure 233962306a36Sopenharmony_ci * @byte_offset: byte offset to write 234062306a36Sopenharmony_ci * @dev_addr: device address 234162306a36Sopenharmony_ci * @data: value to write 234262306a36Sopenharmony_ci * 234362306a36Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 234462306a36Sopenharmony_ci * a specified device address. 234562306a36Sopenharmony_ci */ 234662306a36Sopenharmony_cis32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, 234762306a36Sopenharmony_ci u8 dev_addr, u8 data) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, 235062306a36Sopenharmony_ci data, false); 235162306a36Sopenharmony_ci} 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci/** 235462306a36Sopenharmony_ci * ixgbe_i2c_start - Sets I2C start condition 235562306a36Sopenharmony_ci * @hw: pointer to hardware structure 235662306a36Sopenharmony_ci * 235762306a36Sopenharmony_ci * Sets I2C start condition (High -> Low on SDA while SCL is High) 235862306a36Sopenharmony_ci * Set bit-bang mode on X550 hardware. 235962306a36Sopenharmony_ci **/ 236062306a36Sopenharmony_cistatic void ixgbe_i2c_start(struct ixgbe_hw *hw) 236162306a36Sopenharmony_ci{ 236262306a36Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci i2cctl |= IXGBE_I2C_BB_EN(hw); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci /* Start condition must begin with data and clock high */ 236762306a36Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 1); 236862306a36Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* Setup time for start condition (4.7us) */ 237162306a36Sopenharmony_ci udelay(IXGBE_I2C_T_SU_STA); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 0); 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci /* Hold time for start condition (4us) */ 237662306a36Sopenharmony_ci udelay(IXGBE_I2C_T_HD_STA); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci /* Minimum low period of clock is 4.7 us */ 238162306a36Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci} 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci/** 238662306a36Sopenharmony_ci * ixgbe_i2c_stop - Sets I2C stop condition 238762306a36Sopenharmony_ci * @hw: pointer to hardware structure 238862306a36Sopenharmony_ci * 238962306a36Sopenharmony_ci * Sets I2C stop condition (Low -> High on SDA while SCL is High) 239062306a36Sopenharmony_ci * Disables bit-bang mode and negates data output enable on X550 239162306a36Sopenharmony_ci * hardware. 239262306a36Sopenharmony_ci **/ 239362306a36Sopenharmony_cistatic void ixgbe_i2c_stop(struct ixgbe_hw *hw) 239462306a36Sopenharmony_ci{ 239562306a36Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 239662306a36Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 239762306a36Sopenharmony_ci u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw); 239862306a36Sopenharmony_ci u32 bb_en_bit = IXGBE_I2C_BB_EN(hw); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci /* Stop condition must begin with data low and clock high */ 240162306a36Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 0); 240262306a36Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci /* Setup time for stop condition (4us) */ 240562306a36Sopenharmony_ci udelay(IXGBE_I2C_T_SU_STO); 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 1); 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci /* bus free time between stop and start (4.7us)*/ 241062306a36Sopenharmony_ci udelay(IXGBE_I2C_T_BUF); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci if (bb_en_bit || data_oe_bit || clk_oe_bit) { 241362306a36Sopenharmony_ci i2cctl &= ~bb_en_bit; 241462306a36Sopenharmony_ci i2cctl |= data_oe_bit | clk_oe_bit; 241562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 241662306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci/** 242162306a36Sopenharmony_ci * ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C 242262306a36Sopenharmony_ci * @hw: pointer to hardware structure 242362306a36Sopenharmony_ci * @data: data byte to clock in 242462306a36Sopenharmony_ci * 242562306a36Sopenharmony_ci * Clocks in one byte data via I2C data/clock 242662306a36Sopenharmony_ci **/ 242762306a36Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) 242862306a36Sopenharmony_ci{ 242962306a36Sopenharmony_ci s32 i; 243062306a36Sopenharmony_ci bool bit = false; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci *data = 0; 243362306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 243462306a36Sopenharmony_ci ixgbe_clock_in_i2c_bit(hw, &bit); 243562306a36Sopenharmony_ci *data |= bit << i; 243662306a36Sopenharmony_ci } 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci return 0; 243962306a36Sopenharmony_ci} 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci/** 244262306a36Sopenharmony_ci * ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C 244362306a36Sopenharmony_ci * @hw: pointer to hardware structure 244462306a36Sopenharmony_ci * @data: data byte clocked out 244562306a36Sopenharmony_ci * 244662306a36Sopenharmony_ci * Clocks out one byte data via I2C data/clock 244762306a36Sopenharmony_ci **/ 244862306a36Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) 244962306a36Sopenharmony_ci{ 245062306a36Sopenharmony_ci s32 status; 245162306a36Sopenharmony_ci s32 i; 245262306a36Sopenharmony_ci u32 i2cctl; 245362306a36Sopenharmony_ci bool bit = false; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 245662306a36Sopenharmony_ci bit = (data >> i) & 0x1; 245762306a36Sopenharmony_ci status = ixgbe_clock_out_i2c_bit(hw, bit); 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci if (status != 0) 246062306a36Sopenharmony_ci break; 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci /* Release SDA line (set high) */ 246462306a36Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 246562306a36Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OUT(hw); 246662306a36Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OE_N_EN(hw); 246762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 246862306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci return status; 247162306a36Sopenharmony_ci} 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci/** 247462306a36Sopenharmony_ci * ixgbe_get_i2c_ack - Polls for I2C ACK 247562306a36Sopenharmony_ci * @hw: pointer to hardware structure 247662306a36Sopenharmony_ci * 247762306a36Sopenharmony_ci * Clocks in/out one bit via I2C data/clock 247862306a36Sopenharmony_ci **/ 247962306a36Sopenharmony_cistatic s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) 248062306a36Sopenharmony_ci{ 248162306a36Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 248262306a36Sopenharmony_ci s32 status = 0; 248362306a36Sopenharmony_ci u32 i = 0; 248462306a36Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 248562306a36Sopenharmony_ci u32 timeout = 10; 248662306a36Sopenharmony_ci bool ack = true; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci if (data_oe_bit) { 248962306a36Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OUT(hw); 249062306a36Sopenharmony_ci i2cctl |= data_oe_bit; 249162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 249262306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 249362306a36Sopenharmony_ci } 249462306a36Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci /* Minimum high period of clock is 4us */ 249762306a36Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci /* Poll for ACK. Note that ACK in I2C spec is 250062306a36Sopenharmony_ci * transition from 1 to 0 */ 250162306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 250262306a36Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 250362306a36Sopenharmony_ci ack = ixgbe_get_i2c_data(hw, &i2cctl); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci udelay(1); 250662306a36Sopenharmony_ci if (ack == 0) 250762306a36Sopenharmony_ci break; 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci if (ack == 1) { 251162306a36Sopenharmony_ci hw_dbg(hw, "I2C ack was not received.\n"); 251262306a36Sopenharmony_ci status = -EIO; 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci /* Minimum low period of clock is 4.7 us */ 251862306a36Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci return status; 252162306a36Sopenharmony_ci} 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci/** 252462306a36Sopenharmony_ci * ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock 252562306a36Sopenharmony_ci * @hw: pointer to hardware structure 252662306a36Sopenharmony_ci * @data: read data value 252762306a36Sopenharmony_ci * 252862306a36Sopenharmony_ci * Clocks in one bit via I2C data/clock 252962306a36Sopenharmony_ci **/ 253062306a36Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) 253162306a36Sopenharmony_ci{ 253262306a36Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 253362306a36Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci if (data_oe_bit) { 253662306a36Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OUT(hw); 253762306a36Sopenharmony_ci i2cctl |= data_oe_bit; 253862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 253962306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci /* Minimum high period of clock is 4us */ 254462306a36Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 254762306a36Sopenharmony_ci *data = ixgbe_get_i2c_data(hw, &i2cctl); 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci /* Minimum low period of clock is 4.7 us */ 255262306a36Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci return 0; 255562306a36Sopenharmony_ci} 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci/** 255862306a36Sopenharmony_ci * ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock 255962306a36Sopenharmony_ci * @hw: pointer to hardware structure 256062306a36Sopenharmony_ci * @data: data value to write 256162306a36Sopenharmony_ci * 256262306a36Sopenharmony_ci * Clocks out one bit via I2C data/clock 256362306a36Sopenharmony_ci **/ 256462306a36Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) 256562306a36Sopenharmony_ci{ 256662306a36Sopenharmony_ci s32 status; 256762306a36Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci status = ixgbe_set_i2c_data(hw, &i2cctl, data); 257062306a36Sopenharmony_ci if (status == 0) { 257162306a36Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci /* Minimum high period of clock is 4us */ 257462306a36Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci /* Minimum low period of clock is 4.7 us. 257962306a36Sopenharmony_ci * This also takes care of the data hold time. 258062306a36Sopenharmony_ci */ 258162306a36Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 258262306a36Sopenharmony_ci } else { 258362306a36Sopenharmony_ci hw_dbg(hw, "I2C data was not set to %X\n", data); 258462306a36Sopenharmony_ci return -EIO; 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci return 0; 258862306a36Sopenharmony_ci} 258962306a36Sopenharmony_ci/** 259062306a36Sopenharmony_ci * ixgbe_raise_i2c_clk - Raises the I2C SCL clock 259162306a36Sopenharmony_ci * @hw: pointer to hardware structure 259262306a36Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 259362306a36Sopenharmony_ci * 259462306a36Sopenharmony_ci * Raises the I2C clock line '0'->'1' 259562306a36Sopenharmony_ci * Negates the I2C clock output enable on X550 hardware. 259662306a36Sopenharmony_ci **/ 259762306a36Sopenharmony_cistatic void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) 259862306a36Sopenharmony_ci{ 259962306a36Sopenharmony_ci u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw); 260062306a36Sopenharmony_ci u32 i = 0; 260162306a36Sopenharmony_ci u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; 260262306a36Sopenharmony_ci u32 i2cctl_r = 0; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci if (clk_oe_bit) { 260562306a36Sopenharmony_ci *i2cctl |= clk_oe_bit; 260662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 260762306a36Sopenharmony_ci } 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 261062306a36Sopenharmony_ci *i2cctl |= IXGBE_I2C_CLK_OUT(hw); 261162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 261262306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 261362306a36Sopenharmony_ci /* SCL rise time (1000ns) */ 261462306a36Sopenharmony_ci udelay(IXGBE_I2C_T_RISE); 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 261762306a36Sopenharmony_ci if (i2cctl_r & IXGBE_I2C_CLK_IN(hw)) 261862306a36Sopenharmony_ci break; 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci} 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci/** 262362306a36Sopenharmony_ci * ixgbe_lower_i2c_clk - Lowers the I2C SCL clock 262462306a36Sopenharmony_ci * @hw: pointer to hardware structure 262562306a36Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 262662306a36Sopenharmony_ci * 262762306a36Sopenharmony_ci * Lowers the I2C clock line '1'->'0' 262862306a36Sopenharmony_ci * Asserts the I2C clock output enable on X550 hardware. 262962306a36Sopenharmony_ci **/ 263062306a36Sopenharmony_cistatic void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) 263162306a36Sopenharmony_ci{ 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci *i2cctl &= ~IXGBE_I2C_CLK_OUT(hw); 263462306a36Sopenharmony_ci *i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN(hw); 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 263762306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci /* SCL fall time (300ns) */ 264062306a36Sopenharmony_ci udelay(IXGBE_I2C_T_FALL); 264162306a36Sopenharmony_ci} 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci/** 264462306a36Sopenharmony_ci * ixgbe_set_i2c_data - Sets the I2C data bit 264562306a36Sopenharmony_ci * @hw: pointer to hardware structure 264662306a36Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 264762306a36Sopenharmony_ci * @data: I2C data value (0 or 1) to set 264862306a36Sopenharmony_ci * 264962306a36Sopenharmony_ci * Sets the I2C data bit 265062306a36Sopenharmony_ci * Asserts the I2C data output enable on X550 hardware. 265162306a36Sopenharmony_ci **/ 265262306a36Sopenharmony_cistatic s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) 265362306a36Sopenharmony_ci{ 265462306a36Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci if (data) 265762306a36Sopenharmony_ci *i2cctl |= IXGBE_I2C_DATA_OUT(hw); 265862306a36Sopenharmony_ci else 265962306a36Sopenharmony_ci *i2cctl &= ~IXGBE_I2C_DATA_OUT(hw); 266062306a36Sopenharmony_ci *i2cctl &= ~data_oe_bit; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 266362306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ 266662306a36Sopenharmony_ci udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci if (!data) /* Can't verify data in this case */ 266962306a36Sopenharmony_ci return 0; 267062306a36Sopenharmony_ci if (data_oe_bit) { 267162306a36Sopenharmony_ci *i2cctl |= data_oe_bit; 267262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 267362306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 267462306a36Sopenharmony_ci } 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci /* Verify data was set correctly */ 267762306a36Sopenharmony_ci *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 267862306a36Sopenharmony_ci if (data != ixgbe_get_i2c_data(hw, i2cctl)) { 267962306a36Sopenharmony_ci hw_dbg(hw, "Error - I2C data was not set to %X.\n", data); 268062306a36Sopenharmony_ci return -EIO; 268162306a36Sopenharmony_ci } 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci return 0; 268462306a36Sopenharmony_ci} 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci/** 268762306a36Sopenharmony_ci * ixgbe_get_i2c_data - Reads the I2C SDA data bit 268862306a36Sopenharmony_ci * @hw: pointer to hardware structure 268962306a36Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 269062306a36Sopenharmony_ci * 269162306a36Sopenharmony_ci * Returns the I2C data bit value 269262306a36Sopenharmony_ci * Negates the I2C data output enable on X550 hardware. 269362306a36Sopenharmony_ci **/ 269462306a36Sopenharmony_cistatic bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl) 269562306a36Sopenharmony_ci{ 269662306a36Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci if (data_oe_bit) { 269962306a36Sopenharmony_ci *i2cctl |= data_oe_bit; 270062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 270162306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 270262306a36Sopenharmony_ci udelay(IXGBE_I2C_T_FALL); 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci if (*i2cctl & IXGBE_I2C_DATA_IN(hw)) 270662306a36Sopenharmony_ci return true; 270762306a36Sopenharmony_ci return false; 270862306a36Sopenharmony_ci} 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci/** 271162306a36Sopenharmony_ci * ixgbe_i2c_bus_clear - Clears the I2C bus 271262306a36Sopenharmony_ci * @hw: pointer to hardware structure 271362306a36Sopenharmony_ci * 271462306a36Sopenharmony_ci * Clears the I2C bus by sending nine clock pulses. 271562306a36Sopenharmony_ci * Used when data line is stuck low. 271662306a36Sopenharmony_ci **/ 271762306a36Sopenharmony_cistatic void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) 271862306a36Sopenharmony_ci{ 271962306a36Sopenharmony_ci u32 i2cctl; 272062306a36Sopenharmony_ci u32 i; 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci ixgbe_i2c_start(hw); 272362306a36Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 1); 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci for (i = 0; i < 9; i++) { 272862306a36Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci /* Min high period of clock is 4us */ 273162306a36Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci /* Min low period of clock is 4.7us*/ 273662306a36Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci ixgbe_i2c_start(hw); 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci /* Put the i2c bus back to default state */ 274262306a36Sopenharmony_ci ixgbe_i2c_stop(hw); 274362306a36Sopenharmony_ci} 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci/** 274662306a36Sopenharmony_ci * ixgbe_tn_check_overtemp - Checks if an overtemp occurred. 274762306a36Sopenharmony_ci * @hw: pointer to hardware structure 274862306a36Sopenharmony_ci * 274962306a36Sopenharmony_ci * Checks if the LASI temp alarm status was triggered due to overtemp 275062306a36Sopenharmony_ci * 275162306a36Sopenharmony_ci * Return true when an overtemp event detected, otherwise false. 275262306a36Sopenharmony_ci **/ 275362306a36Sopenharmony_cibool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) 275462306a36Sopenharmony_ci{ 275562306a36Sopenharmony_ci u16 phy_data = 0; 275662306a36Sopenharmony_ci u32 status; 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM) 275962306a36Sopenharmony_ci return false; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci /* Check that the LASI temp alarm status was triggered */ 276262306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG, 276362306a36Sopenharmony_ci MDIO_MMD_PMAPMD, &phy_data); 276462306a36Sopenharmony_ci if (status) 276562306a36Sopenharmony_ci return false; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci return !!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM); 276862306a36Sopenharmony_ci} 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci/** ixgbe_set_copper_phy_power - Control power for copper phy 277162306a36Sopenharmony_ci * @hw: pointer to hardware structure 277262306a36Sopenharmony_ci * @on: true for on, false for off 277362306a36Sopenharmony_ci **/ 277462306a36Sopenharmony_cis32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci u32 status; 277762306a36Sopenharmony_ci u16 reg; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci /* Bail if we don't have copper phy */ 278062306a36Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) 278162306a36Sopenharmony_ci return 0; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci if (!on && ixgbe_mng_present(hw)) 278462306a36Sopenharmony_ci return 0; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_VEND1, ®); 278762306a36Sopenharmony_ci if (status) 278862306a36Sopenharmony_ci return status; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci if (on) { 279162306a36Sopenharmony_ci reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; 279262306a36Sopenharmony_ci } else { 279362306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 279462306a36Sopenharmony_ci return 0; 279562306a36Sopenharmony_ci reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci status = hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_VEND1, reg); 279962306a36Sopenharmony_ci return status; 280062306a36Sopenharmony_ci} 2801