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, &reg);
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