18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/pci.h>
58c2ecf20Sopenharmony_ci#include <linux/delay.h>
68c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
78c2ecf20Sopenharmony_ci#include <linux/sched.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "ixgbe.h"
108c2ecf20Sopenharmony_ci#include "ixgbe_phy.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic void ixgbe_i2c_start(struct ixgbe_hw *hw);
138c2ecf20Sopenharmony_cistatic void ixgbe_i2c_stop(struct ixgbe_hw *hw);
148c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data);
158c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
168c2ecf20Sopenharmony_cistatic s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
178c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
188c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
198c2ecf20Sopenharmony_cistatic void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
208c2ecf20Sopenharmony_cistatic void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
218c2ecf20Sopenharmony_cistatic s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
228c2ecf20Sopenharmony_cistatic bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl);
238c2ecf20Sopenharmony_cistatic void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw);
248c2ecf20Sopenharmony_cistatic enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
258c2ecf20Sopenharmony_cistatic s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
268c2ecf20Sopenharmony_cistatic s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/**
298c2ecf20Sopenharmony_ci *  ixgbe_out_i2c_byte_ack - Send I2C byte with ack
308c2ecf20Sopenharmony_ci *  @hw: pointer to the hardware structure
318c2ecf20Sopenharmony_ci *  @byte: byte to send
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci *  Returns an error code on error.
348c2ecf20Sopenharmony_ci **/
358c2ecf20Sopenharmony_cistatic s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	s32 status;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	status = ixgbe_clock_out_i2c_byte(hw, byte);
408c2ecf20Sopenharmony_ci	if (status)
418c2ecf20Sopenharmony_ci		return status;
428c2ecf20Sopenharmony_ci	return ixgbe_get_i2c_ack(hw);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/**
468c2ecf20Sopenharmony_ci *  ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack
478c2ecf20Sopenharmony_ci *  @hw: pointer to the hardware structure
488c2ecf20Sopenharmony_ci *  @byte: pointer to a u8 to receive the byte
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci *  Returns an error code on error.
518c2ecf20Sopenharmony_ci **/
528c2ecf20Sopenharmony_cistatic s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	s32 status;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	status = ixgbe_clock_in_i2c_byte(hw, byte);
578c2ecf20Sopenharmony_ci	if (status)
588c2ecf20Sopenharmony_ci		return status;
598c2ecf20Sopenharmony_ci	/* ACK */
608c2ecf20Sopenharmony_ci	return ixgbe_clock_out_i2c_bit(hw, false);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/**
648c2ecf20Sopenharmony_ci *  ixgbe_ones_comp_byte_add - Perform one's complement addition
658c2ecf20Sopenharmony_ci *  @add1: addend 1
668c2ecf20Sopenharmony_ci *  @add2: addend 2
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci *  Returns one's complement 8-bit sum.
698c2ecf20Sopenharmony_ci **/
708c2ecf20Sopenharmony_cistatic u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	u16 sum = add1 + add2;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	sum = (sum & 0xFF) + (sum >> 8);
758c2ecf20Sopenharmony_ci	return sum & 0xFF;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci *  ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation
808c2ecf20Sopenharmony_ci *  @hw: pointer to the hardware structure
818c2ecf20Sopenharmony_ci *  @addr: I2C bus address to read from
828c2ecf20Sopenharmony_ci *  @reg: I2C device register to read from
838c2ecf20Sopenharmony_ci *  @val: pointer to location to receive read value
848c2ecf20Sopenharmony_ci *  @lock: true if to take and release semaphore
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci *  Returns an error code on error.
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
898c2ecf20Sopenharmony_ci					u16 reg, u16 *val, bool lock)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	u32 swfw_mask = hw->phy.phy_semaphore_mask;
928c2ecf20Sopenharmony_ci	int max_retry = 3;
938c2ecf20Sopenharmony_ci	int retry = 0;
948c2ecf20Sopenharmony_ci	u8 csum_byte;
958c2ecf20Sopenharmony_ci	u8 high_bits;
968c2ecf20Sopenharmony_ci	u8 low_bits;
978c2ecf20Sopenharmony_ci	u8 reg_high;
988c2ecf20Sopenharmony_ci	u8 csum;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	reg_high = ((reg >> 7) & 0xFE) | 1;     /* Indicate read combined */
1018c2ecf20Sopenharmony_ci	csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
1028c2ecf20Sopenharmony_ci	csum = ~csum;
1038c2ecf20Sopenharmony_ci	do {
1048c2ecf20Sopenharmony_ci		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
1058c2ecf20Sopenharmony_ci			return -EBUSY;
1068c2ecf20Sopenharmony_ci		ixgbe_i2c_start(hw);
1078c2ecf20Sopenharmony_ci		/* Device Address and write indication */
1088c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, addr))
1098c2ecf20Sopenharmony_ci			goto fail;
1108c2ecf20Sopenharmony_ci		/* Write bits 14:8 */
1118c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, reg_high))
1128c2ecf20Sopenharmony_ci			goto fail;
1138c2ecf20Sopenharmony_ci		/* Write bits 7:0 */
1148c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
1158c2ecf20Sopenharmony_ci			goto fail;
1168c2ecf20Sopenharmony_ci		/* Write csum */
1178c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, csum))
1188c2ecf20Sopenharmony_ci			goto fail;
1198c2ecf20Sopenharmony_ci		/* Re-start condition */
1208c2ecf20Sopenharmony_ci		ixgbe_i2c_start(hw);
1218c2ecf20Sopenharmony_ci		/* Device Address and read indication */
1228c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, addr | 1))
1238c2ecf20Sopenharmony_ci			goto fail;
1248c2ecf20Sopenharmony_ci		/* Get upper bits */
1258c2ecf20Sopenharmony_ci		if (ixgbe_in_i2c_byte_ack(hw, &high_bits))
1268c2ecf20Sopenharmony_ci			goto fail;
1278c2ecf20Sopenharmony_ci		/* Get low bits */
1288c2ecf20Sopenharmony_ci		if (ixgbe_in_i2c_byte_ack(hw, &low_bits))
1298c2ecf20Sopenharmony_ci			goto fail;
1308c2ecf20Sopenharmony_ci		/* Get csum */
1318c2ecf20Sopenharmony_ci		if (ixgbe_clock_in_i2c_byte(hw, &csum_byte))
1328c2ecf20Sopenharmony_ci			goto fail;
1338c2ecf20Sopenharmony_ci		/* NACK */
1348c2ecf20Sopenharmony_ci		if (ixgbe_clock_out_i2c_bit(hw, false))
1358c2ecf20Sopenharmony_ci			goto fail;
1368c2ecf20Sopenharmony_ci		ixgbe_i2c_stop(hw);
1378c2ecf20Sopenharmony_ci		if (lock)
1388c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
1398c2ecf20Sopenharmony_ci		*val = (high_bits << 8) | low_bits;
1408c2ecf20Sopenharmony_ci		return 0;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cifail:
1438c2ecf20Sopenharmony_ci		ixgbe_i2c_bus_clear(hw);
1448c2ecf20Sopenharmony_ci		if (lock)
1458c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
1468c2ecf20Sopenharmony_ci		retry++;
1478c2ecf20Sopenharmony_ci		if (retry < max_retry)
1488c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte read combined error - Retry.\n");
1498c2ecf20Sopenharmony_ci		else
1508c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte read combined error.\n");
1518c2ecf20Sopenharmony_ci	} while (retry < max_retry);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return -EIO;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/**
1578c2ecf20Sopenharmony_ci *  ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation
1588c2ecf20Sopenharmony_ci *  @hw: pointer to the hardware structure
1598c2ecf20Sopenharmony_ci *  @addr: I2C bus address to write to
1608c2ecf20Sopenharmony_ci *  @reg: I2C device register to write to
1618c2ecf20Sopenharmony_ci *  @val: value to write
1628c2ecf20Sopenharmony_ci *  @lock: true if to take and release semaphore
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci *  Returns an error code on error.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
1678c2ecf20Sopenharmony_ci					 u16 reg, u16 val, bool lock)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	u32 swfw_mask = hw->phy.phy_semaphore_mask;
1708c2ecf20Sopenharmony_ci	int max_retry = 1;
1718c2ecf20Sopenharmony_ci	int retry = 0;
1728c2ecf20Sopenharmony_ci	u8 reg_high;
1738c2ecf20Sopenharmony_ci	u8 csum;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	reg_high = (reg >> 7) & 0xFE;   /* Indicate write combined */
1768c2ecf20Sopenharmony_ci	csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
1778c2ecf20Sopenharmony_ci	csum = ixgbe_ones_comp_byte_add(csum, val >> 8);
1788c2ecf20Sopenharmony_ci	csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
1798c2ecf20Sopenharmony_ci	csum = ~csum;
1808c2ecf20Sopenharmony_ci	do {
1818c2ecf20Sopenharmony_ci		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
1828c2ecf20Sopenharmony_ci			return -EBUSY;
1838c2ecf20Sopenharmony_ci		ixgbe_i2c_start(hw);
1848c2ecf20Sopenharmony_ci		/* Device Address and write indication */
1858c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, addr))
1868c2ecf20Sopenharmony_ci			goto fail;
1878c2ecf20Sopenharmony_ci		/* Write bits 14:8 */
1888c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, reg_high))
1898c2ecf20Sopenharmony_ci			goto fail;
1908c2ecf20Sopenharmony_ci		/* Write bits 7:0 */
1918c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
1928c2ecf20Sopenharmony_ci			goto fail;
1938c2ecf20Sopenharmony_ci		/* Write data 15:8 */
1948c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, val >> 8))
1958c2ecf20Sopenharmony_ci			goto fail;
1968c2ecf20Sopenharmony_ci		/* Write data 7:0 */
1978c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF))
1988c2ecf20Sopenharmony_ci			goto fail;
1998c2ecf20Sopenharmony_ci		/* Write csum */
2008c2ecf20Sopenharmony_ci		if (ixgbe_out_i2c_byte_ack(hw, csum))
2018c2ecf20Sopenharmony_ci			goto fail;
2028c2ecf20Sopenharmony_ci		ixgbe_i2c_stop(hw);
2038c2ecf20Sopenharmony_ci		if (lock)
2048c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
2058c2ecf20Sopenharmony_ci		return 0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cifail:
2088c2ecf20Sopenharmony_ci		ixgbe_i2c_bus_clear(hw);
2098c2ecf20Sopenharmony_ci		if (lock)
2108c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
2118c2ecf20Sopenharmony_ci		retry++;
2128c2ecf20Sopenharmony_ci		if (retry < max_retry)
2138c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte write combined error - Retry.\n");
2148c2ecf20Sopenharmony_ci		else
2158c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte write combined error.\n");
2168c2ecf20Sopenharmony_ci	} while (retry < max_retry);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return -EIO;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci/**
2228c2ecf20Sopenharmony_ci *  ixgbe_probe_phy - Probe a single address for a PHY
2238c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
2248c2ecf20Sopenharmony_ci *  @phy_addr: PHY address to probe
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci *  Returns true if PHY found
2278c2ecf20Sopenharmony_ci **/
2288c2ecf20Sopenharmony_cistatic bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	u16 ext_ability = 0;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	hw->phy.mdio.prtad = phy_addr;
2338c2ecf20Sopenharmony_ci	if (mdio45_probe(&hw->phy.mdio, phy_addr) != 0)
2348c2ecf20Sopenharmony_ci		return false;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (ixgbe_get_phy_id(hw))
2378c2ecf20Sopenharmony_ci		return false;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (hw->phy.type == ixgbe_phy_unknown) {
2428c2ecf20Sopenharmony_ci		hw->phy.ops.read_reg(hw,
2438c2ecf20Sopenharmony_ci				     MDIO_PMA_EXTABLE,
2448c2ecf20Sopenharmony_ci				     MDIO_MMD_PMAPMD,
2458c2ecf20Sopenharmony_ci				     &ext_ability);
2468c2ecf20Sopenharmony_ci		if (ext_ability &
2478c2ecf20Sopenharmony_ci		    (MDIO_PMA_EXTABLE_10GBT |
2488c2ecf20Sopenharmony_ci		     MDIO_PMA_EXTABLE_1000BT))
2498c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_cu_unknown;
2508c2ecf20Sopenharmony_ci		else
2518c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_generic;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return true;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/**
2588c2ecf20Sopenharmony_ci *  ixgbe_identify_phy_generic - Get physical layer module
2598c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci *  Determines the physical layer module found on the current adapter.
2628c2ecf20Sopenharmony_ci **/
2638c2ecf20Sopenharmony_cis32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	u32 status = -EFAULT;
2668c2ecf20Sopenharmony_ci	u32 phy_addr;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (!hw->phy.phy_semaphore_mask) {
2698c2ecf20Sopenharmony_ci		if (hw->bus.lan_id)
2708c2ecf20Sopenharmony_ci			hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM;
2718c2ecf20Sopenharmony_ci		else
2728c2ecf20Sopenharmony_ci			hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (hw->phy.type != ixgbe_phy_unknown)
2768c2ecf20Sopenharmony_ci		return 0;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (hw->phy.nw_mng_if_sel) {
2798c2ecf20Sopenharmony_ci		phy_addr = (hw->phy.nw_mng_if_sel &
2808c2ecf20Sopenharmony_ci			    IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
2818c2ecf20Sopenharmony_ci			   IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
2828c2ecf20Sopenharmony_ci		if (ixgbe_probe_phy(hw, phy_addr))
2838c2ecf20Sopenharmony_ci			return 0;
2848c2ecf20Sopenharmony_ci		else
2858c2ecf20Sopenharmony_ci			return -EFAULT;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
2898c2ecf20Sopenharmony_ci		if (ixgbe_probe_phy(hw, phy_addr)) {
2908c2ecf20Sopenharmony_ci			status = 0;
2918c2ecf20Sopenharmony_ci			break;
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* Certain media types do not have a phy so an address will not
2968c2ecf20Sopenharmony_ci	 * be found and the code will take this path.  Caller has to
2978c2ecf20Sopenharmony_ci	 * decide if it is an error or not.
2988c2ecf20Sopenharmony_ci	 */
2998c2ecf20Sopenharmony_ci	if (status)
3008c2ecf20Sopenharmony_ci		hw->phy.mdio.prtad = MDIO_PRTAD_NONE;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return status;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci/**
3068c2ecf20Sopenharmony_ci * ixgbe_check_reset_blocked - check status of MNG FW veto bit
3078c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * This function checks the MMNGC.MNG_VETO bit to see if there are
3108c2ecf20Sopenharmony_ci * any constraints on link from manageability.  For MAC's that don't
3118c2ecf20Sopenharmony_ci * have this bit just return false since the link can not be blocked
3128c2ecf20Sopenharmony_ci * via this method.
3138c2ecf20Sopenharmony_ci **/
3148c2ecf20Sopenharmony_cibool ixgbe_check_reset_blocked(struct ixgbe_hw *hw)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	u32 mmngc;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* If we don't have this bit, it can't be blocking */
3198c2ecf20Sopenharmony_ci	if (hw->mac.type == ixgbe_mac_82598EB)
3208c2ecf20Sopenharmony_ci		return false;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC);
3238c2ecf20Sopenharmony_ci	if (mmngc & IXGBE_MMNGC_MNG_VETO) {
3248c2ecf20Sopenharmony_ci		hw_dbg(hw, "MNG_VETO bit detected.\n");
3258c2ecf20Sopenharmony_ci		return true;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return false;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/**
3328c2ecf20Sopenharmony_ci *  ixgbe_get_phy_id - Get the phy type
3338c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
3348c2ecf20Sopenharmony_ci *
3358c2ecf20Sopenharmony_ci **/
3368c2ecf20Sopenharmony_cistatic s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	s32 status;
3398c2ecf20Sopenharmony_ci	u16 phy_id_high = 0;
3408c2ecf20Sopenharmony_ci	u16 phy_id_low = 0;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD,
3438c2ecf20Sopenharmony_ci				      &phy_id_high);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (!status) {
3468c2ecf20Sopenharmony_ci		hw->phy.id = (u32)(phy_id_high << 16);
3478c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_reg(hw, MDIO_DEVID2, MDIO_MMD_PMAPMD,
3488c2ecf20Sopenharmony_ci					      &phy_id_low);
3498c2ecf20Sopenharmony_ci		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
3508c2ecf20Sopenharmony_ci		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci	return status;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci/**
3568c2ecf20Sopenharmony_ci *  ixgbe_get_phy_type_from_id - Get the phy type
3578c2ecf20Sopenharmony_ci *  @phy_id: hardware phy id
3588c2ecf20Sopenharmony_ci *
3598c2ecf20Sopenharmony_ci **/
3608c2ecf20Sopenharmony_cistatic enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	enum ixgbe_phy_type phy_type;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	switch (phy_id) {
3658c2ecf20Sopenharmony_ci	case TN1010_PHY_ID:
3668c2ecf20Sopenharmony_ci		phy_type = ixgbe_phy_tn;
3678c2ecf20Sopenharmony_ci		break;
3688c2ecf20Sopenharmony_ci	case X550_PHY_ID2:
3698c2ecf20Sopenharmony_ci	case X550_PHY_ID3:
3708c2ecf20Sopenharmony_ci	case X540_PHY_ID:
3718c2ecf20Sopenharmony_ci		phy_type = ixgbe_phy_aq;
3728c2ecf20Sopenharmony_ci		break;
3738c2ecf20Sopenharmony_ci	case QT2022_PHY_ID:
3748c2ecf20Sopenharmony_ci		phy_type = ixgbe_phy_qt;
3758c2ecf20Sopenharmony_ci		break;
3768c2ecf20Sopenharmony_ci	case ATH_PHY_ID:
3778c2ecf20Sopenharmony_ci		phy_type = ixgbe_phy_nl;
3788c2ecf20Sopenharmony_ci		break;
3798c2ecf20Sopenharmony_ci	case X557_PHY_ID:
3808c2ecf20Sopenharmony_ci	case X557_PHY_ID2:
3818c2ecf20Sopenharmony_ci		phy_type = ixgbe_phy_x550em_ext_t;
3828c2ecf20Sopenharmony_ci		break;
3838c2ecf20Sopenharmony_ci	default:
3848c2ecf20Sopenharmony_ci		phy_type = ixgbe_phy_unknown;
3858c2ecf20Sopenharmony_ci		break;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return phy_type;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci/**
3928c2ecf20Sopenharmony_ci *  ixgbe_reset_phy_generic - Performs a PHY reset
3938c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
3948c2ecf20Sopenharmony_ci **/
3958c2ecf20Sopenharmony_cis32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	u32 i;
3988c2ecf20Sopenharmony_ci	u16 ctrl = 0;
3998c2ecf20Sopenharmony_ci	s32 status = 0;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (hw->phy.type == ixgbe_phy_unknown)
4028c2ecf20Sopenharmony_ci		status = ixgbe_identify_phy_generic(hw);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (status != 0 || hw->phy.type == ixgbe_phy_none)
4058c2ecf20Sopenharmony_ci		return status;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* Don't reset PHY if it's shut down due to overtemp. */
4088c2ecf20Sopenharmony_ci	if (!hw->phy.reset_if_overtemp && hw->phy.ops.check_overtemp(hw))
4098c2ecf20Sopenharmony_ci		return 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* Blocked by MNG FW so bail */
4128c2ecf20Sopenharmony_ci	if (ixgbe_check_reset_blocked(hw))
4138c2ecf20Sopenharmony_ci		return 0;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/*
4168c2ecf20Sopenharmony_ci	 * Perform soft PHY reset to the PHY_XS.
4178c2ecf20Sopenharmony_ci	 * This will cause a soft reset to the PHY
4188c2ecf20Sopenharmony_ci	 */
4198c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, MDIO_CTRL1,
4208c2ecf20Sopenharmony_ci			      MDIO_MMD_PHYXS,
4218c2ecf20Sopenharmony_ci			      MDIO_CTRL1_RESET);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * Poll for reset bit to self-clear indicating reset is complete.
4258c2ecf20Sopenharmony_ci	 * Some PHYs could take up to 3 seconds to complete and need about
4268c2ecf20Sopenharmony_ci	 * 1.7 usec delay after the reset is complete.
4278c2ecf20Sopenharmony_ci	 */
4288c2ecf20Sopenharmony_ci	for (i = 0; i < 30; i++) {
4298c2ecf20Sopenharmony_ci		msleep(100);
4308c2ecf20Sopenharmony_ci		if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
4318c2ecf20Sopenharmony_ci			status = hw->phy.ops.read_reg(hw,
4328c2ecf20Sopenharmony_ci						  IXGBE_MDIO_TX_VENDOR_ALARMS_3,
4338c2ecf20Sopenharmony_ci						  MDIO_MMD_PMAPMD, &ctrl);
4348c2ecf20Sopenharmony_ci			if (status)
4358c2ecf20Sopenharmony_ci				return status;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci			if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
4388c2ecf20Sopenharmony_ci				udelay(2);
4398c2ecf20Sopenharmony_ci				break;
4408c2ecf20Sopenharmony_ci			}
4418c2ecf20Sopenharmony_ci		} else {
4428c2ecf20Sopenharmony_ci			status = hw->phy.ops.read_reg(hw, MDIO_CTRL1,
4438c2ecf20Sopenharmony_ci						      MDIO_MMD_PHYXS, &ctrl);
4448c2ecf20Sopenharmony_ci			if (status)
4458c2ecf20Sopenharmony_ci				return status;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci			if (!(ctrl & MDIO_CTRL1_RESET)) {
4488c2ecf20Sopenharmony_ci				udelay(2);
4498c2ecf20Sopenharmony_ci				break;
4508c2ecf20Sopenharmony_ci			}
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (ctrl & MDIO_CTRL1_RESET) {
4558c2ecf20Sopenharmony_ci		hw_dbg(hw, "PHY reset polling failed to complete.\n");
4568c2ecf20Sopenharmony_ci		return -EIO;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci/**
4638c2ecf20Sopenharmony_ci *  ixgbe_read_phy_mdi - Reads a value from a specified PHY register without
4648c2ecf20Sopenharmony_ci *  the SWFW lock
4658c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
4668c2ecf20Sopenharmony_ci *  @reg_addr: 32 bit address of PHY register to read
4678c2ecf20Sopenharmony_ci *  @device_type: 5 bit device type
4688c2ecf20Sopenharmony_ci *  @phy_data: Pointer to read data from PHY register
4698c2ecf20Sopenharmony_ci **/
4708c2ecf20Sopenharmony_cis32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
4718c2ecf20Sopenharmony_ci		       u16 *phy_data)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	u32 i, data, command;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* Setup and write the address cycle command */
4768c2ecf20Sopenharmony_ci	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
4778c2ecf20Sopenharmony_ci		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
4788c2ecf20Sopenharmony_ci		   (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
4798c2ecf20Sopenharmony_ci		   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* Check every 10 usec to see if the address cycle completed.
4848c2ecf20Sopenharmony_ci	 * The MDI Command bit will clear when the operation is
4858c2ecf20Sopenharmony_ci	 * complete
4868c2ecf20Sopenharmony_ci	 */
4878c2ecf20Sopenharmony_ci	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
4888c2ecf20Sopenharmony_ci		udelay(10);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
4918c2ecf20Sopenharmony_ci		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
4928c2ecf20Sopenharmony_ci				break;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
4978c2ecf20Sopenharmony_ci		hw_dbg(hw, "PHY address command did not complete.\n");
4988c2ecf20Sopenharmony_ci		return -EIO;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	/* Address cycle complete, setup and write the read
5028c2ecf20Sopenharmony_ci	 * command
5038c2ecf20Sopenharmony_ci	 */
5048c2ecf20Sopenharmony_ci	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
5058c2ecf20Sopenharmony_ci		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
5068c2ecf20Sopenharmony_ci		   (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
5078c2ecf20Sopenharmony_ci		   (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	/* Check every 10 usec to see if the address cycle
5128c2ecf20Sopenharmony_ci	 * completed. The MDI Command bit will clear when the
5138c2ecf20Sopenharmony_ci	 * operation is complete
5148c2ecf20Sopenharmony_ci	 */
5158c2ecf20Sopenharmony_ci	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
5168c2ecf20Sopenharmony_ci		udelay(10);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
5198c2ecf20Sopenharmony_ci		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
5208c2ecf20Sopenharmony_ci			break;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
5248c2ecf20Sopenharmony_ci		hw_dbg(hw, "PHY read command didn't complete\n");
5258c2ecf20Sopenharmony_ci		return -EIO;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/* Read operation is complete.  Get the data
5298c2ecf20Sopenharmony_ci	 * from MSRWD
5308c2ecf20Sopenharmony_ci	 */
5318c2ecf20Sopenharmony_ci	data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
5328c2ecf20Sopenharmony_ci	data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
5338c2ecf20Sopenharmony_ci	*phy_data = (u16)(data);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/**
5398c2ecf20Sopenharmony_ci *  ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
5408c2ecf20Sopenharmony_ci *  using the SWFW lock - this function is needed in most cases
5418c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
5428c2ecf20Sopenharmony_ci *  @reg_addr: 32 bit address of PHY register to read
5438c2ecf20Sopenharmony_ci *  @device_type: 5 bit device type
5448c2ecf20Sopenharmony_ci *  @phy_data: Pointer to read data from PHY register
5458c2ecf20Sopenharmony_ci **/
5468c2ecf20Sopenharmony_cis32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
5478c2ecf20Sopenharmony_ci			       u32 device_type, u16 *phy_data)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	s32 status;
5508c2ecf20Sopenharmony_ci	u32 gssr = hw->phy.phy_semaphore_mask;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) {
5538c2ecf20Sopenharmony_ci		status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type,
5548c2ecf20Sopenharmony_ci						phy_data);
5558c2ecf20Sopenharmony_ci		hw->mac.ops.release_swfw_sync(hw, gssr);
5568c2ecf20Sopenharmony_ci	} else {
5578c2ecf20Sopenharmony_ci		return -EBUSY;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return status;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci/**
5648c2ecf20Sopenharmony_ci *  ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register
5658c2ecf20Sopenharmony_ci *  without SWFW lock
5668c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
5678c2ecf20Sopenharmony_ci *  @reg_addr: 32 bit PHY register to write
5688c2ecf20Sopenharmony_ci *  @device_type: 5 bit device type
5698c2ecf20Sopenharmony_ci *  @phy_data: Data to write to the PHY register
5708c2ecf20Sopenharmony_ci **/
5718c2ecf20Sopenharmony_cis32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
5728c2ecf20Sopenharmony_ci				u32 device_type, u16 phy_data)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	u32 i, command;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* Put the data in the MDI single read and write data register*/
5778c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* Setup and write the address cycle command */
5808c2ecf20Sopenharmony_ci	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
5818c2ecf20Sopenharmony_ci		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
5828c2ecf20Sopenharmony_ci		   (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
5838c2ecf20Sopenharmony_ci		   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/*
5888c2ecf20Sopenharmony_ci	 * Check every 10 usec to see if the address cycle completed.
5898c2ecf20Sopenharmony_ci	 * The MDI Command bit will clear when the operation is
5908c2ecf20Sopenharmony_ci	 * complete
5918c2ecf20Sopenharmony_ci	 */
5928c2ecf20Sopenharmony_ci	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
5938c2ecf20Sopenharmony_ci		udelay(10);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
5968c2ecf20Sopenharmony_ci		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
6018c2ecf20Sopenharmony_ci		hw_dbg(hw, "PHY address cmd didn't complete\n");
6028c2ecf20Sopenharmony_ci		return -EIO;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	/*
6068c2ecf20Sopenharmony_ci	 * Address cycle complete, setup and write the write
6078c2ecf20Sopenharmony_ci	 * command
6088c2ecf20Sopenharmony_ci	 */
6098c2ecf20Sopenharmony_ci	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
6108c2ecf20Sopenharmony_ci		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
6118c2ecf20Sopenharmony_ci		   (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
6128c2ecf20Sopenharmony_ci		   (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/* Check every 10 usec to see if the address cycle
6178c2ecf20Sopenharmony_ci	 * completed. The MDI Command bit will clear when the
6188c2ecf20Sopenharmony_ci	 * operation is complete
6198c2ecf20Sopenharmony_ci	 */
6208c2ecf20Sopenharmony_ci	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
6218c2ecf20Sopenharmony_ci		udelay(10);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
6248c2ecf20Sopenharmony_ci		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
6258c2ecf20Sopenharmony_ci			break;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
6298c2ecf20Sopenharmony_ci		hw_dbg(hw, "PHY write cmd didn't complete\n");
6308c2ecf20Sopenharmony_ci		return -EIO;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	return 0;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci/**
6378c2ecf20Sopenharmony_ci *  ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
6388c2ecf20Sopenharmony_ci *  using SWFW lock- this function is needed in most cases
6398c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
6408c2ecf20Sopenharmony_ci *  @reg_addr: 32 bit PHY register to write
6418c2ecf20Sopenharmony_ci *  @device_type: 5 bit device type
6428c2ecf20Sopenharmony_ci *  @phy_data: Data to write to the PHY register
6438c2ecf20Sopenharmony_ci **/
6448c2ecf20Sopenharmony_cis32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
6458c2ecf20Sopenharmony_ci				u32 device_type, u16 phy_data)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	s32 status;
6488c2ecf20Sopenharmony_ci	u32 gssr = hw->phy.phy_semaphore_mask;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) {
6518c2ecf20Sopenharmony_ci		status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type,
6528c2ecf20Sopenharmony_ci						 phy_data);
6538c2ecf20Sopenharmony_ci		hw->mac.ops.release_swfw_sync(hw, gssr);
6548c2ecf20Sopenharmony_ci	} else {
6558c2ecf20Sopenharmony_ci		return -EBUSY;
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	return status;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci#define IXGBE_HW_READ_REG(addr) IXGBE_READ_REG(hw, addr)
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/**
6648c2ecf20Sopenharmony_ci *  ixgbe_msca_cmd - Write the command register and poll for completion/timeout
6658c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
6668c2ecf20Sopenharmony_ci *  @cmd: command register value to write
6678c2ecf20Sopenharmony_ci **/
6688c2ecf20Sopenharmony_cistatic s32 ixgbe_msca_cmd(struct ixgbe_hw *hw, u32 cmd)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSCA, cmd);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return readx_poll_timeout(IXGBE_HW_READ_REG, IXGBE_MSCA, cmd,
6738c2ecf20Sopenharmony_ci				  !(cmd & IXGBE_MSCA_MDI_COMMAND), 10,
6748c2ecf20Sopenharmony_ci				  10 * IXGBE_MDIO_COMMAND_TIMEOUT);
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/**
6788c2ecf20Sopenharmony_ci *  ixgbe_mii_bus_read_generic - Read a clause 22/45 register with gssr flags
6798c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
6808c2ecf20Sopenharmony_ci *  @addr: address
6818c2ecf20Sopenharmony_ci *  @regnum: register number
6828c2ecf20Sopenharmony_ci *  @gssr: semaphore flags to acquire
6838c2ecf20Sopenharmony_ci **/
6848c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_read_generic(struct ixgbe_hw *hw, int addr,
6858c2ecf20Sopenharmony_ci				      int regnum, u32 gssr)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	u32 hwaddr, cmd;
6888c2ecf20Sopenharmony_ci	s32 data;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (hw->mac.ops.acquire_swfw_sync(hw, gssr))
6918c2ecf20Sopenharmony_ci		return -EBUSY;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT;
6948c2ecf20Sopenharmony_ci	if (regnum & MII_ADDR_C45) {
6958c2ecf20Sopenharmony_ci		hwaddr |= regnum & GENMASK(21, 0);
6968c2ecf20Sopenharmony_ci		cmd = hwaddr | IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND;
6978c2ecf20Sopenharmony_ci	} else {
6988c2ecf20Sopenharmony_ci		hwaddr |= (regnum & GENMASK(5, 0)) << IXGBE_MSCA_DEV_TYPE_SHIFT;
6998c2ecf20Sopenharmony_ci		cmd = hwaddr | IXGBE_MSCA_OLD_PROTOCOL |
7008c2ecf20Sopenharmony_ci			IXGBE_MSCA_READ_AUTOINC | IXGBE_MSCA_MDI_COMMAND;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	data = ixgbe_msca_cmd(hw, cmd);
7048c2ecf20Sopenharmony_ci	if (data < 0)
7058c2ecf20Sopenharmony_ci		goto mii_bus_read_done;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* For a clause 45 access the address cycle just completed, we still
7088c2ecf20Sopenharmony_ci	 * need to do the read command, otherwise just get the data
7098c2ecf20Sopenharmony_ci	 */
7108c2ecf20Sopenharmony_ci	if (!(regnum & MII_ADDR_C45))
7118c2ecf20Sopenharmony_ci		goto do_mii_bus_read;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	cmd = hwaddr | IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND;
7148c2ecf20Sopenharmony_ci	data = ixgbe_msca_cmd(hw, cmd);
7158c2ecf20Sopenharmony_ci	if (data < 0)
7168c2ecf20Sopenharmony_ci		goto mii_bus_read_done;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cido_mii_bus_read:
7198c2ecf20Sopenharmony_ci	data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
7208c2ecf20Sopenharmony_ci	data = (data >> IXGBE_MSRWD_READ_DATA_SHIFT) & GENMASK(16, 0);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cimii_bus_read_done:
7238c2ecf20Sopenharmony_ci	hw->mac.ops.release_swfw_sync(hw, gssr);
7248c2ecf20Sopenharmony_ci	return data;
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci/**
7288c2ecf20Sopenharmony_ci *  ixgbe_mii_bus_write_generic - Write a clause 22/45 register with gssr flags
7298c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
7308c2ecf20Sopenharmony_ci *  @addr: address
7318c2ecf20Sopenharmony_ci *  @regnum: register number
7328c2ecf20Sopenharmony_ci *  @val: value to write
7338c2ecf20Sopenharmony_ci *  @gssr: semaphore flags to acquire
7348c2ecf20Sopenharmony_ci **/
7358c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_write_generic(struct ixgbe_hw *hw, int addr,
7368c2ecf20Sopenharmony_ci				       int regnum, u16 val, u32 gssr)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	u32 hwaddr, cmd;
7398c2ecf20Sopenharmony_ci	s32 err;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (hw->mac.ops.acquire_swfw_sync(hw, gssr))
7428c2ecf20Sopenharmony_ci		return -EBUSY;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)val);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT;
7478c2ecf20Sopenharmony_ci	if (regnum & MII_ADDR_C45) {
7488c2ecf20Sopenharmony_ci		hwaddr |= regnum & GENMASK(21, 0);
7498c2ecf20Sopenharmony_ci		cmd = hwaddr | IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND;
7508c2ecf20Sopenharmony_ci	} else {
7518c2ecf20Sopenharmony_ci		hwaddr |= (regnum & GENMASK(5, 0)) << IXGBE_MSCA_DEV_TYPE_SHIFT;
7528c2ecf20Sopenharmony_ci		cmd = hwaddr | IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE |
7538c2ecf20Sopenharmony_ci			IXGBE_MSCA_MDI_COMMAND;
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/* For clause 45 this is an address cycle, for clause 22 this is the
7578c2ecf20Sopenharmony_ci	 * entire transaction
7588c2ecf20Sopenharmony_ci	 */
7598c2ecf20Sopenharmony_ci	err = ixgbe_msca_cmd(hw, cmd);
7608c2ecf20Sopenharmony_ci	if (err < 0 || !(regnum & MII_ADDR_C45))
7618c2ecf20Sopenharmony_ci		goto mii_bus_write_done;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	cmd = hwaddr | IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND;
7648c2ecf20Sopenharmony_ci	err = ixgbe_msca_cmd(hw, cmd);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cimii_bus_write_done:
7678c2ecf20Sopenharmony_ci	hw->mac.ops.release_swfw_sync(hw, gssr);
7688c2ecf20Sopenharmony_ci	return err;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci/**
7728c2ecf20Sopenharmony_ci *  ixgbe_mii_bus_read - Read a clause 22/45 register
7738c2ecf20Sopenharmony_ci *  @bus: pointer to mii_bus structure which points to our driver private
7748c2ecf20Sopenharmony_ci *  @addr: address
7758c2ecf20Sopenharmony_ci *  @regnum: register number
7768c2ecf20Sopenharmony_ci **/
7778c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_read(struct mii_bus *bus, int addr, int regnum)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = bus->priv;
7808c2ecf20Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
7818c2ecf20Sopenharmony_ci	u32 gssr = hw->phy.phy_semaphore_mask;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	return ixgbe_mii_bus_read_generic(hw, addr, regnum, gssr);
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci/**
7878c2ecf20Sopenharmony_ci *  ixgbe_mii_bus_write - Write a clause 22/45 register
7888c2ecf20Sopenharmony_ci *  @bus: pointer to mii_bus structure which points to our driver private
7898c2ecf20Sopenharmony_ci *  @addr: address
7908c2ecf20Sopenharmony_ci *  @regnum: register number
7918c2ecf20Sopenharmony_ci *  @val: value to write
7928c2ecf20Sopenharmony_ci **/
7938c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_write(struct mii_bus *bus, int addr, int regnum,
7948c2ecf20Sopenharmony_ci			       u16 val)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = bus->priv;
7978c2ecf20Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
7988c2ecf20Sopenharmony_ci	u32 gssr = hw->phy.phy_semaphore_mask;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	return ixgbe_mii_bus_write_generic(hw, addr, regnum, val, gssr);
8018c2ecf20Sopenharmony_ci}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci/**
8048c2ecf20Sopenharmony_ci *  ixgbe_x550em_a_mii_bus_read - Read a clause 22/45 register on x550em_a
8058c2ecf20Sopenharmony_ci *  @bus: pointer to mii_bus structure which points to our driver private
8068c2ecf20Sopenharmony_ci *  @addr: address
8078c2ecf20Sopenharmony_ci *  @regnum: register number
8088c2ecf20Sopenharmony_ci **/
8098c2ecf20Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_read(struct mii_bus *bus, int addr,
8108c2ecf20Sopenharmony_ci				       int regnum)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = bus->priv;
8138c2ecf20Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
8148c2ecf20Sopenharmony_ci	u32 gssr = hw->phy.phy_semaphore_mask;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM;
8178c2ecf20Sopenharmony_ci	return ixgbe_mii_bus_read_generic(hw, addr, regnum, gssr);
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci/**
8218c2ecf20Sopenharmony_ci *  ixgbe_x550em_a_mii_bus_write - Write a clause 22/45 register on x550em_a
8228c2ecf20Sopenharmony_ci *  @bus: pointer to mii_bus structure which points to our driver private
8238c2ecf20Sopenharmony_ci *  @addr: address
8248c2ecf20Sopenharmony_ci *  @regnum: register number
8258c2ecf20Sopenharmony_ci *  @val: value to write
8268c2ecf20Sopenharmony_ci **/
8278c2ecf20Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_write(struct mii_bus *bus, int addr,
8288c2ecf20Sopenharmony_ci					int regnum, u16 val)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = bus->priv;
8318c2ecf20Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
8328c2ecf20Sopenharmony_ci	u32 gssr = hw->phy.phy_semaphore_mask;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM;
8358c2ecf20Sopenharmony_ci	return ixgbe_mii_bus_write_generic(hw, addr, regnum, val, gssr);
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci/**
8398c2ecf20Sopenharmony_ci * ixgbe_get_first_secondary_devfn - get first device downstream of root port
8408c2ecf20Sopenharmony_ci * @devfn: PCI_DEVFN of root port on domain 0, bus 0
8418c2ecf20Sopenharmony_ci *
8428c2ecf20Sopenharmony_ci * Returns pci_dev pointer to PCI_DEVFN(0, 0) on subordinate side of root
8438c2ecf20Sopenharmony_ci * on domain 0, bus 0, devfn = 'devfn'
8448c2ecf20Sopenharmony_ci **/
8458c2ecf20Sopenharmony_cistatic struct pci_dev *ixgbe_get_first_secondary_devfn(unsigned int devfn)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct pci_dev *rp_pdev;
8488c2ecf20Sopenharmony_ci	int bus;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn);
8518c2ecf20Sopenharmony_ci	if (rp_pdev && rp_pdev->subordinate) {
8528c2ecf20Sopenharmony_ci		bus = rp_pdev->subordinate->number;
8538c2ecf20Sopenharmony_ci		pci_dev_put(rp_pdev);
8548c2ecf20Sopenharmony_ci		return pci_get_domain_bus_and_slot(0, bus, 0);
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	pci_dev_put(rp_pdev);
8588c2ecf20Sopenharmony_ci	return NULL;
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci/**
8628c2ecf20Sopenharmony_ci * ixgbe_x550em_a_has_mii - is this the first ixgbe x550em_a PCI function?
8638c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure
8648c2ecf20Sopenharmony_ci *
8658c2ecf20Sopenharmony_ci * Returns true if hw points to lowest numbered PCI B:D.F x550_em_a device in
8668c2ecf20Sopenharmony_ci * the SoC.  There are up to 4 MACs sharing a single MDIO bus on the x550em_a,
8678c2ecf20Sopenharmony_ci * but we only want to register one MDIO bus.
8688c2ecf20Sopenharmony_ci **/
8698c2ecf20Sopenharmony_cistatic bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = hw->back;
8728c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
8738c2ecf20Sopenharmony_ci	struct pci_dev *func0_pdev;
8748c2ecf20Sopenharmony_ci	bool has_mii = false;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices
8778c2ecf20Sopenharmony_ci	 * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0
8788c2ecf20Sopenharmony_ci	 * It's not valid for function 0 to be disabled and function 1 is up,
8798c2ecf20Sopenharmony_ci	 * so the lowest numbered ixgbe dev will be device 0 function 0 on one
8808c2ecf20Sopenharmony_ci	 * of those two root ports
8818c2ecf20Sopenharmony_ci	 */
8828c2ecf20Sopenharmony_ci	func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0));
8838c2ecf20Sopenharmony_ci	if (func0_pdev) {
8848c2ecf20Sopenharmony_ci		if (func0_pdev == pdev)
8858c2ecf20Sopenharmony_ci			has_mii = true;
8868c2ecf20Sopenharmony_ci		goto out;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci	func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0));
8898c2ecf20Sopenharmony_ci	if (func0_pdev == pdev)
8908c2ecf20Sopenharmony_ci		has_mii = true;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ciout:
8938c2ecf20Sopenharmony_ci	pci_dev_put(func0_pdev);
8948c2ecf20Sopenharmony_ci	return has_mii;
8958c2ecf20Sopenharmony_ci}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci/**
8988c2ecf20Sopenharmony_ci * ixgbe_mii_bus_init - mii_bus structure setup
8998c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure
9008c2ecf20Sopenharmony_ci *
9018c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure
9028c2ecf20Sopenharmony_ci *
9038c2ecf20Sopenharmony_ci * ixgbe_mii_bus_init initializes a mii_bus structure in adapter
9048c2ecf20Sopenharmony_ci **/
9058c2ecf20Sopenharmony_cis32 ixgbe_mii_bus_init(struct ixgbe_hw *hw)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	s32 (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
9088c2ecf20Sopenharmony_ci	s32 (*read)(struct mii_bus *bus, int addr, int regnum);
9098c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = hw->back;
9108c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
9118c2ecf20Sopenharmony_ci	struct device *dev = &adapter->netdev->dev;
9128c2ecf20Sopenharmony_ci	struct mii_bus *bus;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	switch (hw->device_id) {
9158c2ecf20Sopenharmony_ci	/* C3000 SoCs */
9168c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_KR:
9178c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_KR_L:
9188c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_SFP_N:
9198c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_SGMII:
9208c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
9218c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_10G_T:
9228c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_SFP:
9238c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_1G_T:
9248c2ecf20Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
9258c2ecf20Sopenharmony_ci		if (!ixgbe_x550em_a_has_mii(hw))
9268c2ecf20Sopenharmony_ci			return 0;
9278c2ecf20Sopenharmony_ci		read = &ixgbe_x550em_a_mii_bus_read;
9288c2ecf20Sopenharmony_ci		write = &ixgbe_x550em_a_mii_bus_write;
9298c2ecf20Sopenharmony_ci		break;
9308c2ecf20Sopenharmony_ci	default:
9318c2ecf20Sopenharmony_ci		read = &ixgbe_mii_bus_read;
9328c2ecf20Sopenharmony_ci		write = &ixgbe_mii_bus_write;
9338c2ecf20Sopenharmony_ci		break;
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	bus = devm_mdiobus_alloc(dev);
9378c2ecf20Sopenharmony_ci	if (!bus)
9388c2ecf20Sopenharmony_ci		return -ENOMEM;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	bus->read = read;
9418c2ecf20Sopenharmony_ci	bus->write = write;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* Use the position of the device in the PCI hierarchy as the id */
9448c2ecf20Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mdio-%s", ixgbe_driver_name,
9458c2ecf20Sopenharmony_ci		 pci_name(pdev));
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	bus->name = "ixgbe-mdio";
9488c2ecf20Sopenharmony_ci	bus->priv = adapter;
9498c2ecf20Sopenharmony_ci	bus->parent = dev;
9508c2ecf20Sopenharmony_ci	bus->phy_mask = GENMASK(31, 0);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	/* Support clause 22/45 natively.  ixgbe_probe() sets MDIO_EMULATE_C22
9538c2ecf20Sopenharmony_ci	 * unfortunately that causes some clause 22 frames to be sent with
9548c2ecf20Sopenharmony_ci	 * clause 45 addressing.  We don't want that.
9558c2ecf20Sopenharmony_ci	 */
9568c2ecf20Sopenharmony_ci	hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	adapter->mii_bus = bus;
9598c2ecf20Sopenharmony_ci	return mdiobus_register(bus);
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci/**
9638c2ecf20Sopenharmony_ci *  ixgbe_setup_phy_link_generic - Set and restart autoneg
9648c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
9658c2ecf20Sopenharmony_ci *
9668c2ecf20Sopenharmony_ci *  Restart autonegotiation and PHY and waits for completion.
9678c2ecf20Sopenharmony_ci **/
9688c2ecf20Sopenharmony_cis32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	s32 status = 0;
9718c2ecf20Sopenharmony_ci	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
9728c2ecf20Sopenharmony_ci	bool autoneg = false;
9738c2ecf20Sopenharmony_ci	ixgbe_link_speed speed;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	/* Set or unset auto-negotiation 10G advertisement */
9788c2ecf20Sopenharmony_ci	hw->phy.ops.read_reg(hw, MDIO_AN_10GBT_CTRL, MDIO_MMD_AN, &autoneg_reg);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G;
9818c2ecf20Sopenharmony_ci	if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) &&
9828c2ecf20Sopenharmony_ci	    (speed & IXGBE_LINK_SPEED_10GB_FULL))
9838c2ecf20Sopenharmony_ci		autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, MDIO_AN_10GBT_CTRL, MDIO_MMD_AN, autoneg_reg);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
9888c2ecf20Sopenharmony_ci			     MDIO_MMD_AN, &autoneg_reg);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	if (hw->mac.type == ixgbe_mac_X550) {
9918c2ecf20Sopenharmony_ci		/* Set or unset auto-negotiation 5G advertisement */
9928c2ecf20Sopenharmony_ci		autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE;
9938c2ecf20Sopenharmony_ci		if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) &&
9948c2ecf20Sopenharmony_ci		    (speed & IXGBE_LINK_SPEED_5GB_FULL))
9958c2ecf20Sopenharmony_ci			autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		/* Set or unset auto-negotiation 2.5G advertisement */
9988c2ecf20Sopenharmony_ci		autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE;
9998c2ecf20Sopenharmony_ci		if ((hw->phy.autoneg_advertised &
10008c2ecf20Sopenharmony_ci		     IXGBE_LINK_SPEED_2_5GB_FULL) &&
10018c2ecf20Sopenharmony_ci		    (speed & IXGBE_LINK_SPEED_2_5GB_FULL))
10028c2ecf20Sopenharmony_ci			autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	/* Set or unset auto-negotiation 1G advertisement */
10068c2ecf20Sopenharmony_ci	autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE;
10078c2ecf20Sopenharmony_ci	if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) &&
10088c2ecf20Sopenharmony_ci	    (speed & IXGBE_LINK_SPEED_1GB_FULL))
10098c2ecf20Sopenharmony_ci		autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
10128c2ecf20Sopenharmony_ci			      MDIO_MMD_AN, autoneg_reg);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	/* Set or unset auto-negotiation 100M advertisement */
10158c2ecf20Sopenharmony_ci	hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, &autoneg_reg);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	autoneg_reg &= ~(ADVERTISE_100FULL | ADVERTISE_100HALF);
10188c2ecf20Sopenharmony_ci	if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) &&
10198c2ecf20Sopenharmony_ci	    (speed & IXGBE_LINK_SPEED_100_FULL))
10208c2ecf20Sopenharmony_ci		autoneg_reg |= ADVERTISE_100FULL;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, autoneg_reg);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	/* Blocked by MNG FW so don't reset PHY */
10258c2ecf20Sopenharmony_ci	if (ixgbe_check_reset_blocked(hw))
10268c2ecf20Sopenharmony_ci		return 0;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/* Restart PHY autonegotiation and wait for completion */
10298c2ecf20Sopenharmony_ci	hw->phy.ops.read_reg(hw, MDIO_CTRL1,
10308c2ecf20Sopenharmony_ci			     MDIO_MMD_AN, &autoneg_reg);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	autoneg_reg |= MDIO_AN_CTRL1_RESTART;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, MDIO_CTRL1,
10358c2ecf20Sopenharmony_ci			      MDIO_MMD_AN, autoneg_reg);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	return status;
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci/**
10418c2ecf20Sopenharmony_ci *  ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
10428c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
10438c2ecf20Sopenharmony_ci *  @speed: new link speed
10448c2ecf20Sopenharmony_ci *  @autoneg_wait_to_complete: unused
10458c2ecf20Sopenharmony_ci **/
10468c2ecf20Sopenharmony_cis32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
10478c2ecf20Sopenharmony_ci				       ixgbe_link_speed speed,
10488c2ecf20Sopenharmony_ci				       bool autoneg_wait_to_complete)
10498c2ecf20Sopenharmony_ci{
10508c2ecf20Sopenharmony_ci	/* Clear autoneg_advertised and set new values based on input link
10518c2ecf20Sopenharmony_ci	 * speed.
10528c2ecf20Sopenharmony_ci	 */
10538c2ecf20Sopenharmony_ci	hw->phy.autoneg_advertised = 0;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
10568c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_5GB_FULL)
10598c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_2_5GB_FULL)
10628c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_1GB_FULL)
10658c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_100_FULL)
10688c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_10_FULL)
10718c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	/* Setup link based on the new speed settings */
10748c2ecf20Sopenharmony_ci	if (hw->phy.ops.setup_link)
10758c2ecf20Sopenharmony_ci		hw->phy.ops.setup_link(hw);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	return 0;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci/**
10818c2ecf20Sopenharmony_ci * ixgbe_get_copper_speeds_supported - Get copper link speed from phy
10828c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure
10838c2ecf20Sopenharmony_ci *
10848c2ecf20Sopenharmony_ci * Determines the supported link capabilities by reading the PHY auto
10858c2ecf20Sopenharmony_ci * negotiation register.
10868c2ecf20Sopenharmony_ci */
10878c2ecf20Sopenharmony_cistatic s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	u16 speed_ability;
10908c2ecf20Sopenharmony_ci	s32 status;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD,
10938c2ecf20Sopenharmony_ci				      &speed_ability);
10948c2ecf20Sopenharmony_ci	if (status)
10958c2ecf20Sopenharmony_ci		return status;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (speed_ability & MDIO_SPEED_10G)
10988c2ecf20Sopenharmony_ci		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
10998c2ecf20Sopenharmony_ci	if (speed_ability & MDIO_PMA_SPEED_1000)
11008c2ecf20Sopenharmony_ci		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
11018c2ecf20Sopenharmony_ci	if (speed_ability & MDIO_PMA_SPEED_100)
11028c2ecf20Sopenharmony_ci		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
11058c2ecf20Sopenharmony_ci	case ixgbe_mac_X550:
11068c2ecf20Sopenharmony_ci		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
11078c2ecf20Sopenharmony_ci		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	case ixgbe_mac_X550EM_x:
11108c2ecf20Sopenharmony_ci	case ixgbe_mac_x550em_a:
11118c2ecf20Sopenharmony_ci		hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL;
11128c2ecf20Sopenharmony_ci		break;
11138c2ecf20Sopenharmony_ci	default:
11148c2ecf20Sopenharmony_ci		break;
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	return 0;
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/**
11218c2ecf20Sopenharmony_ci * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
11228c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure
11238c2ecf20Sopenharmony_ci * @speed: pointer to link speed
11248c2ecf20Sopenharmony_ci * @autoneg: boolean auto-negotiation value
11258c2ecf20Sopenharmony_ci */
11268c2ecf20Sopenharmony_cis32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
11278c2ecf20Sopenharmony_ci					       ixgbe_link_speed *speed,
11288c2ecf20Sopenharmony_ci					       bool *autoneg)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	s32 status = 0;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	*autoneg = true;
11338c2ecf20Sopenharmony_ci	if (!hw->phy.speeds_supported)
11348c2ecf20Sopenharmony_ci		status = ixgbe_get_copper_speeds_supported(hw);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	*speed = hw->phy.speeds_supported;
11378c2ecf20Sopenharmony_ci	return status;
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci/**
11418c2ecf20Sopenharmony_ci *  ixgbe_check_phy_link_tnx - Determine link and speed status
11428c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
11438c2ecf20Sopenharmony_ci *  @speed: link speed
11448c2ecf20Sopenharmony_ci *  @link_up: status of link
11458c2ecf20Sopenharmony_ci *
11468c2ecf20Sopenharmony_ci *  Reads the VS1 register to determine if link is up and the current speed for
11478c2ecf20Sopenharmony_ci *  the PHY.
11488c2ecf20Sopenharmony_ci **/
11498c2ecf20Sopenharmony_cis32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
11508c2ecf20Sopenharmony_ci			     bool *link_up)
11518c2ecf20Sopenharmony_ci{
11528c2ecf20Sopenharmony_ci	s32 status;
11538c2ecf20Sopenharmony_ci	u32 time_out;
11548c2ecf20Sopenharmony_ci	u32 max_time_out = 10;
11558c2ecf20Sopenharmony_ci	u16 phy_link = 0;
11568c2ecf20Sopenharmony_ci	u16 phy_speed = 0;
11578c2ecf20Sopenharmony_ci	u16 phy_data = 0;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	/* Initialize speed and link to default case */
11608c2ecf20Sopenharmony_ci	*link_up = false;
11618c2ecf20Sopenharmony_ci	*speed = IXGBE_LINK_SPEED_10GB_FULL;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	/*
11648c2ecf20Sopenharmony_ci	 * Check current speed and link status of the PHY register.
11658c2ecf20Sopenharmony_ci	 * This is a vendor specific register and may have to
11668c2ecf20Sopenharmony_ci	 * be changed for other copper PHYs.
11678c2ecf20Sopenharmony_ci	 */
11688c2ecf20Sopenharmony_ci	for (time_out = 0; time_out < max_time_out; time_out++) {
11698c2ecf20Sopenharmony_ci		udelay(10);
11708c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_reg(hw,
11718c2ecf20Sopenharmony_ci					      MDIO_STAT1,
11728c2ecf20Sopenharmony_ci					      MDIO_MMD_VEND1,
11738c2ecf20Sopenharmony_ci					      &phy_data);
11748c2ecf20Sopenharmony_ci		phy_link = phy_data &
11758c2ecf20Sopenharmony_ci			    IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
11768c2ecf20Sopenharmony_ci		phy_speed = phy_data &
11778c2ecf20Sopenharmony_ci			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
11788c2ecf20Sopenharmony_ci		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
11798c2ecf20Sopenharmony_ci			*link_up = true;
11808c2ecf20Sopenharmony_ci			if (phy_speed ==
11818c2ecf20Sopenharmony_ci			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
11828c2ecf20Sopenharmony_ci				*speed = IXGBE_LINK_SPEED_1GB_FULL;
11838c2ecf20Sopenharmony_ci			break;
11848c2ecf20Sopenharmony_ci		}
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	return status;
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci/**
11918c2ecf20Sopenharmony_ci *	ixgbe_setup_phy_link_tnx - Set and restart autoneg
11928c2ecf20Sopenharmony_ci *	@hw: pointer to hardware structure
11938c2ecf20Sopenharmony_ci *
11948c2ecf20Sopenharmony_ci *	Restart autonegotiation and PHY and waits for completion.
11958c2ecf20Sopenharmony_ci *      This function always returns success, this is nessary since
11968c2ecf20Sopenharmony_ci *	it is called via a function pointer that could call other
11978c2ecf20Sopenharmony_ci *	functions that could return an error.
11988c2ecf20Sopenharmony_ci **/
11998c2ecf20Sopenharmony_cis32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
12028c2ecf20Sopenharmony_ci	bool autoneg = false;
12038c2ecf20Sopenharmony_ci	ixgbe_link_speed speed;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
12088c2ecf20Sopenharmony_ci		/* Set or unset auto-negotiation 10G advertisement */
12098c2ecf20Sopenharmony_ci		hw->phy.ops.read_reg(hw, MDIO_AN_10GBT_CTRL,
12108c2ecf20Sopenharmony_ci				     MDIO_MMD_AN,
12118c2ecf20Sopenharmony_ci				     &autoneg_reg);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci		autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G;
12148c2ecf20Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
12158c2ecf20Sopenharmony_ci			autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci		hw->phy.ops.write_reg(hw, MDIO_AN_10GBT_CTRL,
12188c2ecf20Sopenharmony_ci				      MDIO_MMD_AN,
12198c2ecf20Sopenharmony_ci				      autoneg_reg);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
12238c2ecf20Sopenharmony_ci		/* Set or unset auto-negotiation 1G advertisement */
12248c2ecf20Sopenharmony_ci		hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
12258c2ecf20Sopenharmony_ci				     MDIO_MMD_AN,
12268c2ecf20Sopenharmony_ci				     &autoneg_reg);
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci		autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
12298c2ecf20Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
12308c2ecf20Sopenharmony_ci			autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci		hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
12338c2ecf20Sopenharmony_ci				      MDIO_MMD_AN,
12348c2ecf20Sopenharmony_ci				      autoneg_reg);
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (speed & IXGBE_LINK_SPEED_100_FULL) {
12388c2ecf20Sopenharmony_ci		/* Set or unset auto-negotiation 100M advertisement */
12398c2ecf20Sopenharmony_ci		hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE,
12408c2ecf20Sopenharmony_ci				     MDIO_MMD_AN,
12418c2ecf20Sopenharmony_ci				     &autoneg_reg);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci		autoneg_reg &= ~(ADVERTISE_100FULL |
12448c2ecf20Sopenharmony_ci				 ADVERTISE_100HALF);
12458c2ecf20Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
12468c2ecf20Sopenharmony_ci			autoneg_reg |= ADVERTISE_100FULL;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci		hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE,
12498c2ecf20Sopenharmony_ci				      MDIO_MMD_AN,
12508c2ecf20Sopenharmony_ci				      autoneg_reg);
12518c2ecf20Sopenharmony_ci	}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	/* Blocked by MNG FW so don't reset PHY */
12548c2ecf20Sopenharmony_ci	if (ixgbe_check_reset_blocked(hw))
12558c2ecf20Sopenharmony_ci		return 0;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	/* Restart PHY autonegotiation and wait for completion */
12588c2ecf20Sopenharmony_ci	hw->phy.ops.read_reg(hw, MDIO_CTRL1,
12598c2ecf20Sopenharmony_ci			     MDIO_MMD_AN, &autoneg_reg);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	autoneg_reg |= MDIO_AN_CTRL1_RESTART;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, MDIO_CTRL1,
12648c2ecf20Sopenharmony_ci			      MDIO_MMD_AN, autoneg_reg);
12658c2ecf20Sopenharmony_ci	return 0;
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci/**
12698c2ecf20Sopenharmony_ci *  ixgbe_reset_phy_nl - Performs a PHY reset
12708c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
12718c2ecf20Sopenharmony_ci **/
12728c2ecf20Sopenharmony_cis32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	u16 phy_offset, control, eword, edata, block_crc;
12758c2ecf20Sopenharmony_ci	bool end_data = false;
12768c2ecf20Sopenharmony_ci	u16 list_offset, data_offset;
12778c2ecf20Sopenharmony_ci	u16 phy_data = 0;
12788c2ecf20Sopenharmony_ci	s32 ret_val;
12798c2ecf20Sopenharmony_ci	u32 i;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	/* Blocked by MNG FW so bail */
12828c2ecf20Sopenharmony_ci	if (ixgbe_check_reset_blocked(hw))
12838c2ecf20Sopenharmony_ci		return 0;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	/* reset the PHY and poll for completion */
12888c2ecf20Sopenharmony_ci	hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS,
12898c2ecf20Sopenharmony_ci			      (phy_data | MDIO_CTRL1_RESET));
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	for (i = 0; i < 100; i++) {
12928c2ecf20Sopenharmony_ci		hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS,
12938c2ecf20Sopenharmony_ci				     &phy_data);
12948c2ecf20Sopenharmony_ci		if ((phy_data & MDIO_CTRL1_RESET) == 0)
12958c2ecf20Sopenharmony_ci			break;
12968c2ecf20Sopenharmony_ci		usleep_range(10000, 20000);
12978c2ecf20Sopenharmony_ci	}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	if ((phy_data & MDIO_CTRL1_RESET) != 0) {
13008c2ecf20Sopenharmony_ci		hw_dbg(hw, "PHY reset did not complete.\n");
13018c2ecf20Sopenharmony_ci		return -EIO;
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	/* Get init offsets */
13058c2ecf20Sopenharmony_ci	ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
13068c2ecf20Sopenharmony_ci						      &data_offset);
13078c2ecf20Sopenharmony_ci	if (ret_val)
13088c2ecf20Sopenharmony_ci		return ret_val;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
13118c2ecf20Sopenharmony_ci	data_offset++;
13128c2ecf20Sopenharmony_ci	while (!end_data) {
13138c2ecf20Sopenharmony_ci		/*
13148c2ecf20Sopenharmony_ci		 * Read control word from PHY init contents offset
13158c2ecf20Sopenharmony_ci		 */
13168c2ecf20Sopenharmony_ci		ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
13178c2ecf20Sopenharmony_ci		if (ret_val)
13188c2ecf20Sopenharmony_ci			goto err_eeprom;
13198c2ecf20Sopenharmony_ci		control = (eword & IXGBE_CONTROL_MASK_NL) >>
13208c2ecf20Sopenharmony_ci			   IXGBE_CONTROL_SHIFT_NL;
13218c2ecf20Sopenharmony_ci		edata = eword & IXGBE_DATA_MASK_NL;
13228c2ecf20Sopenharmony_ci		switch (control) {
13238c2ecf20Sopenharmony_ci		case IXGBE_DELAY_NL:
13248c2ecf20Sopenharmony_ci			data_offset++;
13258c2ecf20Sopenharmony_ci			hw_dbg(hw, "DELAY: %d MS\n", edata);
13268c2ecf20Sopenharmony_ci			usleep_range(edata * 1000, edata * 2000);
13278c2ecf20Sopenharmony_ci			break;
13288c2ecf20Sopenharmony_ci		case IXGBE_DATA_NL:
13298c2ecf20Sopenharmony_ci			hw_dbg(hw, "DATA:\n");
13308c2ecf20Sopenharmony_ci			data_offset++;
13318c2ecf20Sopenharmony_ci			ret_val = hw->eeprom.ops.read(hw, data_offset++,
13328c2ecf20Sopenharmony_ci						      &phy_offset);
13338c2ecf20Sopenharmony_ci			if (ret_val)
13348c2ecf20Sopenharmony_ci				goto err_eeprom;
13358c2ecf20Sopenharmony_ci			for (i = 0; i < edata; i++) {
13368c2ecf20Sopenharmony_ci				ret_val = hw->eeprom.ops.read(hw, data_offset,
13378c2ecf20Sopenharmony_ci							      &eword);
13388c2ecf20Sopenharmony_ci				if (ret_val)
13398c2ecf20Sopenharmony_ci					goto err_eeprom;
13408c2ecf20Sopenharmony_ci				hw->phy.ops.write_reg(hw, phy_offset,
13418c2ecf20Sopenharmony_ci						      MDIO_MMD_PMAPMD, eword);
13428c2ecf20Sopenharmony_ci				hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword,
13438c2ecf20Sopenharmony_ci				       phy_offset);
13448c2ecf20Sopenharmony_ci				data_offset++;
13458c2ecf20Sopenharmony_ci				phy_offset++;
13468c2ecf20Sopenharmony_ci			}
13478c2ecf20Sopenharmony_ci			break;
13488c2ecf20Sopenharmony_ci		case IXGBE_CONTROL_NL:
13498c2ecf20Sopenharmony_ci			data_offset++;
13508c2ecf20Sopenharmony_ci			hw_dbg(hw, "CONTROL:\n");
13518c2ecf20Sopenharmony_ci			if (edata == IXGBE_CONTROL_EOL_NL) {
13528c2ecf20Sopenharmony_ci				hw_dbg(hw, "EOL\n");
13538c2ecf20Sopenharmony_ci				end_data = true;
13548c2ecf20Sopenharmony_ci			} else if (edata == IXGBE_CONTROL_SOL_NL) {
13558c2ecf20Sopenharmony_ci				hw_dbg(hw, "SOL\n");
13568c2ecf20Sopenharmony_ci			} else {
13578c2ecf20Sopenharmony_ci				hw_dbg(hw, "Bad control value\n");
13588c2ecf20Sopenharmony_ci				return -EIO;
13598c2ecf20Sopenharmony_ci			}
13608c2ecf20Sopenharmony_ci			break;
13618c2ecf20Sopenharmony_ci		default:
13628c2ecf20Sopenharmony_ci			hw_dbg(hw, "Bad control type\n");
13638c2ecf20Sopenharmony_ci			return -EIO;
13648c2ecf20Sopenharmony_ci		}
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	return ret_val;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cierr_eeprom:
13708c2ecf20Sopenharmony_ci	hw_err(hw, "eeprom read at offset %d failed\n", data_offset);
13718c2ecf20Sopenharmony_ci	return -EIO;
13728c2ecf20Sopenharmony_ci}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci/**
13758c2ecf20Sopenharmony_ci *  ixgbe_identify_module_generic - Identifies module type
13768c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
13778c2ecf20Sopenharmony_ci *
13788c2ecf20Sopenharmony_ci *  Determines HW type and calls appropriate function.
13798c2ecf20Sopenharmony_ci **/
13808c2ecf20Sopenharmony_cis32 ixgbe_identify_module_generic(struct ixgbe_hw *hw)
13818c2ecf20Sopenharmony_ci{
13828c2ecf20Sopenharmony_ci	switch (hw->mac.ops.get_media_type(hw)) {
13838c2ecf20Sopenharmony_ci	case ixgbe_media_type_fiber:
13848c2ecf20Sopenharmony_ci		return ixgbe_identify_sfp_module_generic(hw);
13858c2ecf20Sopenharmony_ci	case ixgbe_media_type_fiber_qsfp:
13868c2ecf20Sopenharmony_ci		return ixgbe_identify_qsfp_module_generic(hw);
13878c2ecf20Sopenharmony_ci	default:
13888c2ecf20Sopenharmony_ci		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
13898c2ecf20Sopenharmony_ci		return -ENOENT;
13908c2ecf20Sopenharmony_ci	}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	return -ENOENT;
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci/**
13968c2ecf20Sopenharmony_ci *  ixgbe_identify_sfp_module_generic - Identifies SFP modules
13978c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
13988c2ecf20Sopenharmony_ci *
13998c2ecf20Sopenharmony_ci *  Searches for and identifies the SFP module and assigns appropriate PHY type.
14008c2ecf20Sopenharmony_ci **/
14018c2ecf20Sopenharmony_cis32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = hw->back;
14048c2ecf20Sopenharmony_ci	s32 status;
14058c2ecf20Sopenharmony_ci	u32 vendor_oui = 0;
14068c2ecf20Sopenharmony_ci	enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
14078c2ecf20Sopenharmony_ci	u8 identifier = 0;
14088c2ecf20Sopenharmony_ci	u8 comp_codes_1g = 0;
14098c2ecf20Sopenharmony_ci	u8 comp_codes_10g = 0;
14108c2ecf20Sopenharmony_ci	u8 oui_bytes[3] = {0, 0, 0};
14118c2ecf20Sopenharmony_ci	u8 cable_tech = 0;
14128c2ecf20Sopenharmony_ci	u8 cable_spec = 0;
14138c2ecf20Sopenharmony_ci	u16 enforce_sfp = 0;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
14168c2ecf20Sopenharmony_ci		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
14178c2ecf20Sopenharmony_ci		return -ENOENT;
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	/* LAN ID is needed for sfp_type determination */
14218c2ecf20Sopenharmony_ci	hw->mac.ops.set_lan_id(hw);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw,
14248c2ecf20Sopenharmony_ci					     IXGBE_SFF_IDENTIFIER,
14258c2ecf20Sopenharmony_ci					     &identifier);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	if (status)
14288c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
14318c2ecf20Sopenharmony_ci		hw->phy.type = ixgbe_phy_sfp_unsupported;
14328c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14338c2ecf20Sopenharmony_ci	}
14348c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw,
14358c2ecf20Sopenharmony_ci					     IXGBE_SFF_1GBE_COMP_CODES,
14368c2ecf20Sopenharmony_ci					     &comp_codes_1g);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	if (status)
14398c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw,
14428c2ecf20Sopenharmony_ci					     IXGBE_SFF_10GBE_COMP_CODES,
14438c2ecf20Sopenharmony_ci					     &comp_codes_10g);
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	if (status)
14468c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
14478c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw,
14488c2ecf20Sopenharmony_ci					     IXGBE_SFF_CABLE_TECHNOLOGY,
14498c2ecf20Sopenharmony_ci					     &cable_tech);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	if (status)
14528c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	 /* ID Module
14558c2ecf20Sopenharmony_ci	  * =========
14568c2ecf20Sopenharmony_ci	  * 0   SFP_DA_CU
14578c2ecf20Sopenharmony_ci	  * 1   SFP_SR
14588c2ecf20Sopenharmony_ci	  * 2   SFP_LR
14598c2ecf20Sopenharmony_ci	  * 3   SFP_DA_CORE0 - 82599-specific
14608c2ecf20Sopenharmony_ci	  * 4   SFP_DA_CORE1 - 82599-specific
14618c2ecf20Sopenharmony_ci	  * 5   SFP_SR/LR_CORE0 - 82599-specific
14628c2ecf20Sopenharmony_ci	  * 6   SFP_SR/LR_CORE1 - 82599-specific
14638c2ecf20Sopenharmony_ci	  * 7   SFP_act_lmt_DA_CORE0 - 82599-specific
14648c2ecf20Sopenharmony_ci	  * 8   SFP_act_lmt_DA_CORE1 - 82599-specific
14658c2ecf20Sopenharmony_ci	  * 9   SFP_1g_cu_CORE0 - 82599-specific
14668c2ecf20Sopenharmony_ci	  * 10  SFP_1g_cu_CORE1 - 82599-specific
14678c2ecf20Sopenharmony_ci	  * 11  SFP_1g_sx_CORE0 - 82599-specific
14688c2ecf20Sopenharmony_ci	  * 12  SFP_1g_sx_CORE1 - 82599-specific
14698c2ecf20Sopenharmony_ci	  */
14708c2ecf20Sopenharmony_ci	if (hw->mac.type == ixgbe_mac_82598EB) {
14718c2ecf20Sopenharmony_ci		if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
14728c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
14738c2ecf20Sopenharmony_ci		else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
14748c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_sr;
14758c2ecf20Sopenharmony_ci		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
14768c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_lr;
14778c2ecf20Sopenharmony_ci		else
14788c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_unknown;
14798c2ecf20Sopenharmony_ci	} else {
14808c2ecf20Sopenharmony_ci		if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) {
14818c2ecf20Sopenharmony_ci			if (hw->bus.lan_id == 0)
14828c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
14838c2ecf20Sopenharmony_ci					     ixgbe_sfp_type_da_cu_core0;
14848c2ecf20Sopenharmony_ci			else
14858c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
14868c2ecf20Sopenharmony_ci					     ixgbe_sfp_type_da_cu_core1;
14878c2ecf20Sopenharmony_ci		} else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) {
14888c2ecf20Sopenharmony_ci			hw->phy.ops.read_i2c_eeprom(
14898c2ecf20Sopenharmony_ci					hw, IXGBE_SFF_CABLE_SPEC_COMP,
14908c2ecf20Sopenharmony_ci					&cable_spec);
14918c2ecf20Sopenharmony_ci			if (cable_spec &
14928c2ecf20Sopenharmony_ci			    IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
14938c2ecf20Sopenharmony_ci				if (hw->bus.lan_id == 0)
14948c2ecf20Sopenharmony_ci					hw->phy.sfp_type =
14958c2ecf20Sopenharmony_ci					ixgbe_sfp_type_da_act_lmt_core0;
14968c2ecf20Sopenharmony_ci				else
14978c2ecf20Sopenharmony_ci					hw->phy.sfp_type =
14988c2ecf20Sopenharmony_ci					ixgbe_sfp_type_da_act_lmt_core1;
14998c2ecf20Sopenharmony_ci			} else {
15008c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15018c2ecf20Sopenharmony_ci						ixgbe_sfp_type_unknown;
15028c2ecf20Sopenharmony_ci			}
15038c2ecf20Sopenharmony_ci		} else if (comp_codes_10g &
15048c2ecf20Sopenharmony_ci			   (IXGBE_SFF_10GBASESR_CAPABLE |
15058c2ecf20Sopenharmony_ci			    IXGBE_SFF_10GBASELR_CAPABLE)) {
15068c2ecf20Sopenharmony_ci			if (hw->bus.lan_id == 0)
15078c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15088c2ecf20Sopenharmony_ci					      ixgbe_sfp_type_srlr_core0;
15098c2ecf20Sopenharmony_ci			else
15108c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15118c2ecf20Sopenharmony_ci					      ixgbe_sfp_type_srlr_core1;
15128c2ecf20Sopenharmony_ci		} else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) {
15138c2ecf20Sopenharmony_ci			if (hw->bus.lan_id == 0)
15148c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15158c2ecf20Sopenharmony_ci					ixgbe_sfp_type_1g_cu_core0;
15168c2ecf20Sopenharmony_ci			else
15178c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15188c2ecf20Sopenharmony_ci					ixgbe_sfp_type_1g_cu_core1;
15198c2ecf20Sopenharmony_ci		} else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) {
15208c2ecf20Sopenharmony_ci			if (hw->bus.lan_id == 0)
15218c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15228c2ecf20Sopenharmony_ci					ixgbe_sfp_type_1g_sx_core0;
15238c2ecf20Sopenharmony_ci			else
15248c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15258c2ecf20Sopenharmony_ci					ixgbe_sfp_type_1g_sx_core1;
15268c2ecf20Sopenharmony_ci		} else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) {
15278c2ecf20Sopenharmony_ci			if (hw->bus.lan_id == 0)
15288c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15298c2ecf20Sopenharmony_ci					ixgbe_sfp_type_1g_lx_core0;
15308c2ecf20Sopenharmony_ci			else
15318c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
15328c2ecf20Sopenharmony_ci					ixgbe_sfp_type_1g_lx_core1;
15338c2ecf20Sopenharmony_ci		} else {
15348c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_unknown;
15358c2ecf20Sopenharmony_ci		}
15368c2ecf20Sopenharmony_ci	}
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (hw->phy.sfp_type != stored_sfp_type)
15398c2ecf20Sopenharmony_ci		hw->phy.sfp_setup_needed = true;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	/* Determine if the SFP+ PHY is dual speed or not. */
15428c2ecf20Sopenharmony_ci	hw->phy.multispeed_fiber = false;
15438c2ecf20Sopenharmony_ci	if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
15448c2ecf20Sopenharmony_ci	     (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
15458c2ecf20Sopenharmony_ci	    ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
15468c2ecf20Sopenharmony_ci	     (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
15478c2ecf20Sopenharmony_ci		hw->phy.multispeed_fiber = true;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	/* Determine PHY vendor */
15508c2ecf20Sopenharmony_ci	if (hw->phy.type != ixgbe_phy_nl) {
15518c2ecf20Sopenharmony_ci		hw->phy.id = identifier;
15528c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_i2c_eeprom(hw,
15538c2ecf20Sopenharmony_ci					    IXGBE_SFF_VENDOR_OUI_BYTE0,
15548c2ecf20Sopenharmony_ci					    &oui_bytes[0]);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci		if (status != 0)
15578c2ecf20Sopenharmony_ci			goto err_read_i2c_eeprom;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_i2c_eeprom(hw,
15608c2ecf20Sopenharmony_ci					    IXGBE_SFF_VENDOR_OUI_BYTE1,
15618c2ecf20Sopenharmony_ci					    &oui_bytes[1]);
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci		if (status != 0)
15648c2ecf20Sopenharmony_ci			goto err_read_i2c_eeprom;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_i2c_eeprom(hw,
15678c2ecf20Sopenharmony_ci					    IXGBE_SFF_VENDOR_OUI_BYTE2,
15688c2ecf20Sopenharmony_ci					    &oui_bytes[2]);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci		if (status != 0)
15718c2ecf20Sopenharmony_ci			goto err_read_i2c_eeprom;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci		vendor_oui =
15748c2ecf20Sopenharmony_ci		  ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
15758c2ecf20Sopenharmony_ci		   (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
15768c2ecf20Sopenharmony_ci		   (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci		switch (vendor_oui) {
15798c2ecf20Sopenharmony_ci		case IXGBE_SFF_VENDOR_OUI_TYCO:
15808c2ecf20Sopenharmony_ci			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
15818c2ecf20Sopenharmony_ci				hw->phy.type =
15828c2ecf20Sopenharmony_ci					    ixgbe_phy_sfp_passive_tyco;
15838c2ecf20Sopenharmony_ci			break;
15848c2ecf20Sopenharmony_ci		case IXGBE_SFF_VENDOR_OUI_FTL:
15858c2ecf20Sopenharmony_ci			if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
15868c2ecf20Sopenharmony_ci				hw->phy.type = ixgbe_phy_sfp_ftl_active;
15878c2ecf20Sopenharmony_ci			else
15888c2ecf20Sopenharmony_ci				hw->phy.type = ixgbe_phy_sfp_ftl;
15898c2ecf20Sopenharmony_ci			break;
15908c2ecf20Sopenharmony_ci		case IXGBE_SFF_VENDOR_OUI_AVAGO:
15918c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_sfp_avago;
15928c2ecf20Sopenharmony_ci			break;
15938c2ecf20Sopenharmony_ci		case IXGBE_SFF_VENDOR_OUI_INTEL:
15948c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_sfp_intel;
15958c2ecf20Sopenharmony_ci			break;
15968c2ecf20Sopenharmony_ci		default:
15978c2ecf20Sopenharmony_ci			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
15988c2ecf20Sopenharmony_ci				hw->phy.type =
15998c2ecf20Sopenharmony_ci					 ixgbe_phy_sfp_passive_unknown;
16008c2ecf20Sopenharmony_ci			else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
16018c2ecf20Sopenharmony_ci				hw->phy.type =
16028c2ecf20Sopenharmony_ci					ixgbe_phy_sfp_active_unknown;
16038c2ecf20Sopenharmony_ci			else
16048c2ecf20Sopenharmony_ci				hw->phy.type = ixgbe_phy_sfp_unknown;
16058c2ecf20Sopenharmony_ci			break;
16068c2ecf20Sopenharmony_ci		}
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	/* Allow any DA cable vendor */
16108c2ecf20Sopenharmony_ci	if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
16118c2ecf20Sopenharmony_ci	    IXGBE_SFF_DA_ACTIVE_CABLE))
16128c2ecf20Sopenharmony_ci		return 0;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	/* Verify supported 1G SFP modules */
16158c2ecf20Sopenharmony_ci	if (comp_codes_10g == 0 &&
16168c2ecf20Sopenharmony_ci	    !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
16178c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
16188c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
16198c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
16208c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
16218c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
16228c2ecf20Sopenharmony_ci		hw->phy.type = ixgbe_phy_sfp_unsupported;
16238c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
16248c2ecf20Sopenharmony_ci	}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	/* Anything else 82598-based is supported */
16278c2ecf20Sopenharmony_ci	if (hw->mac.type == ixgbe_mac_82598EB)
16288c2ecf20Sopenharmony_ci		return 0;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	hw->mac.ops.get_device_caps(hw, &enforce_sfp);
16318c2ecf20Sopenharmony_ci	if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
16328c2ecf20Sopenharmony_ci	    !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
16338c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
16348c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
16358c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
16368c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
16378c2ecf20Sopenharmony_ci	      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
16388c2ecf20Sopenharmony_ci		/* Make sure we're a supported PHY type */
16398c2ecf20Sopenharmony_ci		if (hw->phy.type == ixgbe_phy_sfp_intel)
16408c2ecf20Sopenharmony_ci			return 0;
16418c2ecf20Sopenharmony_ci		if (hw->allow_unsupported_sfp) {
16428c2ecf20Sopenharmony_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");
16438c2ecf20Sopenharmony_ci			return 0;
16448c2ecf20Sopenharmony_ci		}
16458c2ecf20Sopenharmony_ci		hw_dbg(hw, "SFP+ module not supported\n");
16468c2ecf20Sopenharmony_ci		hw->phy.type = ixgbe_phy_sfp_unsupported;
16478c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
16488c2ecf20Sopenharmony_ci	}
16498c2ecf20Sopenharmony_ci	return 0;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_cierr_read_i2c_eeprom:
16528c2ecf20Sopenharmony_ci	hw->phy.sfp_type = ixgbe_sfp_type_not_present;
16538c2ecf20Sopenharmony_ci	if (hw->phy.type != ixgbe_phy_nl) {
16548c2ecf20Sopenharmony_ci		hw->phy.id = 0;
16558c2ecf20Sopenharmony_ci		hw->phy.type = ixgbe_phy_unknown;
16568c2ecf20Sopenharmony_ci	}
16578c2ecf20Sopenharmony_ci	return -ENOENT;
16588c2ecf20Sopenharmony_ci}
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci/**
16618c2ecf20Sopenharmony_ci * ixgbe_identify_qsfp_module_generic - Identifies QSFP modules
16628c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure
16638c2ecf20Sopenharmony_ci *
16648c2ecf20Sopenharmony_ci * Searches for and identifies the QSFP module and assigns appropriate PHY type
16658c2ecf20Sopenharmony_ci **/
16668c2ecf20Sopenharmony_cistatic s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	struct ixgbe_adapter *adapter = hw->back;
16698c2ecf20Sopenharmony_ci	s32 status;
16708c2ecf20Sopenharmony_ci	u32 vendor_oui = 0;
16718c2ecf20Sopenharmony_ci	enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
16728c2ecf20Sopenharmony_ci	u8 identifier = 0;
16738c2ecf20Sopenharmony_ci	u8 comp_codes_1g = 0;
16748c2ecf20Sopenharmony_ci	u8 comp_codes_10g = 0;
16758c2ecf20Sopenharmony_ci	u8 oui_bytes[3] = {0, 0, 0};
16768c2ecf20Sopenharmony_ci	u16 enforce_sfp = 0;
16778c2ecf20Sopenharmony_ci	u8 connector = 0;
16788c2ecf20Sopenharmony_ci	u8 cable_length = 0;
16798c2ecf20Sopenharmony_ci	u8 device_tech = 0;
16808c2ecf20Sopenharmony_ci	bool active_cable = false;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) {
16838c2ecf20Sopenharmony_ci		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
16848c2ecf20Sopenharmony_ci		return -ENOENT;
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	/* LAN ID is needed for sfp_type determination */
16888c2ecf20Sopenharmony_ci	hw->mac.ops.set_lan_id(hw);
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
16918c2ecf20Sopenharmony_ci					     &identifier);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (status != 0)
16948c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
16978c2ecf20Sopenharmony_ci		hw->phy.type = ixgbe_phy_sfp_unsupported;
16988c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	hw->phy.id = identifier;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
17048c2ecf20Sopenharmony_ci					     &comp_codes_10g);
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	if (status != 0)
17078c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_1GBE_COMP,
17108c2ecf20Sopenharmony_ci					     &comp_codes_1g);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	if (status != 0)
17138c2ecf20Sopenharmony_ci		goto err_read_i2c_eeprom;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) {
17168c2ecf20Sopenharmony_ci		hw->phy.type = ixgbe_phy_qsfp_passive_unknown;
17178c2ecf20Sopenharmony_ci		if (hw->bus.lan_id == 0)
17188c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0;
17198c2ecf20Sopenharmony_ci		else
17208c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1;
17218c2ecf20Sopenharmony_ci	} else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
17228c2ecf20Sopenharmony_ci				     IXGBE_SFF_10GBASELR_CAPABLE)) {
17238c2ecf20Sopenharmony_ci		if (hw->bus.lan_id == 0)
17248c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0;
17258c2ecf20Sopenharmony_ci		else
17268c2ecf20Sopenharmony_ci			hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1;
17278c2ecf20Sopenharmony_ci	} else {
17288c2ecf20Sopenharmony_ci		if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE)
17298c2ecf20Sopenharmony_ci			active_cable = true;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci		if (!active_cable) {
17328c2ecf20Sopenharmony_ci			/* check for active DA cables that pre-date
17338c2ecf20Sopenharmony_ci			 * SFF-8436 v3.6
17348c2ecf20Sopenharmony_ci			 */
17358c2ecf20Sopenharmony_ci			hw->phy.ops.read_i2c_eeprom(hw,
17368c2ecf20Sopenharmony_ci					IXGBE_SFF_QSFP_CONNECTOR,
17378c2ecf20Sopenharmony_ci					&connector);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci			hw->phy.ops.read_i2c_eeprom(hw,
17408c2ecf20Sopenharmony_ci					IXGBE_SFF_QSFP_CABLE_LENGTH,
17418c2ecf20Sopenharmony_ci					&cable_length);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci			hw->phy.ops.read_i2c_eeprom(hw,
17448c2ecf20Sopenharmony_ci					IXGBE_SFF_QSFP_DEVICE_TECH,
17458c2ecf20Sopenharmony_ci					&device_tech);
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci			if ((connector ==
17488c2ecf20Sopenharmony_ci				     IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE) &&
17498c2ecf20Sopenharmony_ci			    (cable_length > 0) &&
17508c2ecf20Sopenharmony_ci			    ((device_tech >> 4) ==
17518c2ecf20Sopenharmony_ci				     IXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL))
17528c2ecf20Sopenharmony_ci				active_cable = true;
17538c2ecf20Sopenharmony_ci		}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci		if (active_cable) {
17568c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_qsfp_active_unknown;
17578c2ecf20Sopenharmony_ci			if (hw->bus.lan_id == 0)
17588c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
17598c2ecf20Sopenharmony_ci						ixgbe_sfp_type_da_act_lmt_core0;
17608c2ecf20Sopenharmony_ci			else
17618c2ecf20Sopenharmony_ci				hw->phy.sfp_type =
17628c2ecf20Sopenharmony_ci						ixgbe_sfp_type_da_act_lmt_core1;
17638c2ecf20Sopenharmony_ci		} else {
17648c2ecf20Sopenharmony_ci			/* unsupported module type */
17658c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_sfp_unsupported;
17668c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
17678c2ecf20Sopenharmony_ci		}
17688c2ecf20Sopenharmony_ci	}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	if (hw->phy.sfp_type != stored_sfp_type)
17718c2ecf20Sopenharmony_ci		hw->phy.sfp_setup_needed = true;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	/* Determine if the QSFP+ PHY is dual speed or not. */
17748c2ecf20Sopenharmony_ci	hw->phy.multispeed_fiber = false;
17758c2ecf20Sopenharmony_ci	if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
17768c2ecf20Sopenharmony_ci	     (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
17778c2ecf20Sopenharmony_ci	    ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
17788c2ecf20Sopenharmony_ci	     (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
17798c2ecf20Sopenharmony_ci		hw->phy.multispeed_fiber = true;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	/* Determine PHY vendor for optical modules */
17828c2ecf20Sopenharmony_ci	if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
17838c2ecf20Sopenharmony_ci			      IXGBE_SFF_10GBASELR_CAPABLE)) {
17848c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_i2c_eeprom(hw,
17858c2ecf20Sopenharmony_ci					IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0,
17868c2ecf20Sopenharmony_ci					&oui_bytes[0]);
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci		if (status != 0)
17898c2ecf20Sopenharmony_ci			goto err_read_i2c_eeprom;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_i2c_eeprom(hw,
17928c2ecf20Sopenharmony_ci					IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1,
17938c2ecf20Sopenharmony_ci					&oui_bytes[1]);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		if (status != 0)
17968c2ecf20Sopenharmony_ci			goto err_read_i2c_eeprom;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci		status = hw->phy.ops.read_i2c_eeprom(hw,
17998c2ecf20Sopenharmony_ci					IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2,
18008c2ecf20Sopenharmony_ci					&oui_bytes[2]);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		if (status != 0)
18038c2ecf20Sopenharmony_ci			goto err_read_i2c_eeprom;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci		vendor_oui =
18068c2ecf20Sopenharmony_ci			((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
18078c2ecf20Sopenharmony_ci			 (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
18088c2ecf20Sopenharmony_ci			 (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci		if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL)
18118c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_qsfp_intel;
18128c2ecf20Sopenharmony_ci		else
18138c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_qsfp_unknown;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci		hw->mac.ops.get_device_caps(hw, &enforce_sfp);
18168c2ecf20Sopenharmony_ci		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
18178c2ecf20Sopenharmony_ci			/* Make sure we're a supported PHY type */
18188c2ecf20Sopenharmony_ci			if (hw->phy.type == ixgbe_phy_qsfp_intel)
18198c2ecf20Sopenharmony_ci				return 0;
18208c2ecf20Sopenharmony_ci			if (hw->allow_unsupported_sfp) {
18218c2ecf20Sopenharmony_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");
18228c2ecf20Sopenharmony_ci				return 0;
18238c2ecf20Sopenharmony_ci			}
18248c2ecf20Sopenharmony_ci			hw_dbg(hw, "QSFP module not supported\n");
18258c2ecf20Sopenharmony_ci			hw->phy.type = ixgbe_phy_sfp_unsupported;
18268c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
18278c2ecf20Sopenharmony_ci		}
18288c2ecf20Sopenharmony_ci		return 0;
18298c2ecf20Sopenharmony_ci	}
18308c2ecf20Sopenharmony_ci	return 0;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_cierr_read_i2c_eeprom:
18338c2ecf20Sopenharmony_ci	hw->phy.sfp_type = ixgbe_sfp_type_not_present;
18348c2ecf20Sopenharmony_ci	hw->phy.id = 0;
18358c2ecf20Sopenharmony_ci	hw->phy.type = ixgbe_phy_unknown;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	return -ENOENT;
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci/**
18418c2ecf20Sopenharmony_ci *  ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
18428c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
18438c2ecf20Sopenharmony_ci *  @list_offset: offset to the SFP ID list
18448c2ecf20Sopenharmony_ci *  @data_offset: offset to the SFP data block
18458c2ecf20Sopenharmony_ci *
18468c2ecf20Sopenharmony_ci *  Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if
18478c2ecf20Sopenharmony_ci *  so it returns the offsets to the phy init sequence block.
18488c2ecf20Sopenharmony_ci **/
18498c2ecf20Sopenharmony_cis32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
18508c2ecf20Sopenharmony_ci					u16 *list_offset,
18518c2ecf20Sopenharmony_ci					u16 *data_offset)
18528c2ecf20Sopenharmony_ci{
18538c2ecf20Sopenharmony_ci	u16 sfp_id;
18548c2ecf20Sopenharmony_ci	u16 sfp_type = hw->phy.sfp_type;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
18578c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
18608c2ecf20Sopenharmony_ci		return -ENOENT;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
18638c2ecf20Sopenharmony_ci	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
18648c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	/*
18678c2ecf20Sopenharmony_ci	 * Limiting active cables and 1G Phys must be initialized as
18688c2ecf20Sopenharmony_ci	 * SR modules
18698c2ecf20Sopenharmony_ci	 */
18708c2ecf20Sopenharmony_ci	if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
18718c2ecf20Sopenharmony_ci	    sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
18728c2ecf20Sopenharmony_ci	    sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
18738c2ecf20Sopenharmony_ci	    sfp_type == ixgbe_sfp_type_1g_sx_core0)
18748c2ecf20Sopenharmony_ci		sfp_type = ixgbe_sfp_type_srlr_core0;
18758c2ecf20Sopenharmony_ci	else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
18768c2ecf20Sopenharmony_ci		 sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
18778c2ecf20Sopenharmony_ci		 sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
18788c2ecf20Sopenharmony_ci		 sfp_type == ixgbe_sfp_type_1g_sx_core1)
18798c2ecf20Sopenharmony_ci		sfp_type = ixgbe_sfp_type_srlr_core1;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	/* Read offset to PHY init contents */
18828c2ecf20Sopenharmony_ci	if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) {
18838c2ecf20Sopenharmony_ci		hw_err(hw, "eeprom read at %d failed\n",
18848c2ecf20Sopenharmony_ci		       IXGBE_PHY_INIT_OFFSET_NL);
18858c2ecf20Sopenharmony_ci		return -EIO;
18868c2ecf20Sopenharmony_ci	}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	if ((!*list_offset) || (*list_offset == 0xFFFF))
18898c2ecf20Sopenharmony_ci		return -EIO;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	/* Shift offset to first ID word */
18928c2ecf20Sopenharmony_ci	(*list_offset)++;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	/*
18958c2ecf20Sopenharmony_ci	 * Find the matching SFP ID in the EEPROM
18968c2ecf20Sopenharmony_ci	 * and program the init sequence
18978c2ecf20Sopenharmony_ci	 */
18988c2ecf20Sopenharmony_ci	if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
18998c2ecf20Sopenharmony_ci		goto err_phy;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	while (sfp_id != IXGBE_PHY_INIT_END_NL) {
19028c2ecf20Sopenharmony_ci		if (sfp_id == sfp_type) {
19038c2ecf20Sopenharmony_ci			(*list_offset)++;
19048c2ecf20Sopenharmony_ci			if (hw->eeprom.ops.read(hw, *list_offset, data_offset))
19058c2ecf20Sopenharmony_ci				goto err_phy;
19068c2ecf20Sopenharmony_ci			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
19078c2ecf20Sopenharmony_ci				hw_dbg(hw, "SFP+ module not supported\n");
19088c2ecf20Sopenharmony_ci				return -EOPNOTSUPP;
19098c2ecf20Sopenharmony_ci			} else {
19108c2ecf20Sopenharmony_ci				break;
19118c2ecf20Sopenharmony_ci			}
19128c2ecf20Sopenharmony_ci		} else {
19138c2ecf20Sopenharmony_ci			(*list_offset) += 2;
19148c2ecf20Sopenharmony_ci			if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
19158c2ecf20Sopenharmony_ci				goto err_phy;
19168c2ecf20Sopenharmony_ci		}
19178c2ecf20Sopenharmony_ci	}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	if (sfp_id == IXGBE_PHY_INIT_END_NL) {
19208c2ecf20Sopenharmony_ci		hw_dbg(hw, "No matching SFP+ module found\n");
19218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	return 0;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cierr_phy:
19278c2ecf20Sopenharmony_ci	hw_err(hw, "eeprom read at offset %d failed\n", *list_offset);
19288c2ecf20Sopenharmony_ci	return -EIO;
19298c2ecf20Sopenharmony_ci}
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci/**
19328c2ecf20Sopenharmony_ci *  ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface
19338c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19348c2ecf20Sopenharmony_ci *  @byte_offset: EEPROM byte offset to read
19358c2ecf20Sopenharmony_ci *  @eeprom_data: value read
19368c2ecf20Sopenharmony_ci *
19378c2ecf20Sopenharmony_ci *  Performs byte read operation to SFP module's EEPROM over I2C interface.
19388c2ecf20Sopenharmony_ci **/
19398c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
19408c2ecf20Sopenharmony_ci				  u8 *eeprom_data)
19418c2ecf20Sopenharmony_ci{
19428c2ecf20Sopenharmony_ci	return hw->phy.ops.read_i2c_byte(hw, byte_offset,
19438c2ecf20Sopenharmony_ci					 IXGBE_I2C_EEPROM_DEV_ADDR,
19448c2ecf20Sopenharmony_ci					 eeprom_data);
19458c2ecf20Sopenharmony_ci}
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci/**
19488c2ecf20Sopenharmony_ci *  ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface
19498c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19508c2ecf20Sopenharmony_ci *  @byte_offset: byte offset at address 0xA2
19518c2ecf20Sopenharmony_ci *  @sff8472_data: value read
19528c2ecf20Sopenharmony_ci *
19538c2ecf20Sopenharmony_ci *  Performs byte read operation to SFP module's SFF-8472 data over I2C
19548c2ecf20Sopenharmony_ci **/
19558c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
19568c2ecf20Sopenharmony_ci				   u8 *sff8472_data)
19578c2ecf20Sopenharmony_ci{
19588c2ecf20Sopenharmony_ci	return hw->phy.ops.read_i2c_byte(hw, byte_offset,
19598c2ecf20Sopenharmony_ci					 IXGBE_I2C_EEPROM_DEV_ADDR2,
19608c2ecf20Sopenharmony_ci					 sff8472_data);
19618c2ecf20Sopenharmony_ci}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci/**
19648c2ecf20Sopenharmony_ci *  ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
19658c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19668c2ecf20Sopenharmony_ci *  @byte_offset: EEPROM byte offset to write
19678c2ecf20Sopenharmony_ci *  @eeprom_data: value to write
19688c2ecf20Sopenharmony_ci *
19698c2ecf20Sopenharmony_ci *  Performs byte write operation to SFP module's EEPROM over I2C interface.
19708c2ecf20Sopenharmony_ci **/
19718c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
19728c2ecf20Sopenharmony_ci				   u8 eeprom_data)
19738c2ecf20Sopenharmony_ci{
19748c2ecf20Sopenharmony_ci	return hw->phy.ops.write_i2c_byte(hw, byte_offset,
19758c2ecf20Sopenharmony_ci					  IXGBE_I2C_EEPROM_DEV_ADDR,
19768c2ecf20Sopenharmony_ci					  eeprom_data);
19778c2ecf20Sopenharmony_ci}
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci/**
19808c2ecf20Sopenharmony_ci * ixgbe_is_sfp_probe - Returns true if SFP is being detected
19818c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure
19828c2ecf20Sopenharmony_ci * @offset: eeprom offset to be read
19838c2ecf20Sopenharmony_ci * @addr: I2C address to be read
19848c2ecf20Sopenharmony_ci */
19858c2ecf20Sopenharmony_cistatic bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr)
19868c2ecf20Sopenharmony_ci{
19878c2ecf20Sopenharmony_ci	if (addr == IXGBE_I2C_EEPROM_DEV_ADDR &&
19888c2ecf20Sopenharmony_ci	    offset == IXGBE_SFF_IDENTIFIER &&
19898c2ecf20Sopenharmony_ci	    hw->phy.sfp_type == ixgbe_sfp_type_not_present)
19908c2ecf20Sopenharmony_ci		return true;
19918c2ecf20Sopenharmony_ci	return false;
19928c2ecf20Sopenharmony_ci}
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci/**
19958c2ecf20Sopenharmony_ci *  ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C
19968c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19978c2ecf20Sopenharmony_ci *  @byte_offset: byte offset to read
19988c2ecf20Sopenharmony_ci *  @dev_addr: device address
19998c2ecf20Sopenharmony_ci *  @data: value read
20008c2ecf20Sopenharmony_ci *  @lock: true if to take and release semaphore
20018c2ecf20Sopenharmony_ci *
20028c2ecf20Sopenharmony_ci *  Performs byte read operation to SFP module's EEPROM over I2C interface at
20038c2ecf20Sopenharmony_ci *  a specified device address.
20048c2ecf20Sopenharmony_ci */
20058c2ecf20Sopenharmony_cistatic s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
20068c2ecf20Sopenharmony_ci					   u8 dev_addr, u8 *data, bool lock)
20078c2ecf20Sopenharmony_ci{
20088c2ecf20Sopenharmony_ci	s32 status;
20098c2ecf20Sopenharmony_ci	u32 max_retry = 10;
20108c2ecf20Sopenharmony_ci	u32 retry = 0;
20118c2ecf20Sopenharmony_ci	u32 swfw_mask = hw->phy.phy_semaphore_mask;
20128c2ecf20Sopenharmony_ci	bool nack = true;
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	if (hw->mac.type >= ixgbe_mac_X550)
20158c2ecf20Sopenharmony_ci		max_retry = 3;
20168c2ecf20Sopenharmony_ci	if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr))
20178c2ecf20Sopenharmony_ci		max_retry = IXGBE_SFP_DETECT_RETRIES;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	*data = 0;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	do {
20228c2ecf20Sopenharmony_ci		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
20238c2ecf20Sopenharmony_ci			return -EBUSY;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci		ixgbe_i2c_start(hw);
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci		/* Device Address and write indication */
20288c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
20298c2ecf20Sopenharmony_ci		if (status != 0)
20308c2ecf20Sopenharmony_ci			goto fail;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci		status = ixgbe_get_i2c_ack(hw);
20338c2ecf20Sopenharmony_ci		if (status != 0)
20348c2ecf20Sopenharmony_ci			goto fail;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
20378c2ecf20Sopenharmony_ci		if (status != 0)
20388c2ecf20Sopenharmony_ci			goto fail;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci		status = ixgbe_get_i2c_ack(hw);
20418c2ecf20Sopenharmony_ci		if (status != 0)
20428c2ecf20Sopenharmony_ci			goto fail;
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci		ixgbe_i2c_start(hw);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci		/* Device Address and read indication */
20478c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1));
20488c2ecf20Sopenharmony_ci		if (status != 0)
20498c2ecf20Sopenharmony_ci			goto fail;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci		status = ixgbe_get_i2c_ack(hw);
20528c2ecf20Sopenharmony_ci		if (status != 0)
20538c2ecf20Sopenharmony_ci			goto fail;
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		status = ixgbe_clock_in_i2c_byte(hw, data);
20568c2ecf20Sopenharmony_ci		if (status != 0)
20578c2ecf20Sopenharmony_ci			goto fail;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_bit(hw, nack);
20608c2ecf20Sopenharmony_ci		if (status != 0)
20618c2ecf20Sopenharmony_ci			goto fail;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci		ixgbe_i2c_stop(hw);
20648c2ecf20Sopenharmony_ci		if (lock)
20658c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
20668c2ecf20Sopenharmony_ci		return 0;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_cifail:
20698c2ecf20Sopenharmony_ci		ixgbe_i2c_bus_clear(hw);
20708c2ecf20Sopenharmony_ci		if (lock) {
20718c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
20728c2ecf20Sopenharmony_ci			msleep(100);
20738c2ecf20Sopenharmony_ci		}
20748c2ecf20Sopenharmony_ci		retry++;
20758c2ecf20Sopenharmony_ci		if (retry < max_retry)
20768c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte read error - Retrying.\n");
20778c2ecf20Sopenharmony_ci		else
20788c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte read error.\n");
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	} while (retry < max_retry);
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	return status;
20838c2ecf20Sopenharmony_ci}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci/**
20868c2ecf20Sopenharmony_ci *  ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
20878c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
20888c2ecf20Sopenharmony_ci *  @byte_offset: byte offset to read
20898c2ecf20Sopenharmony_ci *  @dev_addr: device address
20908c2ecf20Sopenharmony_ci *  @data: value read
20918c2ecf20Sopenharmony_ci *
20928c2ecf20Sopenharmony_ci *  Performs byte read operation to SFP module's EEPROM over I2C interface at
20938c2ecf20Sopenharmony_ci *  a specified device address.
20948c2ecf20Sopenharmony_ci */
20958c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
20968c2ecf20Sopenharmony_ci				u8 dev_addr, u8 *data)
20978c2ecf20Sopenharmony_ci{
20988c2ecf20Sopenharmony_ci	return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
20998c2ecf20Sopenharmony_ci					       data, true);
21008c2ecf20Sopenharmony_ci}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci/**
21038c2ecf20Sopenharmony_ci *  ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C
21048c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
21058c2ecf20Sopenharmony_ci *  @byte_offset: byte offset to read
21068c2ecf20Sopenharmony_ci *  @dev_addr: device address
21078c2ecf20Sopenharmony_ci *  @data: value read
21088c2ecf20Sopenharmony_ci *
21098c2ecf20Sopenharmony_ci *  Performs byte read operation to SFP module's EEPROM over I2C interface at
21108c2ecf20Sopenharmony_ci *  a specified device address.
21118c2ecf20Sopenharmony_ci */
21128c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
21138c2ecf20Sopenharmony_ci					 u8 dev_addr, u8 *data)
21148c2ecf20Sopenharmony_ci{
21158c2ecf20Sopenharmony_ci	return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
21168c2ecf20Sopenharmony_ci					       data, false);
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci/**
21208c2ecf20Sopenharmony_ci *  ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C
21218c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
21228c2ecf20Sopenharmony_ci *  @byte_offset: byte offset to write
21238c2ecf20Sopenharmony_ci *  @dev_addr: device address
21248c2ecf20Sopenharmony_ci *  @data: value to write
21258c2ecf20Sopenharmony_ci *  @lock: true if to take and release semaphore
21268c2ecf20Sopenharmony_ci *
21278c2ecf20Sopenharmony_ci *  Performs byte write operation to SFP module's EEPROM over I2C interface at
21288c2ecf20Sopenharmony_ci *  a specified device address.
21298c2ecf20Sopenharmony_ci */
21308c2ecf20Sopenharmony_cistatic s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
21318c2ecf20Sopenharmony_ci					    u8 dev_addr, u8 data, bool lock)
21328c2ecf20Sopenharmony_ci{
21338c2ecf20Sopenharmony_ci	s32 status;
21348c2ecf20Sopenharmony_ci	u32 max_retry = 1;
21358c2ecf20Sopenharmony_ci	u32 retry = 0;
21368c2ecf20Sopenharmony_ci	u32 swfw_mask = hw->phy.phy_semaphore_mask;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
21398c2ecf20Sopenharmony_ci		return -EBUSY;
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	do {
21428c2ecf20Sopenharmony_ci		ixgbe_i2c_start(hw);
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
21458c2ecf20Sopenharmony_ci		if (status != 0)
21468c2ecf20Sopenharmony_ci			goto fail;
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci		status = ixgbe_get_i2c_ack(hw);
21498c2ecf20Sopenharmony_ci		if (status != 0)
21508c2ecf20Sopenharmony_ci			goto fail;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
21538c2ecf20Sopenharmony_ci		if (status != 0)
21548c2ecf20Sopenharmony_ci			goto fail;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci		status = ixgbe_get_i2c_ack(hw);
21578c2ecf20Sopenharmony_ci		if (status != 0)
21588c2ecf20Sopenharmony_ci			goto fail;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_byte(hw, data);
21618c2ecf20Sopenharmony_ci		if (status != 0)
21628c2ecf20Sopenharmony_ci			goto fail;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci		status = ixgbe_get_i2c_ack(hw);
21658c2ecf20Sopenharmony_ci		if (status != 0)
21668c2ecf20Sopenharmony_ci			goto fail;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci		ixgbe_i2c_stop(hw);
21698c2ecf20Sopenharmony_ci		if (lock)
21708c2ecf20Sopenharmony_ci			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
21718c2ecf20Sopenharmony_ci		return 0;
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_cifail:
21748c2ecf20Sopenharmony_ci		ixgbe_i2c_bus_clear(hw);
21758c2ecf20Sopenharmony_ci		retry++;
21768c2ecf20Sopenharmony_ci		if (retry < max_retry)
21778c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte write error - Retrying.\n");
21788c2ecf20Sopenharmony_ci		else
21798c2ecf20Sopenharmony_ci			hw_dbg(hw, "I2C byte write error.\n");
21808c2ecf20Sopenharmony_ci	} while (retry < max_retry);
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	if (lock)
21838c2ecf20Sopenharmony_ci		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	return status;
21868c2ecf20Sopenharmony_ci}
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci/**
21898c2ecf20Sopenharmony_ci *  ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
21908c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
21918c2ecf20Sopenharmony_ci *  @byte_offset: byte offset to write
21928c2ecf20Sopenharmony_ci *  @dev_addr: device address
21938c2ecf20Sopenharmony_ci *  @data: value to write
21948c2ecf20Sopenharmony_ci *
21958c2ecf20Sopenharmony_ci *  Performs byte write operation to SFP module's EEPROM over I2C interface at
21968c2ecf20Sopenharmony_ci *  a specified device address.
21978c2ecf20Sopenharmony_ci */
21988c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
21998c2ecf20Sopenharmony_ci				 u8 dev_addr, u8 data)
22008c2ecf20Sopenharmony_ci{
22018c2ecf20Sopenharmony_ci	return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
22028c2ecf20Sopenharmony_ci						data, true);
22038c2ecf20Sopenharmony_ci}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci/**
22068c2ecf20Sopenharmony_ci *  ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C
22078c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
22088c2ecf20Sopenharmony_ci *  @byte_offset: byte offset to write
22098c2ecf20Sopenharmony_ci *  @dev_addr: device address
22108c2ecf20Sopenharmony_ci *  @data: value to write
22118c2ecf20Sopenharmony_ci *
22128c2ecf20Sopenharmony_ci *  Performs byte write operation to SFP module's EEPROM over I2C interface at
22138c2ecf20Sopenharmony_ci *  a specified device address.
22148c2ecf20Sopenharmony_ci */
22158c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
22168c2ecf20Sopenharmony_ci					  u8 dev_addr, u8 data)
22178c2ecf20Sopenharmony_ci{
22188c2ecf20Sopenharmony_ci	return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
22198c2ecf20Sopenharmony_ci						data, false);
22208c2ecf20Sopenharmony_ci}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci/**
22238c2ecf20Sopenharmony_ci *  ixgbe_i2c_start - Sets I2C start condition
22248c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
22258c2ecf20Sopenharmony_ci *
22268c2ecf20Sopenharmony_ci *  Sets I2C start condition (High -> Low on SDA while SCL is High)
22278c2ecf20Sopenharmony_ci *  Set bit-bang mode on X550 hardware.
22288c2ecf20Sopenharmony_ci **/
22298c2ecf20Sopenharmony_cistatic void ixgbe_i2c_start(struct ixgbe_hw *hw)
22308c2ecf20Sopenharmony_ci{
22318c2ecf20Sopenharmony_ci	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	i2cctl |= IXGBE_I2C_BB_EN(hw);
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	/* Start condition must begin with data and clock high */
22368c2ecf20Sopenharmony_ci	ixgbe_set_i2c_data(hw, &i2cctl, 1);
22378c2ecf20Sopenharmony_ci	ixgbe_raise_i2c_clk(hw, &i2cctl);
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	/* Setup time for start condition (4.7us) */
22408c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_SU_STA);
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	ixgbe_set_i2c_data(hw, &i2cctl, 0);
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	/* Hold time for start condition (4us) */
22458c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_HD_STA);
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	ixgbe_lower_i2c_clk(hw, &i2cctl);
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	/* Minimum low period of clock is 4.7 us */
22508c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_LOW);
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci}
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci/**
22558c2ecf20Sopenharmony_ci *  ixgbe_i2c_stop - Sets I2C stop condition
22568c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
22578c2ecf20Sopenharmony_ci *
22588c2ecf20Sopenharmony_ci *  Sets I2C stop condition (Low -> High on SDA while SCL is High)
22598c2ecf20Sopenharmony_ci *  Disables bit-bang mode and negates data output enable on X550
22608c2ecf20Sopenharmony_ci *  hardware.
22618c2ecf20Sopenharmony_ci **/
22628c2ecf20Sopenharmony_cistatic void ixgbe_i2c_stop(struct ixgbe_hw *hw)
22638c2ecf20Sopenharmony_ci{
22648c2ecf20Sopenharmony_ci	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
22658c2ecf20Sopenharmony_ci	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
22668c2ecf20Sopenharmony_ci	u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw);
22678c2ecf20Sopenharmony_ci	u32 bb_en_bit = IXGBE_I2C_BB_EN(hw);
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	/* Stop condition must begin with data low and clock high */
22708c2ecf20Sopenharmony_ci	ixgbe_set_i2c_data(hw, &i2cctl, 0);
22718c2ecf20Sopenharmony_ci	ixgbe_raise_i2c_clk(hw, &i2cctl);
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	/* Setup time for stop condition (4us) */
22748c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_SU_STO);
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	ixgbe_set_i2c_data(hw, &i2cctl, 1);
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	/* bus free time between stop and start (4.7us)*/
22798c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_BUF);
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	if (bb_en_bit || data_oe_bit || clk_oe_bit) {
22828c2ecf20Sopenharmony_ci		i2cctl &= ~bb_en_bit;
22838c2ecf20Sopenharmony_ci		i2cctl |= data_oe_bit | clk_oe_bit;
22848c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
22858c2ecf20Sopenharmony_ci		IXGBE_WRITE_FLUSH(hw);
22868c2ecf20Sopenharmony_ci	}
22878c2ecf20Sopenharmony_ci}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci/**
22908c2ecf20Sopenharmony_ci *  ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C
22918c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
22928c2ecf20Sopenharmony_ci *  @data: data byte to clock in
22938c2ecf20Sopenharmony_ci *
22948c2ecf20Sopenharmony_ci *  Clocks in one byte data via I2C data/clock
22958c2ecf20Sopenharmony_ci **/
22968c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
22978c2ecf20Sopenharmony_ci{
22988c2ecf20Sopenharmony_ci	s32 i;
22998c2ecf20Sopenharmony_ci	bool bit = false;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	*data = 0;
23028c2ecf20Sopenharmony_ci	for (i = 7; i >= 0; i--) {
23038c2ecf20Sopenharmony_ci		ixgbe_clock_in_i2c_bit(hw, &bit);
23048c2ecf20Sopenharmony_ci		*data |= bit << i;
23058c2ecf20Sopenharmony_ci	}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	return 0;
23088c2ecf20Sopenharmony_ci}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci/**
23118c2ecf20Sopenharmony_ci *  ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C
23128c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
23138c2ecf20Sopenharmony_ci *  @data: data byte clocked out
23148c2ecf20Sopenharmony_ci *
23158c2ecf20Sopenharmony_ci *  Clocks out one byte data via I2C data/clock
23168c2ecf20Sopenharmony_ci **/
23178c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
23188c2ecf20Sopenharmony_ci{
23198c2ecf20Sopenharmony_ci	s32 status;
23208c2ecf20Sopenharmony_ci	s32 i;
23218c2ecf20Sopenharmony_ci	u32 i2cctl;
23228c2ecf20Sopenharmony_ci	bool bit = false;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	for (i = 7; i >= 0; i--) {
23258c2ecf20Sopenharmony_ci		bit = (data >> i) & 0x1;
23268c2ecf20Sopenharmony_ci		status = ixgbe_clock_out_i2c_bit(hw, bit);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci		if (status != 0)
23298c2ecf20Sopenharmony_ci			break;
23308c2ecf20Sopenharmony_ci	}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	/* Release SDA line (set high) */
23338c2ecf20Sopenharmony_ci	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
23348c2ecf20Sopenharmony_ci	i2cctl |= IXGBE_I2C_DATA_OUT(hw);
23358c2ecf20Sopenharmony_ci	i2cctl |= IXGBE_I2C_DATA_OE_N_EN(hw);
23368c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
23378c2ecf20Sopenharmony_ci	IXGBE_WRITE_FLUSH(hw);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	return status;
23408c2ecf20Sopenharmony_ci}
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci/**
23438c2ecf20Sopenharmony_ci *  ixgbe_get_i2c_ack - Polls for I2C ACK
23448c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
23458c2ecf20Sopenharmony_ci *
23468c2ecf20Sopenharmony_ci *  Clocks in/out one bit via I2C data/clock
23478c2ecf20Sopenharmony_ci **/
23488c2ecf20Sopenharmony_cistatic s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
23498c2ecf20Sopenharmony_ci{
23508c2ecf20Sopenharmony_ci	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
23518c2ecf20Sopenharmony_ci	s32 status = 0;
23528c2ecf20Sopenharmony_ci	u32 i = 0;
23538c2ecf20Sopenharmony_ci	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
23548c2ecf20Sopenharmony_ci	u32 timeout = 10;
23558c2ecf20Sopenharmony_ci	bool ack = true;
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	if (data_oe_bit) {
23588c2ecf20Sopenharmony_ci		i2cctl |= IXGBE_I2C_DATA_OUT(hw);
23598c2ecf20Sopenharmony_ci		i2cctl |= data_oe_bit;
23608c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
23618c2ecf20Sopenharmony_ci		IXGBE_WRITE_FLUSH(hw);
23628c2ecf20Sopenharmony_ci	}
23638c2ecf20Sopenharmony_ci	ixgbe_raise_i2c_clk(hw, &i2cctl);
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	/* Minimum high period of clock is 4us */
23668c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_HIGH);
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	/* Poll for ACK.  Note that ACK in I2C spec is
23698c2ecf20Sopenharmony_ci	 * transition from 1 to 0 */
23708c2ecf20Sopenharmony_ci	for (i = 0; i < timeout; i++) {
23718c2ecf20Sopenharmony_ci		i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
23728c2ecf20Sopenharmony_ci		ack = ixgbe_get_i2c_data(hw, &i2cctl);
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci		udelay(1);
23758c2ecf20Sopenharmony_ci		if (ack == 0)
23768c2ecf20Sopenharmony_ci			break;
23778c2ecf20Sopenharmony_ci	}
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	if (ack == 1) {
23808c2ecf20Sopenharmony_ci		hw_dbg(hw, "I2C ack was not received.\n");
23818c2ecf20Sopenharmony_ci		status = -EIO;
23828c2ecf20Sopenharmony_ci	}
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	ixgbe_lower_i2c_clk(hw, &i2cctl);
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	/* Minimum low period of clock is 4.7 us */
23878c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_LOW);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	return status;
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci/**
23938c2ecf20Sopenharmony_ci *  ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
23948c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
23958c2ecf20Sopenharmony_ci *  @data: read data value
23968c2ecf20Sopenharmony_ci *
23978c2ecf20Sopenharmony_ci *  Clocks in one bit via I2C data/clock
23988c2ecf20Sopenharmony_ci **/
23998c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
24008c2ecf20Sopenharmony_ci{
24018c2ecf20Sopenharmony_ci	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
24028c2ecf20Sopenharmony_ci	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	if (data_oe_bit) {
24058c2ecf20Sopenharmony_ci		i2cctl |= IXGBE_I2C_DATA_OUT(hw);
24068c2ecf20Sopenharmony_ci		i2cctl |= data_oe_bit;
24078c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
24088c2ecf20Sopenharmony_ci		IXGBE_WRITE_FLUSH(hw);
24098c2ecf20Sopenharmony_ci	}
24108c2ecf20Sopenharmony_ci	ixgbe_raise_i2c_clk(hw, &i2cctl);
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	/* Minimum high period of clock is 4us */
24138c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_HIGH);
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
24168c2ecf20Sopenharmony_ci	*data = ixgbe_get_i2c_data(hw, &i2cctl);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	ixgbe_lower_i2c_clk(hw, &i2cctl);
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	/* Minimum low period of clock is 4.7 us */
24218c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_LOW);
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	return 0;
24248c2ecf20Sopenharmony_ci}
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci/**
24278c2ecf20Sopenharmony_ci *  ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
24288c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
24298c2ecf20Sopenharmony_ci *  @data: data value to write
24308c2ecf20Sopenharmony_ci *
24318c2ecf20Sopenharmony_ci *  Clocks out one bit via I2C data/clock
24328c2ecf20Sopenharmony_ci **/
24338c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
24348c2ecf20Sopenharmony_ci{
24358c2ecf20Sopenharmony_ci	s32 status;
24368c2ecf20Sopenharmony_ci	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	status = ixgbe_set_i2c_data(hw, &i2cctl, data);
24398c2ecf20Sopenharmony_ci	if (status == 0) {
24408c2ecf20Sopenharmony_ci		ixgbe_raise_i2c_clk(hw, &i2cctl);
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci		/* Minimum high period of clock is 4us */
24438c2ecf20Sopenharmony_ci		udelay(IXGBE_I2C_T_HIGH);
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci		ixgbe_lower_i2c_clk(hw, &i2cctl);
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci		/* Minimum low period of clock is 4.7 us.
24488c2ecf20Sopenharmony_ci		 * This also takes care of the data hold time.
24498c2ecf20Sopenharmony_ci		 */
24508c2ecf20Sopenharmony_ci		udelay(IXGBE_I2C_T_LOW);
24518c2ecf20Sopenharmony_ci	} else {
24528c2ecf20Sopenharmony_ci		hw_dbg(hw, "I2C data was not set to %X\n", data);
24538c2ecf20Sopenharmony_ci		return -EIO;
24548c2ecf20Sopenharmony_ci	}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	return 0;
24578c2ecf20Sopenharmony_ci}
24588c2ecf20Sopenharmony_ci/**
24598c2ecf20Sopenharmony_ci *  ixgbe_raise_i2c_clk - Raises the I2C SCL clock
24608c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
24618c2ecf20Sopenharmony_ci *  @i2cctl: Current value of I2CCTL register
24628c2ecf20Sopenharmony_ci *
24638c2ecf20Sopenharmony_ci *  Raises the I2C clock line '0'->'1'
24648c2ecf20Sopenharmony_ci *  Negates the I2C clock output enable on X550 hardware.
24658c2ecf20Sopenharmony_ci **/
24668c2ecf20Sopenharmony_cistatic void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
24678c2ecf20Sopenharmony_ci{
24688c2ecf20Sopenharmony_ci	u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw);
24698c2ecf20Sopenharmony_ci	u32 i = 0;
24708c2ecf20Sopenharmony_ci	u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT;
24718c2ecf20Sopenharmony_ci	u32 i2cctl_r = 0;
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci	if (clk_oe_bit) {
24748c2ecf20Sopenharmony_ci		*i2cctl |= clk_oe_bit;
24758c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
24768c2ecf20Sopenharmony_ci	}
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	for (i = 0; i < timeout; i++) {
24798c2ecf20Sopenharmony_ci		*i2cctl |= IXGBE_I2C_CLK_OUT(hw);
24808c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
24818c2ecf20Sopenharmony_ci		IXGBE_WRITE_FLUSH(hw);
24828c2ecf20Sopenharmony_ci		/* SCL rise time (1000ns) */
24838c2ecf20Sopenharmony_ci		udelay(IXGBE_I2C_T_RISE);
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci		i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
24868c2ecf20Sopenharmony_ci		if (i2cctl_r & IXGBE_I2C_CLK_IN(hw))
24878c2ecf20Sopenharmony_ci			break;
24888c2ecf20Sopenharmony_ci	}
24898c2ecf20Sopenharmony_ci}
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci/**
24928c2ecf20Sopenharmony_ci *  ixgbe_lower_i2c_clk - Lowers the I2C SCL clock
24938c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
24948c2ecf20Sopenharmony_ci *  @i2cctl: Current value of I2CCTL register
24958c2ecf20Sopenharmony_ci *
24968c2ecf20Sopenharmony_ci *  Lowers the I2C clock line '1'->'0'
24978c2ecf20Sopenharmony_ci *  Asserts the I2C clock output enable on X550 hardware.
24988c2ecf20Sopenharmony_ci **/
24998c2ecf20Sopenharmony_cistatic void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
25008c2ecf20Sopenharmony_ci{
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	*i2cctl &= ~IXGBE_I2C_CLK_OUT(hw);
25038c2ecf20Sopenharmony_ci	*i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN(hw);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
25068c2ecf20Sopenharmony_ci	IXGBE_WRITE_FLUSH(hw);
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	/* SCL fall time (300ns) */
25098c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_FALL);
25108c2ecf20Sopenharmony_ci}
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci/**
25138c2ecf20Sopenharmony_ci *  ixgbe_set_i2c_data - Sets the I2C data bit
25148c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
25158c2ecf20Sopenharmony_ci *  @i2cctl: Current value of I2CCTL register
25168c2ecf20Sopenharmony_ci *  @data: I2C data value (0 or 1) to set
25178c2ecf20Sopenharmony_ci *
25188c2ecf20Sopenharmony_ci *  Sets the I2C data bit
25198c2ecf20Sopenharmony_ci *  Asserts the I2C data output enable on X550 hardware.
25208c2ecf20Sopenharmony_ci **/
25218c2ecf20Sopenharmony_cistatic s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
25228c2ecf20Sopenharmony_ci{
25238c2ecf20Sopenharmony_ci	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	if (data)
25268c2ecf20Sopenharmony_ci		*i2cctl |= IXGBE_I2C_DATA_OUT(hw);
25278c2ecf20Sopenharmony_ci	else
25288c2ecf20Sopenharmony_ci		*i2cctl &= ~IXGBE_I2C_DATA_OUT(hw);
25298c2ecf20Sopenharmony_ci	*i2cctl &= ~data_oe_bit;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
25328c2ecf20Sopenharmony_ci	IXGBE_WRITE_FLUSH(hw);
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
25358c2ecf20Sopenharmony_ci	udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	if (!data)	/* Can't verify data in this case */
25388c2ecf20Sopenharmony_ci		return 0;
25398c2ecf20Sopenharmony_ci	if (data_oe_bit) {
25408c2ecf20Sopenharmony_ci		*i2cctl |= data_oe_bit;
25418c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
25428c2ecf20Sopenharmony_ci		IXGBE_WRITE_FLUSH(hw);
25438c2ecf20Sopenharmony_ci	}
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	/* Verify data was set correctly */
25468c2ecf20Sopenharmony_ci	*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
25478c2ecf20Sopenharmony_ci	if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
25488c2ecf20Sopenharmony_ci		hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
25498c2ecf20Sopenharmony_ci		return -EIO;
25508c2ecf20Sopenharmony_ci	}
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	return 0;
25538c2ecf20Sopenharmony_ci}
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci/**
25568c2ecf20Sopenharmony_ci *  ixgbe_get_i2c_data - Reads the I2C SDA data bit
25578c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
25588c2ecf20Sopenharmony_ci *  @i2cctl: Current value of I2CCTL register
25598c2ecf20Sopenharmony_ci *
25608c2ecf20Sopenharmony_ci *  Returns the I2C data bit value
25618c2ecf20Sopenharmony_ci *  Negates the I2C data output enable on X550 hardware.
25628c2ecf20Sopenharmony_ci **/
25638c2ecf20Sopenharmony_cistatic bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
25648c2ecf20Sopenharmony_ci{
25658c2ecf20Sopenharmony_ci	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	if (data_oe_bit) {
25688c2ecf20Sopenharmony_ci		*i2cctl |= data_oe_bit;
25698c2ecf20Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
25708c2ecf20Sopenharmony_ci		IXGBE_WRITE_FLUSH(hw);
25718c2ecf20Sopenharmony_ci		udelay(IXGBE_I2C_T_FALL);
25728c2ecf20Sopenharmony_ci	}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	if (*i2cctl & IXGBE_I2C_DATA_IN(hw))
25758c2ecf20Sopenharmony_ci		return true;
25768c2ecf20Sopenharmony_ci	return false;
25778c2ecf20Sopenharmony_ci}
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci/**
25808c2ecf20Sopenharmony_ci *  ixgbe_i2c_bus_clear - Clears the I2C bus
25818c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
25828c2ecf20Sopenharmony_ci *
25838c2ecf20Sopenharmony_ci *  Clears the I2C bus by sending nine clock pulses.
25848c2ecf20Sopenharmony_ci *  Used when data line is stuck low.
25858c2ecf20Sopenharmony_ci **/
25868c2ecf20Sopenharmony_cistatic void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
25878c2ecf20Sopenharmony_ci{
25888c2ecf20Sopenharmony_ci	u32 i2cctl;
25898c2ecf20Sopenharmony_ci	u32 i;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	ixgbe_i2c_start(hw);
25928c2ecf20Sopenharmony_ci	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	ixgbe_set_i2c_data(hw, &i2cctl, 1);
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	for (i = 0; i < 9; i++) {
25978c2ecf20Sopenharmony_ci		ixgbe_raise_i2c_clk(hw, &i2cctl);
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci		/* Min high period of clock is 4us */
26008c2ecf20Sopenharmony_ci		udelay(IXGBE_I2C_T_HIGH);
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci		ixgbe_lower_i2c_clk(hw, &i2cctl);
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci		/* Min low period of clock is 4.7us*/
26058c2ecf20Sopenharmony_ci		udelay(IXGBE_I2C_T_LOW);
26068c2ecf20Sopenharmony_ci	}
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	ixgbe_i2c_start(hw);
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	/* Put the i2c bus back to default state */
26118c2ecf20Sopenharmony_ci	ixgbe_i2c_stop(hw);
26128c2ecf20Sopenharmony_ci}
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci/**
26158c2ecf20Sopenharmony_ci *  ixgbe_tn_check_overtemp - Checks if an overtemp occurred.
26168c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
26178c2ecf20Sopenharmony_ci *
26188c2ecf20Sopenharmony_ci *  Checks if the LASI temp alarm status was triggered due to overtemp
26198c2ecf20Sopenharmony_ci *
26208c2ecf20Sopenharmony_ci *  Return true when an overtemp event detected, otherwise false.
26218c2ecf20Sopenharmony_ci **/
26228c2ecf20Sopenharmony_cibool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
26238c2ecf20Sopenharmony_ci{
26248c2ecf20Sopenharmony_ci	u16 phy_data = 0;
26258c2ecf20Sopenharmony_ci	u32 status;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
26288c2ecf20Sopenharmony_ci		return false;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	/* Check that the LASI temp alarm status was triggered */
26318c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
26328c2ecf20Sopenharmony_ci				      MDIO_MMD_PMAPMD, &phy_data);
26338c2ecf20Sopenharmony_ci	if (status)
26348c2ecf20Sopenharmony_ci		return false;
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	return !!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM);
26378c2ecf20Sopenharmony_ci}
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci/** ixgbe_set_copper_phy_power - Control power for copper phy
26408c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
26418c2ecf20Sopenharmony_ci *  @on: true for on, false for off
26428c2ecf20Sopenharmony_ci **/
26438c2ecf20Sopenharmony_cis32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on)
26448c2ecf20Sopenharmony_ci{
26458c2ecf20Sopenharmony_ci	u32 status;
26468c2ecf20Sopenharmony_ci	u16 reg;
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	/* Bail if we don't have copper phy */
26498c2ecf20Sopenharmony_ci	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
26508c2ecf20Sopenharmony_ci		return 0;
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci	if (!on && ixgbe_mng_present(hw))
26538c2ecf20Sopenharmony_ci		return 0;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	status = hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_VEND1, &reg);
26568c2ecf20Sopenharmony_ci	if (status)
26578c2ecf20Sopenharmony_ci		return status;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	if (on) {
26608c2ecf20Sopenharmony_ci		reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
26618c2ecf20Sopenharmony_ci	} else {
26628c2ecf20Sopenharmony_ci		if (ixgbe_check_reset_blocked(hw))
26638c2ecf20Sopenharmony_ci			return 0;
26648c2ecf20Sopenharmony_ci		reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
26658c2ecf20Sopenharmony_ci	}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	status = hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_VEND1, reg);
26688c2ecf20Sopenharmony_ci	return status;
26698c2ecf20Sopenharmony_ci}
2670