162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2007 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/if_ether.h>
562306a36Sopenharmony_ci#include <linux/delay.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "e1000_mac.h"
862306a36Sopenharmony_ci#include "e1000_phy.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic s32  igb_phy_setup_autoneg(struct e1000_hw *hw);
1162306a36Sopenharmony_cistatic void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
1262306a36Sopenharmony_ci					     u16 *phy_ctrl);
1362306a36Sopenharmony_cistatic s32  igb_wait_autoneg(struct e1000_hw *hw);
1462306a36Sopenharmony_cistatic s32  igb_set_master_slave_mode(struct e1000_hw *hw);
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* Cable length tables */
1762306a36Sopenharmony_cistatic const u16 e1000_m88_cable_length_table[] = {
1862306a36Sopenharmony_ci	0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic const u16 e1000_igp_2_cable_length_table[] = {
2162306a36Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
2262306a36Sopenharmony_ci	0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
2362306a36Sopenharmony_ci	6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
2462306a36Sopenharmony_ci	21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
2562306a36Sopenharmony_ci	40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
2662306a36Sopenharmony_ci	60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
2762306a36Sopenharmony_ci	83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
2862306a36Sopenharmony_ci	104, 109, 114, 118, 121, 124};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/**
3162306a36Sopenharmony_ci *  igb_check_reset_block - Check if PHY reset is blocked
3262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci *  Read the PHY management control register and check whether a PHY reset
3562306a36Sopenharmony_ci *  is blocked.  If a reset is not blocked return 0, otherwise
3662306a36Sopenharmony_ci *  return E1000_BLK_PHY_RESET (12).
3762306a36Sopenharmony_ci **/
3862306a36Sopenharmony_cis32 igb_check_reset_block(struct e1000_hw *hw)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	u32 manc;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	manc = rd32(E1000_MANC);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? E1000_BLK_PHY_RESET : 0;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci *  igb_get_phy_id - Retrieve the PHY ID and revision
4962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci *  Reads the PHY registers and stores the PHY ID and possibly the PHY
5262306a36Sopenharmony_ci *  revision in the hardware structure.
5362306a36Sopenharmony_ci **/
5462306a36Sopenharmony_cis32 igb_get_phy_id(struct e1000_hw *hw)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
5762306a36Sopenharmony_ci	s32 ret_val = 0;
5862306a36Sopenharmony_ci	u16 phy_id;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* ensure PHY page selection to fix misconfigured i210 */
6162306a36Sopenharmony_ci	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
6262306a36Sopenharmony_ci		phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
6562306a36Sopenharmony_ci	if (ret_val)
6662306a36Sopenharmony_ci		goto out;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	phy->id = (u32)(phy_id << 16);
6962306a36Sopenharmony_ci	udelay(20);
7062306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
7162306a36Sopenharmony_ci	if (ret_val)
7262306a36Sopenharmony_ci		goto out;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
7562306a36Sopenharmony_ci	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciout:
7862306a36Sopenharmony_ci	return ret_val;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/**
8262306a36Sopenharmony_ci *  igb_phy_reset_dsp - Reset PHY DSP
8362306a36Sopenharmony_ci *  @hw: pointer to the HW structure
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci *  Reset the digital signal processor.
8662306a36Sopenharmony_ci **/
8762306a36Sopenharmony_cistatic s32 igb_phy_reset_dsp(struct e1000_hw *hw)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	s32 ret_val = 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (!(hw->phy.ops.write_reg))
9262306a36Sopenharmony_ci		goto out;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
9562306a36Sopenharmony_ci	if (ret_val)
9662306a36Sopenharmony_ci		goto out;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciout:
10162306a36Sopenharmony_ci	return ret_val;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/**
10562306a36Sopenharmony_ci *  igb_read_phy_reg_mdic - Read MDI control register
10662306a36Sopenharmony_ci *  @hw: pointer to the HW structure
10762306a36Sopenharmony_ci *  @offset: register offset to be read
10862306a36Sopenharmony_ci *  @data: pointer to the read data
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci *  Reads the MDI control register in the PHY at offset and stores the
11162306a36Sopenharmony_ci *  information read to data.
11262306a36Sopenharmony_ci **/
11362306a36Sopenharmony_cis32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
11662306a36Sopenharmony_ci	u32 i, mdic = 0;
11762306a36Sopenharmony_ci	s32 ret_val = 0;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (offset > MAX_PHY_REG_ADDRESS) {
12062306a36Sopenharmony_ci		hw_dbg("PHY Address %d is out of range\n", offset);
12162306a36Sopenharmony_ci		ret_val = -E1000_ERR_PARAM;
12262306a36Sopenharmony_ci		goto out;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* Set up Op-code, Phy Address, and register offset in the MDI
12662306a36Sopenharmony_ci	 * Control register.  The MAC will take care of interfacing with the
12762306a36Sopenharmony_ci	 * PHY to retrieve the desired data.
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
13062306a36Sopenharmony_ci		(phy->addr << E1000_MDIC_PHY_SHIFT) |
13162306a36Sopenharmony_ci		(E1000_MDIC_OP_READ));
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	wr32(E1000_MDIC, mdic);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* Poll the ready bit to see if the MDI read completed
13662306a36Sopenharmony_ci	 * Increasing the time out as testing showed failures with
13762306a36Sopenharmony_ci	 * the lower time out
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
14062306a36Sopenharmony_ci		udelay(50);
14162306a36Sopenharmony_ci		mdic = rd32(E1000_MDIC);
14262306a36Sopenharmony_ci		if (mdic & E1000_MDIC_READY)
14362306a36Sopenharmony_ci			break;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	if (!(mdic & E1000_MDIC_READY)) {
14662306a36Sopenharmony_ci		hw_dbg("MDI Read did not complete\n");
14762306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
14862306a36Sopenharmony_ci		goto out;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	if (mdic & E1000_MDIC_ERROR) {
15162306a36Sopenharmony_ci		hw_dbg("MDI Error\n");
15262306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
15362306a36Sopenharmony_ci		goto out;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci	*data = (u16) mdic;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciout:
15862306a36Sopenharmony_ci	return ret_val;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/**
16262306a36Sopenharmony_ci *  igb_write_phy_reg_mdic - Write MDI control register
16362306a36Sopenharmony_ci *  @hw: pointer to the HW structure
16462306a36Sopenharmony_ci *  @offset: register offset to write to
16562306a36Sopenharmony_ci *  @data: data to write to register at offset
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci *  Writes data to MDI control register in the PHY at offset.
16862306a36Sopenharmony_ci **/
16962306a36Sopenharmony_cis32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
17262306a36Sopenharmony_ci	u32 i, mdic = 0;
17362306a36Sopenharmony_ci	s32 ret_val = 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (offset > MAX_PHY_REG_ADDRESS) {
17662306a36Sopenharmony_ci		hw_dbg("PHY Address %d is out of range\n", offset);
17762306a36Sopenharmony_ci		ret_val = -E1000_ERR_PARAM;
17862306a36Sopenharmony_ci		goto out;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Set up Op-code, Phy Address, and register offset in the MDI
18262306a36Sopenharmony_ci	 * Control register.  The MAC will take care of interfacing with the
18362306a36Sopenharmony_ci	 * PHY to retrieve the desired data.
18462306a36Sopenharmony_ci	 */
18562306a36Sopenharmony_ci	mdic = (((u32)data) |
18662306a36Sopenharmony_ci		(offset << E1000_MDIC_REG_SHIFT) |
18762306a36Sopenharmony_ci		(phy->addr << E1000_MDIC_PHY_SHIFT) |
18862306a36Sopenharmony_ci		(E1000_MDIC_OP_WRITE));
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	wr32(E1000_MDIC, mdic);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Poll the ready bit to see if the MDI read completed
19362306a36Sopenharmony_ci	 * Increasing the time out as testing showed failures with
19462306a36Sopenharmony_ci	 * the lower time out
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
19762306a36Sopenharmony_ci		udelay(50);
19862306a36Sopenharmony_ci		mdic = rd32(E1000_MDIC);
19962306a36Sopenharmony_ci		if (mdic & E1000_MDIC_READY)
20062306a36Sopenharmony_ci			break;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci	if (!(mdic & E1000_MDIC_READY)) {
20362306a36Sopenharmony_ci		hw_dbg("MDI Write did not complete\n");
20462306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
20562306a36Sopenharmony_ci		goto out;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci	if (mdic & E1000_MDIC_ERROR) {
20862306a36Sopenharmony_ci		hw_dbg("MDI Error\n");
20962306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
21062306a36Sopenharmony_ci		goto out;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciout:
21462306a36Sopenharmony_ci	return ret_val;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/**
21862306a36Sopenharmony_ci *  igb_read_phy_reg_i2c - Read PHY register using i2c
21962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
22062306a36Sopenharmony_ci *  @offset: register offset to be read
22162306a36Sopenharmony_ci *  @data: pointer to the read data
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci *  Reads the PHY register at offset using the i2c interface and stores the
22462306a36Sopenharmony_ci *  retrieved information in data.
22562306a36Sopenharmony_ci **/
22662306a36Sopenharmony_cis32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
22962306a36Sopenharmony_ci	u32 i, i2ccmd = 0;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Set up Op-code, Phy Address, and register address in the I2CCMD
23262306a36Sopenharmony_ci	 * register.  The MAC will take care of interfacing with the
23362306a36Sopenharmony_ci	 * PHY to retrieve the desired data.
23462306a36Sopenharmony_ci	 */
23562306a36Sopenharmony_ci	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
23662306a36Sopenharmony_ci		  (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
23762306a36Sopenharmony_ci		  (E1000_I2CCMD_OPCODE_READ));
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	wr32(E1000_I2CCMD, i2ccmd);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* Poll the ready bit to see if the I2C read completed */
24262306a36Sopenharmony_ci	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
24362306a36Sopenharmony_ci		udelay(50);
24462306a36Sopenharmony_ci		i2ccmd = rd32(E1000_I2CCMD);
24562306a36Sopenharmony_ci		if (i2ccmd & E1000_I2CCMD_READY)
24662306a36Sopenharmony_ci			break;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	if (!(i2ccmd & E1000_I2CCMD_READY)) {
24962306a36Sopenharmony_ci		hw_dbg("I2CCMD Read did not complete\n");
25062306a36Sopenharmony_ci		return -E1000_ERR_PHY;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci	if (i2ccmd & E1000_I2CCMD_ERROR) {
25362306a36Sopenharmony_ci		hw_dbg("I2CCMD Error bit set\n");
25462306a36Sopenharmony_ci		return -E1000_ERR_PHY;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* Need to byte-swap the 16-bit value. */
25862306a36Sopenharmony_ci	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	return 0;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/**
26462306a36Sopenharmony_ci *  igb_write_phy_reg_i2c - Write PHY register using i2c
26562306a36Sopenharmony_ci *  @hw: pointer to the HW structure
26662306a36Sopenharmony_ci *  @offset: register offset to write to
26762306a36Sopenharmony_ci *  @data: data to write at register offset
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci *  Writes the data to PHY register at the offset using the i2c interface.
27062306a36Sopenharmony_ci **/
27162306a36Sopenharmony_cis32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
27462306a36Sopenharmony_ci	u32 i, i2ccmd = 0;
27562306a36Sopenharmony_ci	u16 phy_data_swapped;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Prevent overwriting SFP I2C EEPROM which is at A0 address.*/
27862306a36Sopenharmony_ci	if ((hw->phy.addr == 0) || (hw->phy.addr > 7)) {
27962306a36Sopenharmony_ci		hw_dbg("PHY I2C Address %d is out of range.\n",
28062306a36Sopenharmony_ci			  hw->phy.addr);
28162306a36Sopenharmony_ci		return -E1000_ERR_CONFIG;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* Swap the data bytes for the I2C interface */
28562306a36Sopenharmony_ci	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Set up Op-code, Phy Address, and register address in the I2CCMD
28862306a36Sopenharmony_ci	 * register.  The MAC will take care of interfacing with the
28962306a36Sopenharmony_ci	 * PHY to retrieve the desired data.
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
29262306a36Sopenharmony_ci		  (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
29362306a36Sopenharmony_ci		  E1000_I2CCMD_OPCODE_WRITE |
29462306a36Sopenharmony_ci		  phy_data_swapped);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	wr32(E1000_I2CCMD, i2ccmd);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Poll the ready bit to see if the I2C read completed */
29962306a36Sopenharmony_ci	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
30062306a36Sopenharmony_ci		udelay(50);
30162306a36Sopenharmony_ci		i2ccmd = rd32(E1000_I2CCMD);
30262306a36Sopenharmony_ci		if (i2ccmd & E1000_I2CCMD_READY)
30362306a36Sopenharmony_ci			break;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci	if (!(i2ccmd & E1000_I2CCMD_READY)) {
30662306a36Sopenharmony_ci		hw_dbg("I2CCMD Write did not complete\n");
30762306a36Sopenharmony_ci		return -E1000_ERR_PHY;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	if (i2ccmd & E1000_I2CCMD_ERROR) {
31062306a36Sopenharmony_ci		hw_dbg("I2CCMD Error bit set\n");
31162306a36Sopenharmony_ci		return -E1000_ERR_PHY;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/**
31862306a36Sopenharmony_ci *  igb_read_sfp_data_byte - Reads SFP module data.
31962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
32062306a36Sopenharmony_ci *  @offset: byte location offset to be read
32162306a36Sopenharmony_ci *  @data: read data buffer pointer
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci *  Reads one byte from SFP module data stored
32462306a36Sopenharmony_ci *  in SFP resided EEPROM memory or SFP diagnostic area.
32562306a36Sopenharmony_ci *  Function should be called with
32662306a36Sopenharmony_ci *  E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
32762306a36Sopenharmony_ci *  E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
32862306a36Sopenharmony_ci *  access
32962306a36Sopenharmony_ci **/
33062306a36Sopenharmony_cis32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	u32 i = 0;
33362306a36Sopenharmony_ci	u32 i2ccmd = 0;
33462306a36Sopenharmony_ci	u32 data_local = 0;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
33762306a36Sopenharmony_ci		hw_dbg("I2CCMD command address exceeds upper limit\n");
33862306a36Sopenharmony_ci		return -E1000_ERR_PHY;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Set up Op-code, EEPROM Address,in the I2CCMD
34262306a36Sopenharmony_ci	 * register. The MAC will take care of interfacing with the
34362306a36Sopenharmony_ci	 * EEPROM to retrieve the desired data.
34462306a36Sopenharmony_ci	 */
34562306a36Sopenharmony_ci	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
34662306a36Sopenharmony_ci		  E1000_I2CCMD_OPCODE_READ);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	wr32(E1000_I2CCMD, i2ccmd);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* Poll the ready bit to see if the I2C read completed */
35162306a36Sopenharmony_ci	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
35262306a36Sopenharmony_ci		udelay(50);
35362306a36Sopenharmony_ci		data_local = rd32(E1000_I2CCMD);
35462306a36Sopenharmony_ci		if (data_local & E1000_I2CCMD_READY)
35562306a36Sopenharmony_ci			break;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci	if (!(data_local & E1000_I2CCMD_READY)) {
35862306a36Sopenharmony_ci		hw_dbg("I2CCMD Read did not complete\n");
35962306a36Sopenharmony_ci		return -E1000_ERR_PHY;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	if (data_local & E1000_I2CCMD_ERROR) {
36262306a36Sopenharmony_ci		hw_dbg("I2CCMD Error bit set\n");
36362306a36Sopenharmony_ci		return -E1000_ERR_PHY;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	*data = (u8) data_local & 0xFF;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci/**
37162306a36Sopenharmony_ci *  igb_read_phy_reg_igp - Read igp PHY register
37262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
37362306a36Sopenharmony_ci *  @offset: register offset to be read
37462306a36Sopenharmony_ci *  @data: pointer to the read data
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci *  Acquires semaphore, if necessary, then reads the PHY register at offset
37762306a36Sopenharmony_ci *  and storing the retrieved information in data.  Release any acquired
37862306a36Sopenharmony_ci *  semaphores before exiting.
37962306a36Sopenharmony_ci **/
38062306a36Sopenharmony_cis32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	s32 ret_val = 0;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (!(hw->phy.ops.acquire))
38562306a36Sopenharmony_ci		goto out;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ret_val = hw->phy.ops.acquire(hw);
38862306a36Sopenharmony_ci	if (ret_val)
38962306a36Sopenharmony_ci		goto out;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (offset > MAX_PHY_MULTI_PAGE_REG) {
39262306a36Sopenharmony_ci		ret_val = igb_write_phy_reg_mdic(hw,
39362306a36Sopenharmony_ci						 IGP01E1000_PHY_PAGE_SELECT,
39462306a36Sopenharmony_ci						 (u16)offset);
39562306a36Sopenharmony_ci		if (ret_val) {
39662306a36Sopenharmony_ci			hw->phy.ops.release(hw);
39762306a36Sopenharmony_ci			goto out;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
40262306a36Sopenharmony_ci					data);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	hw->phy.ops.release(hw);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ciout:
40762306a36Sopenharmony_ci	return ret_val;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/**
41162306a36Sopenharmony_ci *  igb_write_phy_reg_igp - Write igp PHY register
41262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
41362306a36Sopenharmony_ci *  @offset: register offset to write to
41462306a36Sopenharmony_ci *  @data: data to write at register offset
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci *  Acquires semaphore, if necessary, then writes the data to PHY register
41762306a36Sopenharmony_ci *  at the offset.  Release any acquired semaphores before exiting.
41862306a36Sopenharmony_ci **/
41962306a36Sopenharmony_cis32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	s32 ret_val = 0;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (!(hw->phy.ops.acquire))
42462306a36Sopenharmony_ci		goto out;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	ret_val = hw->phy.ops.acquire(hw);
42762306a36Sopenharmony_ci	if (ret_val)
42862306a36Sopenharmony_ci		goto out;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (offset > MAX_PHY_MULTI_PAGE_REG) {
43162306a36Sopenharmony_ci		ret_val = igb_write_phy_reg_mdic(hw,
43262306a36Sopenharmony_ci						 IGP01E1000_PHY_PAGE_SELECT,
43362306a36Sopenharmony_ci						 (u16)offset);
43462306a36Sopenharmony_ci		if (ret_val) {
43562306a36Sopenharmony_ci			hw->phy.ops.release(hw);
43662306a36Sopenharmony_ci			goto out;
43762306a36Sopenharmony_ci		}
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
44162306a36Sopenharmony_ci					 data);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	hw->phy.ops.release(hw);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ciout:
44662306a36Sopenharmony_ci	return ret_val;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci/**
45062306a36Sopenharmony_ci *  igb_copper_link_setup_82580 - Setup 82580 PHY for copper link
45162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
45262306a36Sopenharmony_ci *
45362306a36Sopenharmony_ci *  Sets up Carrier-sense on Transmit and downshift values.
45462306a36Sopenharmony_ci **/
45562306a36Sopenharmony_cis32 igb_copper_link_setup_82580(struct e1000_hw *hw)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
45862306a36Sopenharmony_ci	s32 ret_val;
45962306a36Sopenharmony_ci	u16 phy_data;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (phy->reset_disable) {
46262306a36Sopenharmony_ci		ret_val = 0;
46362306a36Sopenharmony_ci		goto out;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (phy->type == e1000_phy_82580) {
46762306a36Sopenharmony_ci		ret_val = hw->phy.ops.reset(hw);
46862306a36Sopenharmony_ci		if (ret_val) {
46962306a36Sopenharmony_ci			hw_dbg("Error resetting the PHY.\n");
47062306a36Sopenharmony_ci			goto out;
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* Enable CRS on TX. This must be set for half-duplex operation. */
47562306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, I82580_CFG_REG, &phy_data);
47662306a36Sopenharmony_ci	if (ret_val)
47762306a36Sopenharmony_ci		goto out;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	phy_data |= I82580_CFG_ASSERT_CRS_ON_TX;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/* Enable downshift */
48262306a36Sopenharmony_ci	phy_data |= I82580_CFG_ENABLE_DOWNSHIFT;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, I82580_CFG_REG, phy_data);
48562306a36Sopenharmony_ci	if (ret_val)
48662306a36Sopenharmony_ci		goto out;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* Set MDI/MDIX mode */
48962306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, I82580_PHY_CTRL_2, &phy_data);
49062306a36Sopenharmony_ci	if (ret_val)
49162306a36Sopenharmony_ci		goto out;
49262306a36Sopenharmony_ci	phy_data &= ~I82580_PHY_CTRL2_MDIX_CFG_MASK;
49362306a36Sopenharmony_ci	/* Options:
49462306a36Sopenharmony_ci	 *   0 - Auto (default)
49562306a36Sopenharmony_ci	 *   1 - MDI mode
49662306a36Sopenharmony_ci	 *   2 - MDI-X mode
49762306a36Sopenharmony_ci	 */
49862306a36Sopenharmony_ci	switch (hw->phy.mdix) {
49962306a36Sopenharmony_ci	case 1:
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci	case 2:
50262306a36Sopenharmony_ci		phy_data |= I82580_PHY_CTRL2_MANUAL_MDIX;
50362306a36Sopenharmony_ci		break;
50462306a36Sopenharmony_ci	case 0:
50562306a36Sopenharmony_ci	default:
50662306a36Sopenharmony_ci		phy_data |= I82580_PHY_CTRL2_AUTO_MDI_MDIX;
50762306a36Sopenharmony_ci		break;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	ret_val = hw->phy.ops.write_reg(hw, I82580_PHY_CTRL_2, phy_data);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ciout:
51262306a36Sopenharmony_ci	return ret_val;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/**
51662306a36Sopenharmony_ci *  igb_copper_link_setup_m88 - Setup m88 PHY's for copper link
51762306a36Sopenharmony_ci *  @hw: pointer to the HW structure
51862306a36Sopenharmony_ci *
51962306a36Sopenharmony_ci *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
52062306a36Sopenharmony_ci *  and downshift values are set also.
52162306a36Sopenharmony_ci **/
52262306a36Sopenharmony_cis32 igb_copper_link_setup_m88(struct e1000_hw *hw)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
52562306a36Sopenharmony_ci	s32 ret_val;
52662306a36Sopenharmony_ci	u16 phy_data;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (phy->reset_disable) {
52962306a36Sopenharmony_ci		ret_val = 0;
53062306a36Sopenharmony_ci		goto out;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Enable CRS on TX. This must be set for half-duplex operation. */
53462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
53562306a36Sopenharmony_ci	if (ret_val)
53662306a36Sopenharmony_ci		goto out;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/* Options:
54162306a36Sopenharmony_ci	 *   MDI/MDI-X = 0 (default)
54262306a36Sopenharmony_ci	 *   0 - Auto for all speeds
54362306a36Sopenharmony_ci	 *   1 - MDI mode
54462306a36Sopenharmony_ci	 *   2 - MDI-X mode
54562306a36Sopenharmony_ci	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
54662306a36Sopenharmony_ci	 */
54762306a36Sopenharmony_ci	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	switch (phy->mdix) {
55062306a36Sopenharmony_ci	case 1:
55162306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	case 2:
55462306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	case 3:
55762306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
55862306a36Sopenharmony_ci		break;
55962306a36Sopenharmony_ci	case 0:
56062306a36Sopenharmony_ci	default:
56162306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Options:
56662306a36Sopenharmony_ci	 *   disable_polarity_correction = 0 (default)
56762306a36Sopenharmony_ci	 *       Automatic Correction for Reversed Cable Polarity
56862306a36Sopenharmony_ci	 *   0 - Disabled
56962306a36Sopenharmony_ci	 *   1 - Enabled
57062306a36Sopenharmony_ci	 */
57162306a36Sopenharmony_ci	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
57262306a36Sopenharmony_ci	if (phy->disable_polarity_correction == 1)
57362306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
57662306a36Sopenharmony_ci	if (ret_val)
57762306a36Sopenharmony_ci		goto out;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (phy->revision < E1000_REVISION_4) {
58062306a36Sopenharmony_ci		/* Force TX_CLK in the Extended PHY Specific Control Register
58162306a36Sopenharmony_ci		 * to 25MHz clock.
58262306a36Sopenharmony_ci		 */
58362306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
58462306a36Sopenharmony_ci					    &phy_data);
58562306a36Sopenharmony_ci		if (ret_val)
58662306a36Sopenharmony_ci			goto out;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		phy_data |= M88E1000_EPSCR_TX_CLK_25;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		if ((phy->revision == E1000_REVISION_2) &&
59162306a36Sopenharmony_ci		    (phy->id == M88E1111_I_PHY_ID)) {
59262306a36Sopenharmony_ci			/* 82573L PHY - set the downshift counter to 5x. */
59362306a36Sopenharmony_ci			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
59462306a36Sopenharmony_ci			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
59562306a36Sopenharmony_ci		} else {
59662306a36Sopenharmony_ci			/* Configure Master and Slave downshift values */
59762306a36Sopenharmony_ci			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
59862306a36Sopenharmony_ci				      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
59962306a36Sopenharmony_ci			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
60062306a36Sopenharmony_ci				     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
60362306a36Sopenharmony_ci					     phy_data);
60462306a36Sopenharmony_ci		if (ret_val)
60562306a36Sopenharmony_ci			goto out;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* Commit the changes. */
60962306a36Sopenharmony_ci	ret_val = igb_phy_sw_reset(hw);
61062306a36Sopenharmony_ci	if (ret_val) {
61162306a36Sopenharmony_ci		hw_dbg("Error committing the PHY changes\n");
61262306a36Sopenharmony_ci		goto out;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ciout:
61662306a36Sopenharmony_ci	return ret_val;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/**
62062306a36Sopenharmony_ci *  igb_copper_link_setup_m88_gen2 - Setup m88 PHY's for copper link
62162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci *  Sets up MDI/MDI-X and polarity for i347-AT4, m88e1322 and m88e1112 PHY's.
62462306a36Sopenharmony_ci *  Also enables and sets the downshift parameters.
62562306a36Sopenharmony_ci **/
62662306a36Sopenharmony_cis32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
62962306a36Sopenharmony_ci	s32 ret_val;
63062306a36Sopenharmony_ci	u16 phy_data;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (phy->reset_disable)
63362306a36Sopenharmony_ci		return 0;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* Enable CRS on Tx. This must be set for half-duplex operation. */
63662306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
63762306a36Sopenharmony_ci	if (ret_val)
63862306a36Sopenharmony_ci		return ret_val;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Options:
64162306a36Sopenharmony_ci	 *   MDI/MDI-X = 0 (default)
64262306a36Sopenharmony_ci	 *   0 - Auto for all speeds
64362306a36Sopenharmony_ci	 *   1 - MDI mode
64462306a36Sopenharmony_ci	 *   2 - MDI-X mode
64562306a36Sopenharmony_ci	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
64662306a36Sopenharmony_ci	 */
64762306a36Sopenharmony_ci	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	switch (phy->mdix) {
65062306a36Sopenharmony_ci	case 1:
65162306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci	case 2:
65462306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
65562306a36Sopenharmony_ci		break;
65662306a36Sopenharmony_ci	case 3:
65762306a36Sopenharmony_ci		/* M88E1112 does not support this mode) */
65862306a36Sopenharmony_ci		if (phy->id != M88E1112_E_PHY_ID) {
65962306a36Sopenharmony_ci			phy_data |= M88E1000_PSCR_AUTO_X_1000T;
66062306a36Sopenharmony_ci			break;
66162306a36Sopenharmony_ci		}
66262306a36Sopenharmony_ci		fallthrough;
66362306a36Sopenharmony_ci	case 0:
66462306a36Sopenharmony_ci	default:
66562306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
66662306a36Sopenharmony_ci		break;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* Options:
67062306a36Sopenharmony_ci	 *   disable_polarity_correction = 0 (default)
67162306a36Sopenharmony_ci	 *       Automatic Correction for Reversed Cable Polarity
67262306a36Sopenharmony_ci	 *   0 - Disabled
67362306a36Sopenharmony_ci	 *   1 - Enabled
67462306a36Sopenharmony_ci	 */
67562306a36Sopenharmony_ci	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
67662306a36Sopenharmony_ci	if (phy->disable_polarity_correction == 1)
67762306a36Sopenharmony_ci		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/* Enable downshift and setting it to X6 */
68062306a36Sopenharmony_ci	if (phy->id == M88E1543_E_PHY_ID) {
68162306a36Sopenharmony_ci		phy_data &= ~I347AT4_PSCR_DOWNSHIFT_ENABLE;
68262306a36Sopenharmony_ci		ret_val =
68362306a36Sopenharmony_ci		    phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
68462306a36Sopenharmony_ci		if (ret_val)
68562306a36Sopenharmony_ci			return ret_val;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		ret_val = igb_phy_sw_reset(hw);
68862306a36Sopenharmony_ci		if (ret_val) {
68962306a36Sopenharmony_ci			hw_dbg("Error committing the PHY changes\n");
69062306a36Sopenharmony_ci			return ret_val;
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	phy_data &= ~I347AT4_PSCR_DOWNSHIFT_MASK;
69562306a36Sopenharmony_ci	phy_data |= I347AT4_PSCR_DOWNSHIFT_6X;
69662306a36Sopenharmony_ci	phy_data |= I347AT4_PSCR_DOWNSHIFT_ENABLE;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
69962306a36Sopenharmony_ci	if (ret_val)
70062306a36Sopenharmony_ci		return ret_val;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* Commit the changes. */
70362306a36Sopenharmony_ci	ret_val = igb_phy_sw_reset(hw);
70462306a36Sopenharmony_ci	if (ret_val) {
70562306a36Sopenharmony_ci		hw_dbg("Error committing the PHY changes\n");
70662306a36Sopenharmony_ci		return ret_val;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci	ret_val = igb_set_master_slave_mode(hw);
70962306a36Sopenharmony_ci	if (ret_val)
71062306a36Sopenharmony_ci		return ret_val;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	return 0;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/**
71662306a36Sopenharmony_ci *  igb_copper_link_setup_igp - Setup igp PHY's for copper link
71762306a36Sopenharmony_ci *  @hw: pointer to the HW structure
71862306a36Sopenharmony_ci *
71962306a36Sopenharmony_ci *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
72062306a36Sopenharmony_ci *  igp PHY's.
72162306a36Sopenharmony_ci **/
72262306a36Sopenharmony_cis32 igb_copper_link_setup_igp(struct e1000_hw *hw)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
72562306a36Sopenharmony_ci	s32 ret_val;
72662306a36Sopenharmony_ci	u16 data;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (phy->reset_disable) {
72962306a36Sopenharmony_ci		ret_val = 0;
73062306a36Sopenharmony_ci		goto out;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	ret_val = phy->ops.reset(hw);
73462306a36Sopenharmony_ci	if (ret_val) {
73562306a36Sopenharmony_ci		hw_dbg("Error resetting the PHY.\n");
73662306a36Sopenharmony_ci		goto out;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* Wait 100ms for MAC to configure PHY from NVM settings, to avoid
74062306a36Sopenharmony_ci	 * timeout issues when LFS is enabled.
74162306a36Sopenharmony_ci	 */
74262306a36Sopenharmony_ci	msleep(100);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	/* The NVM settings will configure LPLU in D3 for
74562306a36Sopenharmony_ci	 * non-IGP1 PHYs.
74662306a36Sopenharmony_ci	 */
74762306a36Sopenharmony_ci	if (phy->type == e1000_phy_igp) {
74862306a36Sopenharmony_ci		/* disable lplu d3 during driver init */
74962306a36Sopenharmony_ci		if (phy->ops.set_d3_lplu_state)
75062306a36Sopenharmony_ci			ret_val = phy->ops.set_d3_lplu_state(hw, false);
75162306a36Sopenharmony_ci		if (ret_val) {
75262306a36Sopenharmony_ci			hw_dbg("Error Disabling LPLU D3\n");
75362306a36Sopenharmony_ci			goto out;
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* disable lplu d0 during driver init */
75862306a36Sopenharmony_ci	ret_val = phy->ops.set_d0_lplu_state(hw, false);
75962306a36Sopenharmony_ci	if (ret_val) {
76062306a36Sopenharmony_ci		hw_dbg("Error Disabling LPLU D0\n");
76162306a36Sopenharmony_ci		goto out;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci	/* Configure mdi-mdix settings */
76462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
76562306a36Sopenharmony_ci	if (ret_val)
76662306a36Sopenharmony_ci		goto out;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	switch (phy->mdix) {
77162306a36Sopenharmony_ci	case 1:
77262306a36Sopenharmony_ci		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
77362306a36Sopenharmony_ci		break;
77462306a36Sopenharmony_ci	case 2:
77562306a36Sopenharmony_ci		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
77662306a36Sopenharmony_ci		break;
77762306a36Sopenharmony_ci	case 0:
77862306a36Sopenharmony_ci	default:
77962306a36Sopenharmony_ci		data |= IGP01E1000_PSCR_AUTO_MDIX;
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
78362306a36Sopenharmony_ci	if (ret_val)
78462306a36Sopenharmony_ci		goto out;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	/* set auto-master slave resolution settings */
78762306a36Sopenharmony_ci	if (hw->mac.autoneg) {
78862306a36Sopenharmony_ci		/* when autonegotiation advertisement is only 1000Mbps then we
78962306a36Sopenharmony_ci		 * should disable SmartSpeed and enable Auto MasterSlave
79062306a36Sopenharmony_ci		 * resolution as hardware default.
79162306a36Sopenharmony_ci		 */
79262306a36Sopenharmony_ci		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
79362306a36Sopenharmony_ci			/* Disable SmartSpeed */
79462306a36Sopenharmony_ci			ret_val = phy->ops.read_reg(hw,
79562306a36Sopenharmony_ci						    IGP01E1000_PHY_PORT_CONFIG,
79662306a36Sopenharmony_ci						    &data);
79762306a36Sopenharmony_ci			if (ret_val)
79862306a36Sopenharmony_ci				goto out;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
80162306a36Sopenharmony_ci			ret_val = phy->ops.write_reg(hw,
80262306a36Sopenharmony_ci						     IGP01E1000_PHY_PORT_CONFIG,
80362306a36Sopenharmony_ci						     data);
80462306a36Sopenharmony_ci			if (ret_val)
80562306a36Sopenharmony_ci				goto out;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci			/* Set auto Master/Slave resolution process */
80862306a36Sopenharmony_ci			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
80962306a36Sopenharmony_ci			if (ret_val)
81062306a36Sopenharmony_ci				goto out;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci			data &= ~CR_1000T_MS_ENABLE;
81362306a36Sopenharmony_ci			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
81462306a36Sopenharmony_ci			if (ret_val)
81562306a36Sopenharmony_ci				goto out;
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
81962306a36Sopenharmony_ci		if (ret_val)
82062306a36Sopenharmony_ci			goto out;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		/* load defaults for future use */
82362306a36Sopenharmony_ci		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
82462306a36Sopenharmony_ci			((data & CR_1000T_MS_VALUE) ?
82562306a36Sopenharmony_ci			e1000_ms_force_master :
82662306a36Sopenharmony_ci			e1000_ms_force_slave) :
82762306a36Sopenharmony_ci			e1000_ms_auto;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		switch (phy->ms_type) {
83062306a36Sopenharmony_ci		case e1000_ms_force_master:
83162306a36Sopenharmony_ci			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
83262306a36Sopenharmony_ci			break;
83362306a36Sopenharmony_ci		case e1000_ms_force_slave:
83462306a36Sopenharmony_ci			data |= CR_1000T_MS_ENABLE;
83562306a36Sopenharmony_ci			data &= ~(CR_1000T_MS_VALUE);
83662306a36Sopenharmony_ci			break;
83762306a36Sopenharmony_ci		case e1000_ms_auto:
83862306a36Sopenharmony_ci			data &= ~CR_1000T_MS_ENABLE;
83962306a36Sopenharmony_ci			break;
84062306a36Sopenharmony_ci		default:
84162306a36Sopenharmony_ci			break;
84262306a36Sopenharmony_ci		}
84362306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
84462306a36Sopenharmony_ci		if (ret_val)
84562306a36Sopenharmony_ci			goto out;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ciout:
84962306a36Sopenharmony_ci	return ret_val;
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci/**
85362306a36Sopenharmony_ci *  igb_copper_link_autoneg - Setup/Enable autoneg for copper link
85462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci *  Performs initial bounds checking on autoneg advertisement parameter, then
85762306a36Sopenharmony_ci *  configure to advertise the full capability.  Setup the PHY to autoneg
85862306a36Sopenharmony_ci *  and restart the negotiation process between the link partner.  If
85962306a36Sopenharmony_ci *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
86062306a36Sopenharmony_ci **/
86162306a36Sopenharmony_cistatic s32 igb_copper_link_autoneg(struct e1000_hw *hw)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
86462306a36Sopenharmony_ci	s32 ret_val;
86562306a36Sopenharmony_ci	u16 phy_ctrl;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	/* Perform some bounds checking on the autoneg advertisement
86862306a36Sopenharmony_ci	 * parameter.
86962306a36Sopenharmony_ci	 */
87062306a36Sopenharmony_ci	phy->autoneg_advertised &= phy->autoneg_mask;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* If autoneg_advertised is zero, we assume it was not defaulted
87362306a36Sopenharmony_ci	 * by the calling code so we set to advertise full capability.
87462306a36Sopenharmony_ci	 */
87562306a36Sopenharmony_ci	if (phy->autoneg_advertised == 0)
87662306a36Sopenharmony_ci		phy->autoneg_advertised = phy->autoneg_mask;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	hw_dbg("Reconfiguring auto-neg advertisement params\n");
87962306a36Sopenharmony_ci	ret_val = igb_phy_setup_autoneg(hw);
88062306a36Sopenharmony_ci	if (ret_val) {
88162306a36Sopenharmony_ci		hw_dbg("Error Setting up Auto-Negotiation\n");
88262306a36Sopenharmony_ci		goto out;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci	hw_dbg("Restarting Auto-Neg\n");
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* Restart auto-negotiation by setting the Auto Neg Enable bit and
88762306a36Sopenharmony_ci	 * the Auto Neg Restart bit in the PHY control register.
88862306a36Sopenharmony_ci	 */
88962306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
89062306a36Sopenharmony_ci	if (ret_val)
89162306a36Sopenharmony_ci		goto out;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
89462306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
89562306a36Sopenharmony_ci	if (ret_val)
89662306a36Sopenharmony_ci		goto out;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	/* Does the user want to wait for Auto-Neg to complete here, or
89962306a36Sopenharmony_ci	 * check at a later time (for example, callback routine).
90062306a36Sopenharmony_ci	 */
90162306a36Sopenharmony_ci	if (phy->autoneg_wait_to_complete) {
90262306a36Sopenharmony_ci		ret_val = igb_wait_autoneg(hw);
90362306a36Sopenharmony_ci		if (ret_val) {
90462306a36Sopenharmony_ci			hw_dbg("Error while waiting for autoneg to complete\n");
90562306a36Sopenharmony_ci			goto out;
90662306a36Sopenharmony_ci		}
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	hw->mac.get_link_status = true;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ciout:
91262306a36Sopenharmony_ci	return ret_val;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci/**
91662306a36Sopenharmony_ci *  igb_phy_setup_autoneg - Configure PHY for auto-negotiation
91762306a36Sopenharmony_ci *  @hw: pointer to the HW structure
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci *  Reads the MII auto-neg advertisement register and/or the 1000T control
92062306a36Sopenharmony_ci *  register and if the PHY is already setup for auto-negotiation, then
92162306a36Sopenharmony_ci *  return successful.  Otherwise, setup advertisement and flow control to
92262306a36Sopenharmony_ci *  the appropriate values for the wanted auto-negotiation.
92362306a36Sopenharmony_ci **/
92462306a36Sopenharmony_cistatic s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
92762306a36Sopenharmony_ci	s32 ret_val;
92862306a36Sopenharmony_ci	u16 mii_autoneg_adv_reg;
92962306a36Sopenharmony_ci	u16 mii_1000t_ctrl_reg = 0;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	phy->autoneg_advertised &= phy->autoneg_mask;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
93462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
93562306a36Sopenharmony_ci	if (ret_val)
93662306a36Sopenharmony_ci		goto out;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
93962306a36Sopenharmony_ci		/* Read the MII 1000Base-T Control Register (Address 9). */
94062306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
94162306a36Sopenharmony_ci					    &mii_1000t_ctrl_reg);
94262306a36Sopenharmony_ci		if (ret_val)
94362306a36Sopenharmony_ci			goto out;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* Need to parse both autoneg_advertised and fc and set up
94762306a36Sopenharmony_ci	 * the appropriate PHY registers.  First we will parse for
94862306a36Sopenharmony_ci	 * autoneg_advertised software override.  Since we can advertise
94962306a36Sopenharmony_ci	 * a plethora of combinations, we need to check each bit
95062306a36Sopenharmony_ci	 * individually.
95162306a36Sopenharmony_ci	 */
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/* First we clear all the 10/100 mb speed bits in the Auto-Neg
95462306a36Sopenharmony_ci	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
95562306a36Sopenharmony_ci	 * the  1000Base-T Control Register (Address 9).
95662306a36Sopenharmony_ci	 */
95762306a36Sopenharmony_ci	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
95862306a36Sopenharmony_ci				 NWAY_AR_100TX_HD_CAPS |
95962306a36Sopenharmony_ci				 NWAY_AR_10T_FD_CAPS   |
96062306a36Sopenharmony_ci				 NWAY_AR_10T_HD_CAPS);
96162306a36Sopenharmony_ci	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Do we want to advertise 10 Mb Half Duplex? */
96662306a36Sopenharmony_ci	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
96762306a36Sopenharmony_ci		hw_dbg("Advertise 10mb Half duplex\n");
96862306a36Sopenharmony_ci		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* Do we want to advertise 10 Mb Full Duplex? */
97262306a36Sopenharmony_ci	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
97362306a36Sopenharmony_ci		hw_dbg("Advertise 10mb Full duplex\n");
97462306a36Sopenharmony_ci		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* Do we want to advertise 100 Mb Half Duplex? */
97862306a36Sopenharmony_ci	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
97962306a36Sopenharmony_ci		hw_dbg("Advertise 100mb Half duplex\n");
98062306a36Sopenharmony_ci		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* Do we want to advertise 100 Mb Full Duplex? */
98462306a36Sopenharmony_ci	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
98562306a36Sopenharmony_ci		hw_dbg("Advertise 100mb Full duplex\n");
98662306a36Sopenharmony_ci		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
99062306a36Sopenharmony_ci	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
99162306a36Sopenharmony_ci		hw_dbg("Advertise 1000mb Half duplex request denied!\n");
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Do we want to advertise 1000 Mb Full Duplex? */
99462306a36Sopenharmony_ci	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
99562306a36Sopenharmony_ci		hw_dbg("Advertise 1000mb Full duplex\n");
99662306a36Sopenharmony_ci		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/* Check for a software override of the flow control settings, and
100062306a36Sopenharmony_ci	 * setup the PHY advertisement registers accordingly.  If
100162306a36Sopenharmony_ci	 * auto-negotiation is enabled, then software will have to set the
100262306a36Sopenharmony_ci	 * "PAUSE" bits to the correct value in the Auto-Negotiation
100362306a36Sopenharmony_ci	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
100462306a36Sopenharmony_ci	 * negotiation.
100562306a36Sopenharmony_ci	 *
100662306a36Sopenharmony_ci	 * The possible values of the "fc" parameter are:
100762306a36Sopenharmony_ci	 *      0:  Flow control is completely disabled
100862306a36Sopenharmony_ci	 *      1:  Rx flow control is enabled (we can receive pause frames
100962306a36Sopenharmony_ci	 *          but not send pause frames).
101062306a36Sopenharmony_ci	 *      2:  Tx flow control is enabled (we can send pause frames
101162306a36Sopenharmony_ci	 *          but we do not support receiving pause frames).
101262306a36Sopenharmony_ci	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
101362306a36Sopenharmony_ci	 *  other:  No software override.  The flow control configuration
101462306a36Sopenharmony_ci	 *          in the EEPROM is used.
101562306a36Sopenharmony_ci	 */
101662306a36Sopenharmony_ci	switch (hw->fc.current_mode) {
101762306a36Sopenharmony_ci	case e1000_fc_none:
101862306a36Sopenharmony_ci		/* Flow control (RX & TX) is completely disabled by a
101962306a36Sopenharmony_ci		 * software over-ride.
102062306a36Sopenharmony_ci		 */
102162306a36Sopenharmony_ci		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
102262306a36Sopenharmony_ci		break;
102362306a36Sopenharmony_ci	case e1000_fc_rx_pause:
102462306a36Sopenharmony_ci		/* RX Flow control is enabled, and TX Flow control is
102562306a36Sopenharmony_ci		 * disabled, by a software over-ride.
102662306a36Sopenharmony_ci		 *
102762306a36Sopenharmony_ci		 * Since there really isn't a way to advertise that we are
102862306a36Sopenharmony_ci		 * capable of RX Pause ONLY, we will advertise that we
102962306a36Sopenharmony_ci		 * support both symmetric and asymmetric RX PAUSE.  Later
103062306a36Sopenharmony_ci		 * (in e1000_config_fc_after_link_up) we will disable the
103162306a36Sopenharmony_ci		 * hw's ability to send PAUSE frames.
103262306a36Sopenharmony_ci		 */
103362306a36Sopenharmony_ci		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
103462306a36Sopenharmony_ci		break;
103562306a36Sopenharmony_ci	case e1000_fc_tx_pause:
103662306a36Sopenharmony_ci		/* TX Flow control is enabled, and RX Flow control is
103762306a36Sopenharmony_ci		 * disabled, by a software over-ride.
103862306a36Sopenharmony_ci		 */
103962306a36Sopenharmony_ci		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
104062306a36Sopenharmony_ci		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
104162306a36Sopenharmony_ci		break;
104262306a36Sopenharmony_ci	case e1000_fc_full:
104362306a36Sopenharmony_ci		/* Flow control (both RX and TX) is enabled by a software
104462306a36Sopenharmony_ci		 * over-ride.
104562306a36Sopenharmony_ci		 */
104662306a36Sopenharmony_ci		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
104762306a36Sopenharmony_ci		break;
104862306a36Sopenharmony_ci	default:
104962306a36Sopenharmony_ci		hw_dbg("Flow control param set incorrectly\n");
105062306a36Sopenharmony_ci		ret_val = -E1000_ERR_CONFIG;
105162306a36Sopenharmony_ci		goto out;
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
105562306a36Sopenharmony_ci	if (ret_val)
105662306a36Sopenharmony_ci		goto out;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
106162306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw,
106262306a36Sopenharmony_ci					     PHY_1000T_CTRL,
106362306a36Sopenharmony_ci					     mii_1000t_ctrl_reg);
106462306a36Sopenharmony_ci		if (ret_val)
106562306a36Sopenharmony_ci			goto out;
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ciout:
106962306a36Sopenharmony_ci	return ret_val;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci/**
107362306a36Sopenharmony_ci *  igb_setup_copper_link - Configure copper link settings
107462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
107562306a36Sopenharmony_ci *
107662306a36Sopenharmony_ci *  Calls the appropriate function to configure the link for auto-neg or forced
107762306a36Sopenharmony_ci *  speed and duplex.  Then we check for link, once link is established calls
107862306a36Sopenharmony_ci *  to configure collision distance and flow control are called.  If link is
107962306a36Sopenharmony_ci *  not established, we return -E1000_ERR_PHY (-2).
108062306a36Sopenharmony_ci **/
108162306a36Sopenharmony_cis32 igb_setup_copper_link(struct e1000_hw *hw)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	s32 ret_val;
108462306a36Sopenharmony_ci	bool link;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (hw->mac.autoneg) {
108762306a36Sopenharmony_ci		/* Setup autoneg and flow control advertisement and perform
108862306a36Sopenharmony_ci		 * autonegotiation.
108962306a36Sopenharmony_ci		 */
109062306a36Sopenharmony_ci		ret_val = igb_copper_link_autoneg(hw);
109162306a36Sopenharmony_ci		if (ret_val)
109262306a36Sopenharmony_ci			goto out;
109362306a36Sopenharmony_ci	} else {
109462306a36Sopenharmony_ci		/* PHY will be set to 10H, 10F, 100H or 100F
109562306a36Sopenharmony_ci		 * depending on user settings.
109662306a36Sopenharmony_ci		 */
109762306a36Sopenharmony_ci		hw_dbg("Forcing Speed and Duplex\n");
109862306a36Sopenharmony_ci		ret_val = hw->phy.ops.force_speed_duplex(hw);
109962306a36Sopenharmony_ci		if (ret_val) {
110062306a36Sopenharmony_ci			hw_dbg("Error Forcing Speed and Duplex\n");
110162306a36Sopenharmony_ci			goto out;
110262306a36Sopenharmony_ci		}
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* Check link status. Wait up to 100 microseconds for link to become
110662306a36Sopenharmony_ci	 * valid.
110762306a36Sopenharmony_ci	 */
110862306a36Sopenharmony_ci	ret_val = igb_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
110962306a36Sopenharmony_ci	if (ret_val)
111062306a36Sopenharmony_ci		goto out;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	if (link) {
111362306a36Sopenharmony_ci		hw_dbg("Valid link established!!!\n");
111462306a36Sopenharmony_ci		igb_config_collision_dist(hw);
111562306a36Sopenharmony_ci		ret_val = igb_config_fc_after_link_up(hw);
111662306a36Sopenharmony_ci	} else {
111762306a36Sopenharmony_ci		hw_dbg("Unable to establish link!!!\n");
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ciout:
112162306a36Sopenharmony_ci	return ret_val;
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci/**
112562306a36Sopenharmony_ci *  igb_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
112662306a36Sopenharmony_ci *  @hw: pointer to the HW structure
112762306a36Sopenharmony_ci *
112862306a36Sopenharmony_ci *  Calls the PHY setup function to force speed and duplex.  Clears the
112962306a36Sopenharmony_ci *  auto-crossover to force MDI manually.  Waits for link and returns
113062306a36Sopenharmony_ci *  successful if link up is successful, else -E1000_ERR_PHY (-2).
113162306a36Sopenharmony_ci **/
113262306a36Sopenharmony_cis32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
113562306a36Sopenharmony_ci	s32 ret_val;
113662306a36Sopenharmony_ci	u16 phy_data;
113762306a36Sopenharmony_ci	bool link;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
114062306a36Sopenharmony_ci	if (ret_val)
114162306a36Sopenharmony_ci		goto out;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	igb_phy_force_speed_duplex_setup(hw, &phy_data);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
114662306a36Sopenharmony_ci	if (ret_val)
114762306a36Sopenharmony_ci		goto out;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	/* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
115062306a36Sopenharmony_ci	 * forced whenever speed and duplex are forced.
115162306a36Sopenharmony_ci	 */
115262306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
115362306a36Sopenharmony_ci	if (ret_val)
115462306a36Sopenharmony_ci		goto out;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
115762306a36Sopenharmony_ci	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
116062306a36Sopenharmony_ci	if (ret_val)
116162306a36Sopenharmony_ci		goto out;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	hw_dbg("IGP PSCR: %X\n", phy_data);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	udelay(1);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	if (phy->autoneg_wait_to_complete) {
116862306a36Sopenharmony_ci		hw_dbg("Waiting for forced speed/duplex link on IGP phy.\n");
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 10000, &link);
117162306a36Sopenharmony_ci		if (ret_val)
117262306a36Sopenharmony_ci			goto out;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		if (!link)
117562306a36Sopenharmony_ci			hw_dbg("Link taking longer than expected.\n");
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		/* Try once more */
117862306a36Sopenharmony_ci		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 10000, &link);
117962306a36Sopenharmony_ci		if (ret_val)
118062306a36Sopenharmony_ci			goto out;
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ciout:
118462306a36Sopenharmony_ci	return ret_val;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci/**
118862306a36Sopenharmony_ci *  igb_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
118962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
119062306a36Sopenharmony_ci *
119162306a36Sopenharmony_ci *  Calls the PHY setup function to force speed and duplex.  Clears the
119262306a36Sopenharmony_ci *  auto-crossover to force MDI manually.  Resets the PHY to commit the
119362306a36Sopenharmony_ci *  changes.  If time expires while waiting for link up, we reset the DSP.
119462306a36Sopenharmony_ci *  After reset, TX_CLK and CRS on TX must be set.  Return successful upon
119562306a36Sopenharmony_ci *  successful completion, else return corresponding error code.
119662306a36Sopenharmony_ci **/
119762306a36Sopenharmony_cis32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
120062306a36Sopenharmony_ci	s32 ret_val;
120162306a36Sopenharmony_ci	u16 phy_data;
120262306a36Sopenharmony_ci	bool link;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	/* I210 and I211 devices support Auto-Crossover in forced operation. */
120562306a36Sopenharmony_ci	if (phy->type != e1000_phy_i210) {
120662306a36Sopenharmony_ci		/* Clear Auto-Crossover to force MDI manually.  M88E1000
120762306a36Sopenharmony_ci		 * requires MDI forced whenever speed and duplex are forced.
120862306a36Sopenharmony_ci		 */
120962306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL,
121062306a36Sopenharmony_ci					    &phy_data);
121162306a36Sopenharmony_ci		if (ret_val)
121262306a36Sopenharmony_ci			goto out;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
121562306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL,
121662306a36Sopenharmony_ci					     phy_data);
121762306a36Sopenharmony_ci		if (ret_val)
121862306a36Sopenharmony_ci			goto out;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci		hw_dbg("M88E1000 PSCR: %X\n", phy_data);
122162306a36Sopenharmony_ci	}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
122462306a36Sopenharmony_ci	if (ret_val)
122562306a36Sopenharmony_ci		goto out;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	igb_phy_force_speed_duplex_setup(hw, &phy_data);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
123062306a36Sopenharmony_ci	if (ret_val)
123162306a36Sopenharmony_ci		goto out;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/* Reset the phy to commit changes. */
123462306a36Sopenharmony_ci	ret_val = igb_phy_sw_reset(hw);
123562306a36Sopenharmony_ci	if (ret_val)
123662306a36Sopenharmony_ci		goto out;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (phy->autoneg_wait_to_complete) {
123962306a36Sopenharmony_ci		hw_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
124262306a36Sopenharmony_ci		if (ret_val)
124362306a36Sopenharmony_ci			goto out;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci		if (!link) {
124662306a36Sopenharmony_ci			bool reset_dsp = true;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci			switch (hw->phy.id) {
124962306a36Sopenharmony_ci			case I347AT4_E_PHY_ID:
125062306a36Sopenharmony_ci			case M88E1112_E_PHY_ID:
125162306a36Sopenharmony_ci			case M88E1543_E_PHY_ID:
125262306a36Sopenharmony_ci			case M88E1512_E_PHY_ID:
125362306a36Sopenharmony_ci			case I210_I_PHY_ID:
125462306a36Sopenharmony_ci				reset_dsp = false;
125562306a36Sopenharmony_ci				break;
125662306a36Sopenharmony_ci			default:
125762306a36Sopenharmony_ci				if (hw->phy.type != e1000_phy_m88)
125862306a36Sopenharmony_ci					reset_dsp = false;
125962306a36Sopenharmony_ci				break;
126062306a36Sopenharmony_ci			}
126162306a36Sopenharmony_ci			if (!reset_dsp) {
126262306a36Sopenharmony_ci				hw_dbg("Link taking longer than expected.\n");
126362306a36Sopenharmony_ci			} else {
126462306a36Sopenharmony_ci				/* We didn't get link.
126562306a36Sopenharmony_ci				 * Reset the DSP and cross our fingers.
126662306a36Sopenharmony_ci				 */
126762306a36Sopenharmony_ci				ret_val = phy->ops.write_reg(hw,
126862306a36Sopenharmony_ci						M88E1000_PHY_PAGE_SELECT,
126962306a36Sopenharmony_ci						0x001d);
127062306a36Sopenharmony_ci				if (ret_val)
127162306a36Sopenharmony_ci					goto out;
127262306a36Sopenharmony_ci				ret_val = igb_phy_reset_dsp(hw);
127362306a36Sopenharmony_ci				if (ret_val)
127462306a36Sopenharmony_ci					goto out;
127562306a36Sopenharmony_ci			}
127662306a36Sopenharmony_ci		}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci		/* Try once more */
127962306a36Sopenharmony_ci		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT,
128062306a36Sopenharmony_ci					   100000, &link);
128162306a36Sopenharmony_ci		if (ret_val)
128262306a36Sopenharmony_ci			goto out;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (hw->phy.type != e1000_phy_m88 ||
128662306a36Sopenharmony_ci	    hw->phy.id == I347AT4_E_PHY_ID ||
128762306a36Sopenharmony_ci	    hw->phy.id == M88E1112_E_PHY_ID ||
128862306a36Sopenharmony_ci	    hw->phy.id == M88E1543_E_PHY_ID ||
128962306a36Sopenharmony_ci	    hw->phy.id == M88E1512_E_PHY_ID ||
129062306a36Sopenharmony_ci	    hw->phy.id == I210_I_PHY_ID)
129162306a36Sopenharmony_ci		goto out;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
129462306a36Sopenharmony_ci	if (ret_val)
129562306a36Sopenharmony_ci		goto out;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	/* Resetting the phy means we need to re-force TX_CLK in the
129862306a36Sopenharmony_ci	 * Extended PHY Specific Control Register to 25MHz clock from
129962306a36Sopenharmony_ci	 * the reset value of 2.5MHz.
130062306a36Sopenharmony_ci	 */
130162306a36Sopenharmony_ci	phy_data |= M88E1000_EPSCR_TX_CLK_25;
130262306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
130362306a36Sopenharmony_ci	if (ret_val)
130462306a36Sopenharmony_ci		goto out;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* In addition, we must re-enable CRS on Tx for both half and full
130762306a36Sopenharmony_ci	 * duplex.
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
131062306a36Sopenharmony_ci	if (ret_val)
131162306a36Sopenharmony_ci		goto out;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
131462306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ciout:
131762306a36Sopenharmony_ci	return ret_val;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci/**
132162306a36Sopenharmony_ci *  igb_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
132262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
132362306a36Sopenharmony_ci *  @phy_ctrl: pointer to current value of PHY_CONTROL
132462306a36Sopenharmony_ci *
132562306a36Sopenharmony_ci *  Forces speed and duplex on the PHY by doing the following: disable flow
132662306a36Sopenharmony_ci *  control, force speed/duplex on the MAC, disable auto speed detection,
132762306a36Sopenharmony_ci *  disable auto-negotiation, configure duplex, configure speed, configure
132862306a36Sopenharmony_ci *  the collision distance, write configuration to CTRL register.  The
132962306a36Sopenharmony_ci *  caller must write to the PHY_CONTROL register for these settings to
133062306a36Sopenharmony_ci *  take affect.
133162306a36Sopenharmony_ci **/
133262306a36Sopenharmony_cistatic void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
133362306a36Sopenharmony_ci					     u16 *phy_ctrl)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	struct e1000_mac_info *mac = &hw->mac;
133662306a36Sopenharmony_ci	u32 ctrl;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* Turn off flow control when forcing speed/duplex */
133962306a36Sopenharmony_ci	hw->fc.current_mode = e1000_fc_none;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	/* Force speed/duplex on the mac */
134262306a36Sopenharmony_ci	ctrl = rd32(E1000_CTRL);
134362306a36Sopenharmony_ci	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
134462306a36Sopenharmony_ci	ctrl &= ~E1000_CTRL_SPD_SEL;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* Disable Auto Speed Detection */
134762306a36Sopenharmony_ci	ctrl &= ~E1000_CTRL_ASDE;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/* Disable autoneg on the phy */
135062306a36Sopenharmony_ci	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	/* Forcing Full or Half Duplex? */
135362306a36Sopenharmony_ci	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
135462306a36Sopenharmony_ci		ctrl &= ~E1000_CTRL_FD;
135562306a36Sopenharmony_ci		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
135662306a36Sopenharmony_ci		hw_dbg("Half Duplex\n");
135762306a36Sopenharmony_ci	} else {
135862306a36Sopenharmony_ci		ctrl |= E1000_CTRL_FD;
135962306a36Sopenharmony_ci		*phy_ctrl |= MII_CR_FULL_DUPLEX;
136062306a36Sopenharmony_ci		hw_dbg("Full Duplex\n");
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	/* Forcing 10mb or 100mb? */
136462306a36Sopenharmony_ci	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
136562306a36Sopenharmony_ci		ctrl |= E1000_CTRL_SPD_100;
136662306a36Sopenharmony_ci		*phy_ctrl |= MII_CR_SPEED_100;
136762306a36Sopenharmony_ci		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
136862306a36Sopenharmony_ci		hw_dbg("Forcing 100mb\n");
136962306a36Sopenharmony_ci	} else {
137062306a36Sopenharmony_ci		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
137162306a36Sopenharmony_ci		*phy_ctrl |= MII_CR_SPEED_10;
137262306a36Sopenharmony_ci		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
137362306a36Sopenharmony_ci		hw_dbg("Forcing 10mb\n");
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	igb_config_collision_dist(hw);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	wr32(E1000_CTRL, ctrl);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci/**
138262306a36Sopenharmony_ci *  igb_set_d3_lplu_state - Sets low power link up state for D3
138362306a36Sopenharmony_ci *  @hw: pointer to the HW structure
138462306a36Sopenharmony_ci *  @active: boolean used to enable/disable lplu
138562306a36Sopenharmony_ci *
138662306a36Sopenharmony_ci *  Success returns 0, Failure returns 1
138762306a36Sopenharmony_ci *
138862306a36Sopenharmony_ci *  The low power link up (lplu) state is set to the power management level D3
138962306a36Sopenharmony_ci *  and SmartSpeed is disabled when active is true, else clear lplu for D3
139062306a36Sopenharmony_ci *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
139162306a36Sopenharmony_ci *  is used during Dx states where the power conservation is most important.
139262306a36Sopenharmony_ci *  During driver activity, SmartSpeed should be enabled so performance is
139362306a36Sopenharmony_ci *  maintained.
139462306a36Sopenharmony_ci **/
139562306a36Sopenharmony_cis32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
139662306a36Sopenharmony_ci{
139762306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
139862306a36Sopenharmony_ci	s32 ret_val = 0;
139962306a36Sopenharmony_ci	u16 data;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (!(hw->phy.ops.read_reg))
140262306a36Sopenharmony_ci		goto out;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
140562306a36Sopenharmony_ci	if (ret_val)
140662306a36Sopenharmony_ci		goto out;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (!active) {
140962306a36Sopenharmony_ci		data &= ~IGP02E1000_PM_D3_LPLU;
141062306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
141162306a36Sopenharmony_ci					     data);
141262306a36Sopenharmony_ci		if (ret_val)
141362306a36Sopenharmony_ci			goto out;
141462306a36Sopenharmony_ci		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
141562306a36Sopenharmony_ci		 * during Dx states where the power conservation is most
141662306a36Sopenharmony_ci		 * important.  During driver activity we should enable
141762306a36Sopenharmony_ci		 * SmartSpeed, so performance is maintained.
141862306a36Sopenharmony_ci		 */
141962306a36Sopenharmony_ci		if (phy->smart_speed == e1000_smart_speed_on) {
142062306a36Sopenharmony_ci			ret_val = phy->ops.read_reg(hw,
142162306a36Sopenharmony_ci						    IGP01E1000_PHY_PORT_CONFIG,
142262306a36Sopenharmony_ci						    &data);
142362306a36Sopenharmony_ci			if (ret_val)
142462306a36Sopenharmony_ci				goto out;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci			data |= IGP01E1000_PSCFR_SMART_SPEED;
142762306a36Sopenharmony_ci			ret_val = phy->ops.write_reg(hw,
142862306a36Sopenharmony_ci						     IGP01E1000_PHY_PORT_CONFIG,
142962306a36Sopenharmony_ci						     data);
143062306a36Sopenharmony_ci			if (ret_val)
143162306a36Sopenharmony_ci				goto out;
143262306a36Sopenharmony_ci		} else if (phy->smart_speed == e1000_smart_speed_off) {
143362306a36Sopenharmony_ci			ret_val = phy->ops.read_reg(hw,
143462306a36Sopenharmony_ci						     IGP01E1000_PHY_PORT_CONFIG,
143562306a36Sopenharmony_ci						     &data);
143662306a36Sopenharmony_ci			if (ret_val)
143762306a36Sopenharmony_ci				goto out;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
144062306a36Sopenharmony_ci			ret_val = phy->ops.write_reg(hw,
144162306a36Sopenharmony_ci						     IGP01E1000_PHY_PORT_CONFIG,
144262306a36Sopenharmony_ci						     data);
144362306a36Sopenharmony_ci			if (ret_val)
144462306a36Sopenharmony_ci				goto out;
144562306a36Sopenharmony_ci		}
144662306a36Sopenharmony_ci	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
144762306a36Sopenharmony_ci		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
144862306a36Sopenharmony_ci		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
144962306a36Sopenharmony_ci		data |= IGP02E1000_PM_D3_LPLU;
145062306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
145162306a36Sopenharmony_ci					      data);
145262306a36Sopenharmony_ci		if (ret_val)
145362306a36Sopenharmony_ci			goto out;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		/* When LPLU is enabled, we should disable SmartSpeed */
145662306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
145762306a36Sopenharmony_ci					    &data);
145862306a36Sopenharmony_ci		if (ret_val)
145962306a36Sopenharmony_ci			goto out;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
146262306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
146362306a36Sopenharmony_ci					     data);
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ciout:
146762306a36Sopenharmony_ci	return ret_val;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci/**
147162306a36Sopenharmony_ci *  igb_check_downshift - Checks whether a downshift in speed occurred
147262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
147362306a36Sopenharmony_ci *
147462306a36Sopenharmony_ci *  Success returns 0, Failure returns 1
147562306a36Sopenharmony_ci *
147662306a36Sopenharmony_ci *  A downshift is detected by querying the PHY link health.
147762306a36Sopenharmony_ci **/
147862306a36Sopenharmony_cis32 igb_check_downshift(struct e1000_hw *hw)
147962306a36Sopenharmony_ci{
148062306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
148162306a36Sopenharmony_ci	s32 ret_val;
148262306a36Sopenharmony_ci	u16 phy_data, offset, mask;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	switch (phy->type) {
148562306a36Sopenharmony_ci	case e1000_phy_i210:
148662306a36Sopenharmony_ci	case e1000_phy_m88:
148762306a36Sopenharmony_ci	case e1000_phy_gg82563:
148862306a36Sopenharmony_ci		offset	= M88E1000_PHY_SPEC_STATUS;
148962306a36Sopenharmony_ci		mask	= M88E1000_PSSR_DOWNSHIFT;
149062306a36Sopenharmony_ci		break;
149162306a36Sopenharmony_ci	case e1000_phy_igp_2:
149262306a36Sopenharmony_ci	case e1000_phy_igp:
149362306a36Sopenharmony_ci	case e1000_phy_igp_3:
149462306a36Sopenharmony_ci		offset	= IGP01E1000_PHY_LINK_HEALTH;
149562306a36Sopenharmony_ci		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
149662306a36Sopenharmony_ci		break;
149762306a36Sopenharmony_ci	default:
149862306a36Sopenharmony_ci		/* speed downshift not supported */
149962306a36Sopenharmony_ci		phy->speed_downgraded = false;
150062306a36Sopenharmony_ci		ret_val = 0;
150162306a36Sopenharmony_ci		goto out;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	if (!ret_val)
150762306a36Sopenharmony_ci		phy->speed_downgraded = (phy_data & mask) ? true : false;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ciout:
151062306a36Sopenharmony_ci	return ret_val;
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci/**
151462306a36Sopenharmony_ci *  igb_check_polarity_m88 - Checks the polarity.
151562306a36Sopenharmony_ci *  @hw: pointer to the HW structure
151662306a36Sopenharmony_ci *
151762306a36Sopenharmony_ci *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
151862306a36Sopenharmony_ci *
151962306a36Sopenharmony_ci *  Polarity is determined based on the PHY specific status register.
152062306a36Sopenharmony_ci **/
152162306a36Sopenharmony_cis32 igb_check_polarity_m88(struct e1000_hw *hw)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
152462306a36Sopenharmony_ci	s32 ret_val;
152562306a36Sopenharmony_ci	u16 data;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (!ret_val)
153062306a36Sopenharmony_ci		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
153162306a36Sopenharmony_ci				      ? e1000_rev_polarity_reversed
153262306a36Sopenharmony_ci				      : e1000_rev_polarity_normal;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	return ret_val;
153562306a36Sopenharmony_ci}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci/**
153862306a36Sopenharmony_ci *  igb_check_polarity_igp - Checks the polarity.
153962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
154062306a36Sopenharmony_ci *
154162306a36Sopenharmony_ci *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
154262306a36Sopenharmony_ci *
154362306a36Sopenharmony_ci *  Polarity is determined based on the PHY port status register, and the
154462306a36Sopenharmony_ci *  current speed (since there is no polarity at 100Mbps).
154562306a36Sopenharmony_ci **/
154662306a36Sopenharmony_cistatic s32 igb_check_polarity_igp(struct e1000_hw *hw)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
154962306a36Sopenharmony_ci	s32 ret_val;
155062306a36Sopenharmony_ci	u16 data, offset, mask;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	/* Polarity is determined based on the speed of
155362306a36Sopenharmony_ci	 * our connection.
155462306a36Sopenharmony_ci	 */
155562306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
155662306a36Sopenharmony_ci	if (ret_val)
155762306a36Sopenharmony_ci		goto out;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
156062306a36Sopenharmony_ci	    IGP01E1000_PSSR_SPEED_1000MBPS) {
156162306a36Sopenharmony_ci		offset	= IGP01E1000_PHY_PCS_INIT_REG;
156262306a36Sopenharmony_ci		mask	= IGP01E1000_PHY_POLARITY_MASK;
156362306a36Sopenharmony_ci	} else {
156462306a36Sopenharmony_ci		/* This really only applies to 10Mbps since
156562306a36Sopenharmony_ci		 * there is no polarity for 100Mbps (always 0).
156662306a36Sopenharmony_ci		 */
156762306a36Sopenharmony_ci		offset	= IGP01E1000_PHY_PORT_STATUS;
156862306a36Sopenharmony_ci		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, offset, &data);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	if (!ret_val)
157462306a36Sopenharmony_ci		phy->cable_polarity = (data & mask)
157562306a36Sopenharmony_ci				      ? e1000_rev_polarity_reversed
157662306a36Sopenharmony_ci				      : e1000_rev_polarity_normal;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ciout:
157962306a36Sopenharmony_ci	return ret_val;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci/**
158362306a36Sopenharmony_ci *  igb_wait_autoneg - Wait for auto-neg completion
158462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
158562306a36Sopenharmony_ci *
158662306a36Sopenharmony_ci *  Waits for auto-negotiation to complete or for the auto-negotiation time
158762306a36Sopenharmony_ci *  limit to expire, which ever happens first.
158862306a36Sopenharmony_ci **/
158962306a36Sopenharmony_cistatic s32 igb_wait_autoneg(struct e1000_hw *hw)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	s32 ret_val = 0;
159262306a36Sopenharmony_ci	u16 i, phy_status;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
159562306a36Sopenharmony_ci	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
159662306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
159762306a36Sopenharmony_ci		if (ret_val)
159862306a36Sopenharmony_ci			break;
159962306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
160062306a36Sopenharmony_ci		if (ret_val)
160162306a36Sopenharmony_ci			break;
160262306a36Sopenharmony_ci		if (phy_status & MII_SR_AUTONEG_COMPLETE)
160362306a36Sopenharmony_ci			break;
160462306a36Sopenharmony_ci		msleep(100);
160562306a36Sopenharmony_ci	}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
160862306a36Sopenharmony_ci	 * has completed.
160962306a36Sopenharmony_ci	 */
161062306a36Sopenharmony_ci	return ret_val;
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci/**
161462306a36Sopenharmony_ci *  igb_phy_has_link - Polls PHY for link
161562306a36Sopenharmony_ci *  @hw: pointer to the HW structure
161662306a36Sopenharmony_ci *  @iterations: number of times to poll for link
161762306a36Sopenharmony_ci *  @usec_interval: delay between polling attempts
161862306a36Sopenharmony_ci *  @success: pointer to whether polling was successful or not
161962306a36Sopenharmony_ci *
162062306a36Sopenharmony_ci *  Polls the PHY status register for link, 'iterations' number of times.
162162306a36Sopenharmony_ci **/
162262306a36Sopenharmony_cis32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
162362306a36Sopenharmony_ci		     u32 usec_interval, bool *success)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	s32 ret_val = 0;
162662306a36Sopenharmony_ci	u16 i, phy_status;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	for (i = 0; i < iterations; i++) {
162962306a36Sopenharmony_ci		/* Some PHYs require the PHY_STATUS register to be read
163062306a36Sopenharmony_ci		 * twice due to the link bit being sticky.  No harm doing
163162306a36Sopenharmony_ci		 * it across the board.
163262306a36Sopenharmony_ci		 */
163362306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
163462306a36Sopenharmony_ci		if (ret_val && usec_interval > 0) {
163562306a36Sopenharmony_ci			/* If the first read fails, another entity may have
163662306a36Sopenharmony_ci			 * ownership of the resources, wait and try again to
163762306a36Sopenharmony_ci			 * see if they have relinquished the resources yet.
163862306a36Sopenharmony_ci			 */
163962306a36Sopenharmony_ci			if (usec_interval >= 1000)
164062306a36Sopenharmony_ci				mdelay(usec_interval/1000);
164162306a36Sopenharmony_ci			else
164262306a36Sopenharmony_ci				udelay(usec_interval);
164362306a36Sopenharmony_ci		}
164462306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
164562306a36Sopenharmony_ci		if (ret_val)
164662306a36Sopenharmony_ci			break;
164762306a36Sopenharmony_ci		if (phy_status & MII_SR_LINK_STATUS)
164862306a36Sopenharmony_ci			break;
164962306a36Sopenharmony_ci		if (usec_interval >= 1000)
165062306a36Sopenharmony_ci			mdelay(usec_interval/1000);
165162306a36Sopenharmony_ci		else
165262306a36Sopenharmony_ci			udelay(usec_interval);
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	*success = (i < iterations) ? true : false;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	return ret_val;
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci/**
166162306a36Sopenharmony_ci *  igb_get_cable_length_m88 - Determine cable length for m88 PHY
166262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
166362306a36Sopenharmony_ci *
166462306a36Sopenharmony_ci *  Reads the PHY specific status register to retrieve the cable length
166562306a36Sopenharmony_ci *  information.  The cable length is determined by averaging the minimum and
166662306a36Sopenharmony_ci *  maximum values to get the "average" cable length.  The m88 PHY has four
166762306a36Sopenharmony_ci *  possible cable length values, which are:
166862306a36Sopenharmony_ci *	Register Value		Cable Length
166962306a36Sopenharmony_ci *	0			< 50 meters
167062306a36Sopenharmony_ci *	1			50 - 80 meters
167162306a36Sopenharmony_ci *	2			80 - 110 meters
167262306a36Sopenharmony_ci *	3			110 - 140 meters
167362306a36Sopenharmony_ci *	4			> 140 meters
167462306a36Sopenharmony_ci **/
167562306a36Sopenharmony_cis32 igb_get_cable_length_m88(struct e1000_hw *hw)
167662306a36Sopenharmony_ci{
167762306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
167862306a36Sopenharmony_ci	s32 ret_val;
167962306a36Sopenharmony_ci	u16 phy_data, index;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
168262306a36Sopenharmony_ci	if (ret_val)
168362306a36Sopenharmony_ci		goto out;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
168662306a36Sopenharmony_ci		M88E1000_PSSR_CABLE_LENGTH_SHIFT;
168762306a36Sopenharmony_ci	if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) {
168862306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
168962306a36Sopenharmony_ci		goto out;
169062306a36Sopenharmony_ci	}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	phy->min_cable_length = e1000_m88_cable_length_table[index];
169362306a36Sopenharmony_ci	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ciout:
169862306a36Sopenharmony_ci	return ret_val;
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_cis32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)
170262306a36Sopenharmony_ci{
170362306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
170462306a36Sopenharmony_ci	s32 ret_val;
170562306a36Sopenharmony_ci	u16 phy_data, phy_data2, index, default_page, is_cm;
170662306a36Sopenharmony_ci	int len_tot = 0;
170762306a36Sopenharmony_ci	u16 len_min;
170862306a36Sopenharmony_ci	u16 len_max;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	switch (hw->phy.id) {
171162306a36Sopenharmony_ci	case M88E1543_E_PHY_ID:
171262306a36Sopenharmony_ci	case M88E1512_E_PHY_ID:
171362306a36Sopenharmony_ci	case I347AT4_E_PHY_ID:
171462306a36Sopenharmony_ci	case I210_I_PHY_ID:
171562306a36Sopenharmony_ci		/* Remember the original page select and set it to 7 */
171662306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
171762306a36Sopenharmony_ci					    &default_page);
171862306a36Sopenharmony_ci		if (ret_val)
171962306a36Sopenharmony_ci			goto out;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07);
172262306a36Sopenharmony_ci		if (ret_val)
172362306a36Sopenharmony_ci			goto out;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci		/* Check if the unit of cable length is meters or cm */
172662306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2);
172762306a36Sopenharmony_ci		if (ret_val)
172862306a36Sopenharmony_ci			goto out;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci		is_cm = !(phy_data2 & I347AT4_PCDC_CABLE_LENGTH_UNIT);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci		/* Get cable length from Pair 0 length Regs */
173362306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL0, &phy_data);
173462306a36Sopenharmony_ci		if (ret_val)
173562306a36Sopenharmony_ci			goto out;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci		phy->pair_length[0] = phy_data / (is_cm ? 100 : 1);
173862306a36Sopenharmony_ci		len_tot = phy->pair_length[0];
173962306a36Sopenharmony_ci		len_min = phy->pair_length[0];
174062306a36Sopenharmony_ci		len_max = phy->pair_length[0];
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci		/* Get cable length from Pair 1 length Regs */
174362306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL1, &phy_data);
174462306a36Sopenharmony_ci		if (ret_val)
174562306a36Sopenharmony_ci			goto out;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci		phy->pair_length[1] = phy_data / (is_cm ? 100 : 1);
174862306a36Sopenharmony_ci		len_tot += phy->pair_length[1];
174962306a36Sopenharmony_ci		len_min = min(len_min, phy->pair_length[1]);
175062306a36Sopenharmony_ci		len_max = max(len_max, phy->pair_length[1]);
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		/* Get cable length from Pair 2 length Regs */
175362306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL2, &phy_data);
175462306a36Sopenharmony_ci		if (ret_val)
175562306a36Sopenharmony_ci			goto out;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci		phy->pair_length[2] = phy_data / (is_cm ? 100 : 1);
175862306a36Sopenharmony_ci		len_tot += phy->pair_length[2];
175962306a36Sopenharmony_ci		len_min = min(len_min, phy->pair_length[2]);
176062306a36Sopenharmony_ci		len_max = max(len_max, phy->pair_length[2]);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci		/* Get cable length from Pair 3 length Regs */
176362306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL3, &phy_data);
176462306a36Sopenharmony_ci		if (ret_val)
176562306a36Sopenharmony_ci			goto out;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci		phy->pair_length[3] = phy_data / (is_cm ? 100 : 1);
176862306a36Sopenharmony_ci		len_tot += phy->pair_length[3];
176962306a36Sopenharmony_ci		len_min = min(len_min, phy->pair_length[3]);
177062306a36Sopenharmony_ci		len_max = max(len_max, phy->pair_length[3]);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci		/* Populate the phy structure with cable length in meters */
177362306a36Sopenharmony_ci		phy->min_cable_length = len_min;
177462306a36Sopenharmony_ci		phy->max_cable_length = len_max;
177562306a36Sopenharmony_ci		phy->cable_length = len_tot / 4;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci		/* Reset the page selec to its original value */
177862306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
177962306a36Sopenharmony_ci					     default_page);
178062306a36Sopenharmony_ci		if (ret_val)
178162306a36Sopenharmony_ci			goto out;
178262306a36Sopenharmony_ci		break;
178362306a36Sopenharmony_ci	case M88E1112_E_PHY_ID:
178462306a36Sopenharmony_ci		/* Remember the original page select and set it to 5 */
178562306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
178662306a36Sopenharmony_ci					    &default_page);
178762306a36Sopenharmony_ci		if (ret_val)
178862306a36Sopenharmony_ci			goto out;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x05);
179162306a36Sopenharmony_ci		if (ret_val)
179262306a36Sopenharmony_ci			goto out;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, M88E1112_VCT_DSP_DISTANCE,
179562306a36Sopenharmony_ci					    &phy_data);
179662306a36Sopenharmony_ci		if (ret_val)
179762306a36Sopenharmony_ci			goto out;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci		index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
180062306a36Sopenharmony_ci			M88E1000_PSSR_CABLE_LENGTH_SHIFT;
180162306a36Sopenharmony_ci		if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) {
180262306a36Sopenharmony_ci			ret_val = -E1000_ERR_PHY;
180362306a36Sopenharmony_ci			goto out;
180462306a36Sopenharmony_ci		}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci		phy->min_cable_length = e1000_m88_cable_length_table[index];
180762306a36Sopenharmony_ci		phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci		phy->cable_length = (phy->min_cable_length +
181062306a36Sopenharmony_ci				     phy->max_cable_length) / 2;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci		/* Reset the page select to its original value */
181362306a36Sopenharmony_ci		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
181462306a36Sopenharmony_ci					     default_page);
181562306a36Sopenharmony_ci		if (ret_val)
181662306a36Sopenharmony_ci			goto out;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		break;
181962306a36Sopenharmony_ci	default:
182062306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
182162306a36Sopenharmony_ci		goto out;
182262306a36Sopenharmony_ci	}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ciout:
182562306a36Sopenharmony_ci	return ret_val;
182662306a36Sopenharmony_ci}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci/**
182962306a36Sopenharmony_ci *  igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY
183062306a36Sopenharmony_ci *  @hw: pointer to the HW structure
183162306a36Sopenharmony_ci *
183262306a36Sopenharmony_ci *  The automatic gain control (agc) normalizes the amplitude of the
183362306a36Sopenharmony_ci *  received signal, adjusting for the attenuation produced by the
183462306a36Sopenharmony_ci *  cable.  By reading the AGC registers, which represent the
183562306a36Sopenharmony_ci *  combination of coarse and fine gain value, the value can be put
183662306a36Sopenharmony_ci *  into a lookup table to obtain the approximate cable length
183762306a36Sopenharmony_ci *  for each channel.
183862306a36Sopenharmony_ci **/
183962306a36Sopenharmony_cis32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
184062306a36Sopenharmony_ci{
184162306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
184262306a36Sopenharmony_ci	s32 ret_val = 0;
184362306a36Sopenharmony_ci	u16 phy_data, i, agc_value = 0;
184462306a36Sopenharmony_ci	u16 cur_agc_index, max_agc_index = 0;
184562306a36Sopenharmony_ci	u16 min_agc_index = ARRAY_SIZE(e1000_igp_2_cable_length_table) - 1;
184662306a36Sopenharmony_ci	static const u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = {
184762306a36Sopenharmony_ci		IGP02E1000_PHY_AGC_A,
184862306a36Sopenharmony_ci		IGP02E1000_PHY_AGC_B,
184962306a36Sopenharmony_ci		IGP02E1000_PHY_AGC_C,
185062306a36Sopenharmony_ci		IGP02E1000_PHY_AGC_D
185162306a36Sopenharmony_ci	};
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/* Read the AGC registers for all channels */
185462306a36Sopenharmony_ci	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
185562306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
185662306a36Sopenharmony_ci		if (ret_val)
185762306a36Sopenharmony_ci			goto out;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci		/* Getting bits 15:9, which represent the combination of
186062306a36Sopenharmony_ci		 * coarse and fine gain values.  The result is a number
186162306a36Sopenharmony_ci		 * that can be put into the lookup table to obtain the
186262306a36Sopenharmony_ci		 * approximate cable length.
186362306a36Sopenharmony_ci		 */
186462306a36Sopenharmony_ci		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
186562306a36Sopenharmony_ci				IGP02E1000_AGC_LENGTH_MASK;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci		/* Array index bound check. */
186862306a36Sopenharmony_ci		if ((cur_agc_index >= ARRAY_SIZE(e1000_igp_2_cable_length_table)) ||
186962306a36Sopenharmony_ci		    (cur_agc_index == 0)) {
187062306a36Sopenharmony_ci			ret_val = -E1000_ERR_PHY;
187162306a36Sopenharmony_ci			goto out;
187262306a36Sopenharmony_ci		}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci		/* Remove min & max AGC values from calculation. */
187562306a36Sopenharmony_ci		if (e1000_igp_2_cable_length_table[min_agc_index] >
187662306a36Sopenharmony_ci		    e1000_igp_2_cable_length_table[cur_agc_index])
187762306a36Sopenharmony_ci			min_agc_index = cur_agc_index;
187862306a36Sopenharmony_ci		if (e1000_igp_2_cable_length_table[max_agc_index] <
187962306a36Sopenharmony_ci		    e1000_igp_2_cable_length_table[cur_agc_index])
188062306a36Sopenharmony_ci			max_agc_index = cur_agc_index;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
188662306a36Sopenharmony_ci		      e1000_igp_2_cable_length_table[max_agc_index]);
188762306a36Sopenharmony_ci	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	/* Calculate cable length with the error range of +/- 10 meters. */
189062306a36Sopenharmony_ci	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
189162306a36Sopenharmony_ci				 (agc_value - IGP02E1000_AGC_RANGE) : 0;
189262306a36Sopenharmony_ci	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ciout:
189762306a36Sopenharmony_ci	return ret_val;
189862306a36Sopenharmony_ci}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci/**
190162306a36Sopenharmony_ci *  igb_get_phy_info_m88 - Retrieve PHY information
190262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
190362306a36Sopenharmony_ci *
190462306a36Sopenharmony_ci *  Valid for only copper links.  Read the PHY status register (sticky read)
190562306a36Sopenharmony_ci *  to verify that link is up.  Read the PHY special control register to
190662306a36Sopenharmony_ci *  determine the polarity and 10base-T extended distance.  Read the PHY
190762306a36Sopenharmony_ci *  special status register to determine MDI/MDIx and current speed.  If
190862306a36Sopenharmony_ci *  speed is 1000, then determine cable length, local and remote receiver.
190962306a36Sopenharmony_ci **/
191062306a36Sopenharmony_cis32 igb_get_phy_info_m88(struct e1000_hw *hw)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
191362306a36Sopenharmony_ci	s32  ret_val;
191462306a36Sopenharmony_ci	u16 phy_data;
191562306a36Sopenharmony_ci	bool link;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	if (phy->media_type != e1000_media_type_copper) {
191862306a36Sopenharmony_ci		hw_dbg("Phy info is only valid for copper media\n");
191962306a36Sopenharmony_ci		ret_val = -E1000_ERR_CONFIG;
192062306a36Sopenharmony_ci		goto out;
192162306a36Sopenharmony_ci	}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	ret_val = igb_phy_has_link(hw, 1, 0, &link);
192462306a36Sopenharmony_ci	if (ret_val)
192562306a36Sopenharmony_ci		goto out;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (!link) {
192862306a36Sopenharmony_ci		hw_dbg("Phy info is only valid if link is up\n");
192962306a36Sopenharmony_ci		ret_val = -E1000_ERR_CONFIG;
193062306a36Sopenharmony_ci		goto out;
193162306a36Sopenharmony_ci	}
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
193462306a36Sopenharmony_ci	if (ret_val)
193562306a36Sopenharmony_ci		goto out;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
193862306a36Sopenharmony_ci				   ? true : false;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	ret_val = igb_check_polarity_m88(hw);
194162306a36Sopenharmony_ci	if (ret_val)
194262306a36Sopenharmony_ci		goto out;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
194562306a36Sopenharmony_ci	if (ret_val)
194662306a36Sopenharmony_ci		goto out;
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
195162306a36Sopenharmony_ci		ret_val = phy->ops.get_cable_length(hw);
195262306a36Sopenharmony_ci		if (ret_val)
195362306a36Sopenharmony_ci			goto out;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
195662306a36Sopenharmony_ci		if (ret_val)
195762306a36Sopenharmony_ci			goto out;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
196062306a36Sopenharmony_ci				? e1000_1000t_rx_status_ok
196162306a36Sopenharmony_ci				: e1000_1000t_rx_status_not_ok;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
196462306a36Sopenharmony_ci				 ? e1000_1000t_rx_status_ok
196562306a36Sopenharmony_ci				 : e1000_1000t_rx_status_not_ok;
196662306a36Sopenharmony_ci	} else {
196762306a36Sopenharmony_ci		/* Set values to "undefined" */
196862306a36Sopenharmony_ci		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
196962306a36Sopenharmony_ci		phy->local_rx = e1000_1000t_rx_status_undefined;
197062306a36Sopenharmony_ci		phy->remote_rx = e1000_1000t_rx_status_undefined;
197162306a36Sopenharmony_ci	}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ciout:
197462306a36Sopenharmony_ci	return ret_val;
197562306a36Sopenharmony_ci}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci/**
197862306a36Sopenharmony_ci *  igb_get_phy_info_igp - Retrieve igp PHY information
197962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
198062306a36Sopenharmony_ci *
198162306a36Sopenharmony_ci *  Read PHY status to determine if link is up.  If link is up, then
198262306a36Sopenharmony_ci *  set/determine 10base-T extended distance and polarity correction.  Read
198362306a36Sopenharmony_ci *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
198462306a36Sopenharmony_ci *  determine on the cable length, local and remote receiver.
198562306a36Sopenharmony_ci **/
198662306a36Sopenharmony_cis32 igb_get_phy_info_igp(struct e1000_hw *hw)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
198962306a36Sopenharmony_ci	s32 ret_val;
199062306a36Sopenharmony_ci	u16 data;
199162306a36Sopenharmony_ci	bool link;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	ret_val = igb_phy_has_link(hw, 1, 0, &link);
199462306a36Sopenharmony_ci	if (ret_val)
199562306a36Sopenharmony_ci		goto out;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	if (!link) {
199862306a36Sopenharmony_ci		hw_dbg("Phy info is only valid if link is up\n");
199962306a36Sopenharmony_ci		ret_val = -E1000_ERR_CONFIG;
200062306a36Sopenharmony_ci		goto out;
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	phy->polarity_correction = true;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	ret_val = igb_check_polarity_igp(hw);
200662306a36Sopenharmony_ci	if (ret_val)
200762306a36Sopenharmony_ci		goto out;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
201062306a36Sopenharmony_ci	if (ret_val)
201162306a36Sopenharmony_ci		goto out;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
201662306a36Sopenharmony_ci	    IGP01E1000_PSSR_SPEED_1000MBPS) {
201762306a36Sopenharmony_ci		ret_val = phy->ops.get_cable_length(hw);
201862306a36Sopenharmony_ci		if (ret_val)
201962306a36Sopenharmony_ci			goto out;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
202262306a36Sopenharmony_ci		if (ret_val)
202362306a36Sopenharmony_ci			goto out;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
202662306a36Sopenharmony_ci				? e1000_1000t_rx_status_ok
202762306a36Sopenharmony_ci				: e1000_1000t_rx_status_not_ok;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
203062306a36Sopenharmony_ci				 ? e1000_1000t_rx_status_ok
203162306a36Sopenharmony_ci				 : e1000_1000t_rx_status_not_ok;
203262306a36Sopenharmony_ci	} else {
203362306a36Sopenharmony_ci		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
203462306a36Sopenharmony_ci		phy->local_rx = e1000_1000t_rx_status_undefined;
203562306a36Sopenharmony_ci		phy->remote_rx = e1000_1000t_rx_status_undefined;
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ciout:
203962306a36Sopenharmony_ci	return ret_val;
204062306a36Sopenharmony_ci}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci/**
204362306a36Sopenharmony_ci *  igb_phy_sw_reset - PHY software reset
204462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
204562306a36Sopenharmony_ci *
204662306a36Sopenharmony_ci *  Does a software reset of the PHY by reading the PHY control register and
204762306a36Sopenharmony_ci *  setting/write the control register reset bit to the PHY.
204862306a36Sopenharmony_ci **/
204962306a36Sopenharmony_cis32 igb_phy_sw_reset(struct e1000_hw *hw)
205062306a36Sopenharmony_ci{
205162306a36Sopenharmony_ci	s32 ret_val = 0;
205262306a36Sopenharmony_ci	u16 phy_ctrl;
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	if (!(hw->phy.ops.read_reg))
205562306a36Sopenharmony_ci		goto out;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
205862306a36Sopenharmony_ci	if (ret_val)
205962306a36Sopenharmony_ci		goto out;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	phy_ctrl |= MII_CR_RESET;
206262306a36Sopenharmony_ci	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
206362306a36Sopenharmony_ci	if (ret_val)
206462306a36Sopenharmony_ci		goto out;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	udelay(1);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ciout:
206962306a36Sopenharmony_ci	return ret_val;
207062306a36Sopenharmony_ci}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci/**
207362306a36Sopenharmony_ci *  igb_phy_hw_reset - PHY hardware reset
207462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
207562306a36Sopenharmony_ci *
207662306a36Sopenharmony_ci *  Verify the reset block is not blocking us from resetting.  Acquire
207762306a36Sopenharmony_ci *  semaphore (if necessary) and read/set/write the device control reset
207862306a36Sopenharmony_ci *  bit in the PHY.  Wait the appropriate delay time for the device to
207962306a36Sopenharmony_ci *  reset and release the semaphore (if necessary).
208062306a36Sopenharmony_ci **/
208162306a36Sopenharmony_cis32 igb_phy_hw_reset(struct e1000_hw *hw)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
208462306a36Sopenharmony_ci	s32  ret_val;
208562306a36Sopenharmony_ci	u32 ctrl;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	ret_val = igb_check_reset_block(hw);
208862306a36Sopenharmony_ci	if (ret_val) {
208962306a36Sopenharmony_ci		ret_val = 0;
209062306a36Sopenharmony_ci		goto out;
209162306a36Sopenharmony_ci	}
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	ret_val = phy->ops.acquire(hw);
209462306a36Sopenharmony_ci	if (ret_val)
209562306a36Sopenharmony_ci		goto out;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	ctrl = rd32(E1000_CTRL);
209862306a36Sopenharmony_ci	wr32(E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
209962306a36Sopenharmony_ci	wrfl();
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	udelay(phy->reset_delay_us);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	wr32(E1000_CTRL, ctrl);
210462306a36Sopenharmony_ci	wrfl();
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	udelay(150);
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	phy->ops.release(hw);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	ret_val = phy->ops.get_cfg_done(hw);
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ciout:
211362306a36Sopenharmony_ci	return ret_val;
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci/**
211762306a36Sopenharmony_ci *  igb_phy_init_script_igp3 - Inits the IGP3 PHY
211862306a36Sopenharmony_ci *  @hw: pointer to the HW structure
211962306a36Sopenharmony_ci *
212062306a36Sopenharmony_ci *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
212162306a36Sopenharmony_ci **/
212262306a36Sopenharmony_cis32 igb_phy_init_script_igp3(struct e1000_hw *hw)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	hw_dbg("Running IGP 3 PHY init script\n");
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	/* PHY init IGP 3 */
212762306a36Sopenharmony_ci	/* Enable rise/fall, 10-mode work in class-A */
212862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
212962306a36Sopenharmony_ci	/* Remove all caps from Replica path filter */
213062306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
213162306a36Sopenharmony_ci	/* Bias trimming for ADC, AFE and Driver (Default) */
213262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
213362306a36Sopenharmony_ci	/* Increase Hybrid poly bias */
213462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
213562306a36Sopenharmony_ci	/* Add 4% to TX amplitude in Giga mode */
213662306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
213762306a36Sopenharmony_ci	/* Disable trimming (TTT) */
213862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
213962306a36Sopenharmony_ci	/* Poly DC correction to 94.6% + 2% for all channels */
214062306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
214162306a36Sopenharmony_ci	/* ABS DC correction to 95.9% */
214262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
214362306a36Sopenharmony_ci	/* BG temp curve trim */
214462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
214562306a36Sopenharmony_ci	/* Increasing ADC OPAMP stage 1 currents to max */
214662306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
214762306a36Sopenharmony_ci	/* Force 1000 ( required for enabling PHY regs configuration) */
214862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
214962306a36Sopenharmony_ci	/* Set upd_freq to 6 */
215062306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
215162306a36Sopenharmony_ci	/* Disable NPDFE */
215262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
215362306a36Sopenharmony_ci	/* Disable adaptive fixed FFE (Default) */
215462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
215562306a36Sopenharmony_ci	/* Enable FFE hysteresis */
215662306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
215762306a36Sopenharmony_ci	/* Fixed FFE for short cable lengths */
215862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
215962306a36Sopenharmony_ci	/* Fixed FFE for medium cable lengths */
216062306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
216162306a36Sopenharmony_ci	/* Fixed FFE for long cable lengths */
216262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
216362306a36Sopenharmony_ci	/* Enable Adaptive Clip Threshold */
216462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
216562306a36Sopenharmony_ci	/* AHT reset limit to 1 */
216662306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
216762306a36Sopenharmony_ci	/* Set AHT master delay to 127 msec */
216862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
216962306a36Sopenharmony_ci	/* Set scan bits for AHT */
217062306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
217162306a36Sopenharmony_ci	/* Set AHT Preset bits */
217262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
217362306a36Sopenharmony_ci	/* Change integ_factor of channel A to 3 */
217462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
217562306a36Sopenharmony_ci	/* Change prop_factor of channels BCD to 8 */
217662306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
217762306a36Sopenharmony_ci	/* Change cg_icount + enable integbp for channels BCD */
217862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
217962306a36Sopenharmony_ci	/* Change cg_icount + enable integbp + change prop_factor_master
218062306a36Sopenharmony_ci	 * to 8 for channel A
218162306a36Sopenharmony_ci	 */
218262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
218362306a36Sopenharmony_ci	/* Disable AHT in Slave mode on channel A */
218462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
218562306a36Sopenharmony_ci	/* Enable LPLU and disable AN to 1000 in non-D0a states,
218662306a36Sopenharmony_ci	 * Enable SPD+B2B
218762306a36Sopenharmony_ci	 */
218862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
218962306a36Sopenharmony_ci	/* Enable restart AN on an1000_dis change */
219062306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
219162306a36Sopenharmony_ci	/* Enable wh_fifo read clock in 10/100 modes */
219262306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
219362306a36Sopenharmony_ci	/* Restart AN, Speed selection is 1000 */
219462306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	return 0;
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci/**
220062306a36Sopenharmony_ci *  igb_initialize_M88E1512_phy - Initialize M88E1512 PHY
220162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
220262306a36Sopenharmony_ci *
220362306a36Sopenharmony_ci *  Initialize Marvel 1512 to work correctly with Avoton.
220462306a36Sopenharmony_ci **/
220562306a36Sopenharmony_cis32 igb_initialize_M88E1512_phy(struct e1000_hw *hw)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
220862306a36Sopenharmony_ci	s32 ret_val = 0;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	/* Switch to PHY page 0xFF. */
221162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FF);
221262306a36Sopenharmony_ci	if (ret_val)
221362306a36Sopenharmony_ci		goto out;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x214B);
221662306a36Sopenharmony_ci	if (ret_val)
221762306a36Sopenharmony_ci		goto out;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2144);
222062306a36Sopenharmony_ci	if (ret_val)
222162306a36Sopenharmony_ci		goto out;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x0C28);
222462306a36Sopenharmony_ci	if (ret_val)
222562306a36Sopenharmony_ci		goto out;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2146);
222862306a36Sopenharmony_ci	if (ret_val)
222962306a36Sopenharmony_ci		goto out;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xB233);
223262306a36Sopenharmony_ci	if (ret_val)
223362306a36Sopenharmony_ci		goto out;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x214D);
223662306a36Sopenharmony_ci	if (ret_val)
223762306a36Sopenharmony_ci		goto out;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xCC0C);
224062306a36Sopenharmony_ci	if (ret_val)
224162306a36Sopenharmony_ci		goto out;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2159);
224462306a36Sopenharmony_ci	if (ret_val)
224562306a36Sopenharmony_ci		goto out;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	/* Switch to PHY page 0xFB. */
224862306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FB);
224962306a36Sopenharmony_ci	if (ret_val)
225062306a36Sopenharmony_ci		goto out;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_3, 0x000D);
225362306a36Sopenharmony_ci	if (ret_val)
225462306a36Sopenharmony_ci		goto out;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	/* Switch to PHY page 0x12. */
225762306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x12);
225862306a36Sopenharmony_ci	if (ret_val)
225962306a36Sopenharmony_ci		goto out;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	/* Change mode to SGMII-to-Copper */
226262306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_MODE, 0x8001);
226362306a36Sopenharmony_ci	if (ret_val)
226462306a36Sopenharmony_ci		goto out;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	/* Return the PHY to page 0. */
226762306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
226862306a36Sopenharmony_ci	if (ret_val)
226962306a36Sopenharmony_ci		goto out;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	ret_val = igb_phy_sw_reset(hw);
227262306a36Sopenharmony_ci	if (ret_val) {
227362306a36Sopenharmony_ci		hw_dbg("Error committing the PHY changes\n");
227462306a36Sopenharmony_ci		return ret_val;
227562306a36Sopenharmony_ci	}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	/* msec_delay(1000); */
227862306a36Sopenharmony_ci	usleep_range(1000, 2000);
227962306a36Sopenharmony_ciout:
228062306a36Sopenharmony_ci	return ret_val;
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci/**
228462306a36Sopenharmony_ci *  igb_initialize_M88E1543_phy - Initialize M88E1512 PHY
228562306a36Sopenharmony_ci *  @hw: pointer to the HW structure
228662306a36Sopenharmony_ci *
228762306a36Sopenharmony_ci *  Initialize Marvell 1543 to work correctly with Avoton.
228862306a36Sopenharmony_ci **/
228962306a36Sopenharmony_cis32 igb_initialize_M88E1543_phy(struct e1000_hw *hw)
229062306a36Sopenharmony_ci{
229162306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
229262306a36Sopenharmony_ci	s32 ret_val = 0;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* Switch to PHY page 0xFF. */
229562306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FF);
229662306a36Sopenharmony_ci	if (ret_val)
229762306a36Sopenharmony_ci		goto out;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x214B);
230062306a36Sopenharmony_ci	if (ret_val)
230162306a36Sopenharmony_ci		goto out;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2144);
230462306a36Sopenharmony_ci	if (ret_val)
230562306a36Sopenharmony_ci		goto out;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x0C28);
230862306a36Sopenharmony_ci	if (ret_val)
230962306a36Sopenharmony_ci		goto out;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2146);
231262306a36Sopenharmony_ci	if (ret_val)
231362306a36Sopenharmony_ci		goto out;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xB233);
231662306a36Sopenharmony_ci	if (ret_val)
231762306a36Sopenharmony_ci		goto out;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x214D);
232062306a36Sopenharmony_ci	if (ret_val)
232162306a36Sopenharmony_ci		goto out;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xDC0C);
232462306a36Sopenharmony_ci	if (ret_val)
232562306a36Sopenharmony_ci		goto out;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2159);
232862306a36Sopenharmony_ci	if (ret_val)
232962306a36Sopenharmony_ci		goto out;
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	/* Switch to PHY page 0xFB. */
233262306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FB);
233362306a36Sopenharmony_ci	if (ret_val)
233462306a36Sopenharmony_ci		goto out;
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_3, 0x0C0D);
233762306a36Sopenharmony_ci	if (ret_val)
233862306a36Sopenharmony_ci		goto out;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	/* Switch to PHY page 0x12. */
234162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x12);
234262306a36Sopenharmony_ci	if (ret_val)
234362306a36Sopenharmony_ci		goto out;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	/* Change mode to SGMII-to-Copper */
234662306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_MODE, 0x8001);
234762306a36Sopenharmony_ci	if (ret_val)
234862306a36Sopenharmony_ci		goto out;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	/* Switch to PHY page 1. */
235162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x1);
235262306a36Sopenharmony_ci	if (ret_val)
235362306a36Sopenharmony_ci		goto out;
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	/* Change mode to 1000BASE-X/SGMII and autoneg enable */
235662306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_FIBER_CTRL, 0x9140);
235762306a36Sopenharmony_ci	if (ret_val)
235862306a36Sopenharmony_ci		goto out;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	/* Return the PHY to page 0. */
236162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
236262306a36Sopenharmony_ci	if (ret_val)
236362306a36Sopenharmony_ci		goto out;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	ret_val = igb_phy_sw_reset(hw);
236662306a36Sopenharmony_ci	if (ret_val) {
236762306a36Sopenharmony_ci		hw_dbg("Error committing the PHY changes\n");
236862306a36Sopenharmony_ci		return ret_val;
236962306a36Sopenharmony_ci	}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	/* msec_delay(1000); */
237262306a36Sopenharmony_ci	usleep_range(1000, 2000);
237362306a36Sopenharmony_ciout:
237462306a36Sopenharmony_ci	return ret_val;
237562306a36Sopenharmony_ci}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci/**
237862306a36Sopenharmony_ci * igb_power_up_phy_copper - Restore copper link in case of PHY power down
237962306a36Sopenharmony_ci * @hw: pointer to the HW structure
238062306a36Sopenharmony_ci *
238162306a36Sopenharmony_ci * In the case of a PHY power down to save power, or to turn off link during a
238262306a36Sopenharmony_ci * driver unload, restore the link to previous settings.
238362306a36Sopenharmony_ci **/
238462306a36Sopenharmony_civoid igb_power_up_phy_copper(struct e1000_hw *hw)
238562306a36Sopenharmony_ci{
238662306a36Sopenharmony_ci	u16 mii_reg = 0;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	/* The PHY will retain its settings across a power down/up cycle */
238962306a36Sopenharmony_ci	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
239062306a36Sopenharmony_ci	mii_reg &= ~MII_CR_POWER_DOWN;
239162306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
239262306a36Sopenharmony_ci}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci/**
239562306a36Sopenharmony_ci * igb_power_down_phy_copper - Power down copper PHY
239662306a36Sopenharmony_ci * @hw: pointer to the HW structure
239762306a36Sopenharmony_ci *
239862306a36Sopenharmony_ci * Power down PHY to save power when interface is down and wake on lan
239962306a36Sopenharmony_ci * is not enabled.
240062306a36Sopenharmony_ci **/
240162306a36Sopenharmony_civoid igb_power_down_phy_copper(struct e1000_hw *hw)
240262306a36Sopenharmony_ci{
240362306a36Sopenharmony_ci	u16 mii_reg = 0;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/* The PHY will retain its settings across a power down/up cycle */
240662306a36Sopenharmony_ci	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
240762306a36Sopenharmony_ci	mii_reg |= MII_CR_POWER_DOWN;
240862306a36Sopenharmony_ci	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
240962306a36Sopenharmony_ci	usleep_range(1000, 2000);
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci/**
241362306a36Sopenharmony_ci *  igb_check_polarity_82580 - Checks the polarity.
241462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
241562306a36Sopenharmony_ci *
241662306a36Sopenharmony_ci *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
241762306a36Sopenharmony_ci *
241862306a36Sopenharmony_ci *  Polarity is determined based on the PHY specific status register.
241962306a36Sopenharmony_ci **/
242062306a36Sopenharmony_cistatic s32 igb_check_polarity_82580(struct e1000_hw *hw)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
242362306a36Sopenharmony_ci	s32 ret_val;
242462306a36Sopenharmony_ci	u16 data;
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, I82580_PHY_STATUS_2, &data);
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	if (!ret_val)
243062306a36Sopenharmony_ci		phy->cable_polarity = (data & I82580_PHY_STATUS2_REV_POLARITY)
243162306a36Sopenharmony_ci				      ? e1000_rev_polarity_reversed
243262306a36Sopenharmony_ci				      : e1000_rev_polarity_normal;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	return ret_val;
243562306a36Sopenharmony_ci}
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci/**
243862306a36Sopenharmony_ci *  igb_phy_force_speed_duplex_82580 - Force speed/duplex for I82580 PHY
243962306a36Sopenharmony_ci *  @hw: pointer to the HW structure
244062306a36Sopenharmony_ci *
244162306a36Sopenharmony_ci *  Calls the PHY setup function to force speed and duplex.  Clears the
244262306a36Sopenharmony_ci *  auto-crossover to force MDI manually.  Waits for link and returns
244362306a36Sopenharmony_ci *  successful if link up is successful, else -E1000_ERR_PHY (-2).
244462306a36Sopenharmony_ci **/
244562306a36Sopenharmony_cis32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw)
244662306a36Sopenharmony_ci{
244762306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
244862306a36Sopenharmony_ci	s32 ret_val;
244962306a36Sopenharmony_ci	u16 phy_data;
245062306a36Sopenharmony_ci	bool link;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
245362306a36Sopenharmony_ci	if (ret_val)
245462306a36Sopenharmony_ci		goto out;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	igb_phy_force_speed_duplex_setup(hw, &phy_data);
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
245962306a36Sopenharmony_ci	if (ret_val)
246062306a36Sopenharmony_ci		goto out;
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	/* Clear Auto-Crossover to force MDI manually.  82580 requires MDI
246362306a36Sopenharmony_ci	 * forced whenever speed and duplex are forced.
246462306a36Sopenharmony_ci	 */
246562306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, I82580_PHY_CTRL_2, &phy_data);
246662306a36Sopenharmony_ci	if (ret_val)
246762306a36Sopenharmony_ci		goto out;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	phy_data &= ~I82580_PHY_CTRL2_MDIX_CFG_MASK;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	ret_val = phy->ops.write_reg(hw, I82580_PHY_CTRL_2, phy_data);
247262306a36Sopenharmony_ci	if (ret_val)
247362306a36Sopenharmony_ci		goto out;
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	hw_dbg("I82580_PHY_CTRL_2: %X\n", phy_data);
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	udelay(1);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	if (phy->autoneg_wait_to_complete) {
248062306a36Sopenharmony_ci		hw_dbg("Waiting for forced speed/duplex link on 82580 phy\n");
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
248362306a36Sopenharmony_ci		if (ret_val)
248462306a36Sopenharmony_ci			goto out;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci		if (!link)
248762306a36Sopenharmony_ci			hw_dbg("Link taking longer than expected.\n");
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci		/* Try once more */
249062306a36Sopenharmony_ci		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
249162306a36Sopenharmony_ci		if (ret_val)
249262306a36Sopenharmony_ci			goto out;
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ciout:
249662306a36Sopenharmony_ci	return ret_val;
249762306a36Sopenharmony_ci}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci/**
250062306a36Sopenharmony_ci *  igb_get_phy_info_82580 - Retrieve I82580 PHY information
250162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
250262306a36Sopenharmony_ci *
250362306a36Sopenharmony_ci *  Read PHY status to determine if link is up.  If link is up, then
250462306a36Sopenharmony_ci *  set/determine 10base-T extended distance and polarity correction.  Read
250562306a36Sopenharmony_ci *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
250662306a36Sopenharmony_ci *  determine on the cable length, local and remote receiver.
250762306a36Sopenharmony_ci **/
250862306a36Sopenharmony_cis32 igb_get_phy_info_82580(struct e1000_hw *hw)
250962306a36Sopenharmony_ci{
251062306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
251162306a36Sopenharmony_ci	s32 ret_val;
251262306a36Sopenharmony_ci	u16 data;
251362306a36Sopenharmony_ci	bool link;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	ret_val = igb_phy_has_link(hw, 1, 0, &link);
251662306a36Sopenharmony_ci	if (ret_val)
251762306a36Sopenharmony_ci		goto out;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	if (!link) {
252062306a36Sopenharmony_ci		hw_dbg("Phy info is only valid if link is up\n");
252162306a36Sopenharmony_ci		ret_val = -E1000_ERR_CONFIG;
252262306a36Sopenharmony_ci		goto out;
252362306a36Sopenharmony_ci	}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	phy->polarity_correction = true;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	ret_val = igb_check_polarity_82580(hw);
252862306a36Sopenharmony_ci	if (ret_val)
252962306a36Sopenharmony_ci		goto out;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, I82580_PHY_STATUS_2, &data);
253262306a36Sopenharmony_ci	if (ret_val)
253362306a36Sopenharmony_ci		goto out;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	phy->is_mdix = (data & I82580_PHY_STATUS2_MDIX) ? true : false;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if ((data & I82580_PHY_STATUS2_SPEED_MASK) ==
253862306a36Sopenharmony_ci	    I82580_PHY_STATUS2_SPEED_1000MBPS) {
253962306a36Sopenharmony_ci		ret_val = hw->phy.ops.get_cable_length(hw);
254062306a36Sopenharmony_ci		if (ret_val)
254162306a36Sopenharmony_ci			goto out;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
254462306a36Sopenharmony_ci		if (ret_val)
254562306a36Sopenharmony_ci			goto out;
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
254862306a36Sopenharmony_ci				? e1000_1000t_rx_status_ok
254962306a36Sopenharmony_ci				: e1000_1000t_rx_status_not_ok;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
255262306a36Sopenharmony_ci				 ? e1000_1000t_rx_status_ok
255362306a36Sopenharmony_ci				 : e1000_1000t_rx_status_not_ok;
255462306a36Sopenharmony_ci	} else {
255562306a36Sopenharmony_ci		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
255662306a36Sopenharmony_ci		phy->local_rx = e1000_1000t_rx_status_undefined;
255762306a36Sopenharmony_ci		phy->remote_rx = e1000_1000t_rx_status_undefined;
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ciout:
256162306a36Sopenharmony_ci	return ret_val;
256262306a36Sopenharmony_ci}
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci/**
256562306a36Sopenharmony_ci *  igb_get_cable_length_82580 - Determine cable length for 82580 PHY
256662306a36Sopenharmony_ci *  @hw: pointer to the HW structure
256762306a36Sopenharmony_ci *
256862306a36Sopenharmony_ci * Reads the diagnostic status register and verifies result is valid before
256962306a36Sopenharmony_ci * placing it in the phy_cable_length field.
257062306a36Sopenharmony_ci **/
257162306a36Sopenharmony_cis32 igb_get_cable_length_82580(struct e1000_hw *hw)
257262306a36Sopenharmony_ci{
257362306a36Sopenharmony_ci	struct e1000_phy_info *phy = &hw->phy;
257462306a36Sopenharmony_ci	s32 ret_val;
257562306a36Sopenharmony_ci	u16 phy_data, length;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	ret_val = phy->ops.read_reg(hw, I82580_PHY_DIAG_STATUS, &phy_data);
257862306a36Sopenharmony_ci	if (ret_val)
257962306a36Sopenharmony_ci		goto out;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	length = (phy_data & I82580_DSTATUS_CABLE_LENGTH) >>
258262306a36Sopenharmony_ci		 I82580_DSTATUS_CABLE_LENGTH_SHIFT;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	if (length == E1000_CABLE_LENGTH_UNDEFINED)
258562306a36Sopenharmony_ci		ret_val = -E1000_ERR_PHY;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	phy->cable_length = length;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ciout:
259062306a36Sopenharmony_ci	return ret_val;
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci/**
259462306a36Sopenharmony_ci *  igb_set_master_slave_mode - Setup PHY for Master/slave mode
259562306a36Sopenharmony_ci *  @hw: pointer to the HW structure
259662306a36Sopenharmony_ci *
259762306a36Sopenharmony_ci *  Sets up Master/slave mode
259862306a36Sopenharmony_ci **/
259962306a36Sopenharmony_cistatic s32 igb_set_master_slave_mode(struct e1000_hw *hw)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	s32 ret_val;
260262306a36Sopenharmony_ci	u16 phy_data;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	/* Resolve Master/Slave mode */
260562306a36Sopenharmony_ci	ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data);
260662306a36Sopenharmony_ci	if (ret_val)
260762306a36Sopenharmony_ci		return ret_val;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	/* load defaults for future use */
261062306a36Sopenharmony_ci	hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ?
261162306a36Sopenharmony_ci				   ((phy_data & CR_1000T_MS_VALUE) ?
261262306a36Sopenharmony_ci				    e1000_ms_force_master :
261362306a36Sopenharmony_ci				    e1000_ms_force_slave) : e1000_ms_auto;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	switch (hw->phy.ms_type) {
261662306a36Sopenharmony_ci	case e1000_ms_force_master:
261762306a36Sopenharmony_ci		phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
261862306a36Sopenharmony_ci		break;
261962306a36Sopenharmony_ci	case e1000_ms_force_slave:
262062306a36Sopenharmony_ci		phy_data |= CR_1000T_MS_ENABLE;
262162306a36Sopenharmony_ci		phy_data &= ~(CR_1000T_MS_VALUE);
262262306a36Sopenharmony_ci		break;
262362306a36Sopenharmony_ci	case e1000_ms_auto:
262462306a36Sopenharmony_ci		phy_data &= ~CR_1000T_MS_ENABLE;
262562306a36Sopenharmony_ci		fallthrough;
262662306a36Sopenharmony_ci	default:
262762306a36Sopenharmony_ci		break;
262862306a36Sopenharmony_ci	}
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data);
263162306a36Sopenharmony_ci}
2632