163b3bba8SJerry Jelinek /******************************************************************************
2*48ed61a7SRobert Mustacchi   SPDX-License-Identifier: BSD-3-Clause
363b3bba8SJerry Jelinek 
4*48ed61a7SRobert Mustacchi   Copyright (c) 2001-2017, Intel Corporation
563b3bba8SJerry Jelinek   All rights reserved.
6*48ed61a7SRobert Mustacchi 
7*48ed61a7SRobert Mustacchi   Redistribution and use in source and binary forms, with or without
863b3bba8SJerry Jelinek   modification, are permitted provided that the following conditions are met:
9*48ed61a7SRobert Mustacchi 
10*48ed61a7SRobert Mustacchi    1. Redistributions of source code must retain the above copyright notice,
1163b3bba8SJerry Jelinek       this list of conditions and the following disclaimer.
12*48ed61a7SRobert Mustacchi 
13*48ed61a7SRobert Mustacchi    2. Redistributions in binary form must reproduce the above copyright
14*48ed61a7SRobert Mustacchi       notice, this list of conditions and the following disclaimer in the
1563b3bba8SJerry Jelinek       documentation and/or other materials provided with the distribution.
16*48ed61a7SRobert Mustacchi 
17*48ed61a7SRobert Mustacchi    3. Neither the name of the Intel Corporation nor the names of its
18*48ed61a7SRobert Mustacchi       contributors may be used to endorse or promote products derived from
1963b3bba8SJerry Jelinek       this software without specific prior written permission.
20*48ed61a7SRobert Mustacchi 
2163b3bba8SJerry Jelinek   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22*48ed61a7SRobert Mustacchi   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*48ed61a7SRobert Mustacchi   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*48ed61a7SRobert Mustacchi   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25*48ed61a7SRobert Mustacchi   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26*48ed61a7SRobert Mustacchi   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27*48ed61a7SRobert Mustacchi   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*48ed61a7SRobert Mustacchi   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29*48ed61a7SRobert Mustacchi   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3063b3bba8SJerry Jelinek   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3163b3bba8SJerry Jelinek   POSSIBILITY OF SUCH DAMAGE.
3263b3bba8SJerry Jelinek 
3363b3bba8SJerry Jelinek ******************************************************************************/
34dc0cb1cdSDale Ghent /*$FreeBSD$*/
359da57d7bSbt 
369da57d7bSbt #include "ixgbe_api.h"
379da57d7bSbt #include "ixgbe_common.h"
389da57d7bSbt #include "ixgbe_phy.h"
3973cd555cSBin Tu - Sun Microsystems - Beijing China 
4073cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_i2c_start(struct ixgbe_hw *hw);
4173cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_i2c_stop(struct ixgbe_hw *hw);
4273cd555cSBin Tu - Sun Microsystems - Beijing China static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data);
4373cd555cSBin Tu - Sun Microsystems - Beijing China static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
4473cd555cSBin Tu - Sun Microsystems - Beijing China static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
4573cd555cSBin Tu - Sun Microsystems - Beijing China static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
4673cd555cSBin Tu - Sun Microsystems - Beijing China static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
4769b5a878SDan McDonald static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
4873cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
4973cd555cSBin Tu - Sun Microsystems - Beijing China static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
50dc0cb1cdSDale Ghent static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl);
51dc0cb1cdSDale Ghent static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
52dc0cb1cdSDale Ghent 					  u8 *sff8472_data);
53dc0cb1cdSDale Ghent 
54dc0cb1cdSDale Ghent /**
55dc0cb1cdSDale Ghent  * ixgbe_out_i2c_byte_ack - Send I2C byte with ack
56dc0cb1cdSDale Ghent  * @hw: pointer to the hardware structure
57dc0cb1cdSDale Ghent  * @byte: byte to send
58dc0cb1cdSDale Ghent  *
59dc0cb1cdSDale Ghent  * Returns an error code on error.
60dc0cb1cdSDale Ghent  */
ixgbe_out_i2c_byte_ack(struct ixgbe_hw * hw,u8 byte)61dc0cb1cdSDale Ghent static s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte)
62dc0cb1cdSDale Ghent {
63dc0cb1cdSDale Ghent 	s32 status;
64dc0cb1cdSDale Ghent 
65dc0cb1cdSDale Ghent 	status = ixgbe_clock_out_i2c_byte(hw, byte);
66dc0cb1cdSDale Ghent 	if (status)
67dc0cb1cdSDale Ghent 		return status;
68dc0cb1cdSDale Ghent 	return ixgbe_get_i2c_ack(hw);
69dc0cb1cdSDale Ghent }
70dc0cb1cdSDale Ghent 
71dc0cb1cdSDale Ghent /**
72dc0cb1cdSDale Ghent  * ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack
73dc0cb1cdSDale Ghent  * @hw: pointer to the hardware structure
74dc0cb1cdSDale Ghent  * @byte: pointer to a u8 to receive the byte
75dc0cb1cdSDale Ghent  *
76dc0cb1cdSDale Ghent  * Returns an error code on error.
77dc0cb1cdSDale Ghent  */
ixgbe_in_i2c_byte_ack(struct ixgbe_hw * hw,u8 * byte)78dc0cb1cdSDale Ghent static s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte)
79dc0cb1cdSDale Ghent {
80dc0cb1cdSDale Ghent 	s32 status;
81dc0cb1cdSDale Ghent 
82dc0cb1cdSDale Ghent 	status = ixgbe_clock_in_i2c_byte(hw, byte);
83dc0cb1cdSDale Ghent 	if (status)
84dc0cb1cdSDale Ghent 		return status;
85dc0cb1cdSDale Ghent 	/* ACK */
86dc0cb1cdSDale Ghent 	return ixgbe_clock_out_i2c_bit(hw, FALSE);
87dc0cb1cdSDale Ghent }
88dc0cb1cdSDale Ghent 
89dc0cb1cdSDale Ghent /**
90dc0cb1cdSDale Ghent  * ixgbe_ones_comp_byte_add - Perform one's complement addition
91*48ed61a7SRobert Mustacchi  * @add1: addend 1
92*48ed61a7SRobert Mustacchi  * @add2: addend 2
93dc0cb1cdSDale Ghent  *
94dc0cb1cdSDale Ghent  * Returns one's complement 8-bit sum.
95dc0cb1cdSDale Ghent  */
ixgbe_ones_comp_byte_add(u8 add1,u8 add2)96dc0cb1cdSDale Ghent static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
97dc0cb1cdSDale Ghent {
98dc0cb1cdSDale Ghent 	u16 sum = add1 + add2;
99dc0cb1cdSDale Ghent 
100dc0cb1cdSDale Ghent 	sum = (sum & 0xFF) + (sum >> 8);
101dc0cb1cdSDale Ghent 	return sum & 0xFF;
102dc0cb1cdSDale Ghent }
103dc0cb1cdSDale Ghent 
104dc0cb1cdSDale Ghent /**
105dc0cb1cdSDale Ghent  * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation
106dc0cb1cdSDale Ghent  * @hw: pointer to the hardware structure
107dc0cb1cdSDale Ghent  * @addr: I2C bus address to read from
108dc0cb1cdSDale Ghent  * @reg: I2C device register to read from
109dc0cb1cdSDale Ghent  * @val: pointer to location to receive read value
110dc0cb1cdSDale Ghent  * @lock: TRUE if to take and release semaphore
111dc0cb1cdSDale Ghent  *
112dc0cb1cdSDale Ghent  * Returns an error code on error.
113dc0cb1cdSDale Ghent  */
ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw * hw,u8 addr,u16 reg,u16 * val,bool lock)114*48ed61a7SRobert Mustacchi s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg,
115*48ed61a7SRobert Mustacchi 					u16 *val, bool lock)
116dc0cb1cdSDale Ghent {
117dc0cb1cdSDale Ghent 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
118*48ed61a7SRobert Mustacchi 	int max_retry = 3;
119dc0cb1cdSDale Ghent 	int retry = 0;
120dc0cb1cdSDale Ghent 	u8 csum_byte;
121dc0cb1cdSDale Ghent 	u8 high_bits;
122dc0cb1cdSDale Ghent 	u8 low_bits;
123dc0cb1cdSDale Ghent 	u8 reg_high;
124dc0cb1cdSDale Ghent 	u8 csum;
125dc0cb1cdSDale Ghent 
126dc0cb1cdSDale Ghent 	reg_high = ((reg >> 7) & 0xFE) | 1;	/* Indicate read combined */
127dc0cb1cdSDale Ghent 	csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
128dc0cb1cdSDale Ghent 	csum = ~csum;
129dc0cb1cdSDale Ghent 	do {
130dc0cb1cdSDale Ghent 		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
131dc0cb1cdSDale Ghent 			return IXGBE_ERR_SWFW_SYNC;
132dc0cb1cdSDale Ghent 		ixgbe_i2c_start(hw);
133dc0cb1cdSDale Ghent 		/* Device Address and write indication */
134dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, addr))
135dc0cb1cdSDale Ghent 			goto fail;
136dc0cb1cdSDale Ghent 		/* Write bits 14:8 */
137dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, reg_high))
138dc0cb1cdSDale Ghent 			goto fail;
139dc0cb1cdSDale Ghent 		/* Write bits 7:0 */
140dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
141dc0cb1cdSDale Ghent 			goto fail;
142dc0cb1cdSDale Ghent 		/* Write csum */
143dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, csum))
144dc0cb1cdSDale Ghent 			goto fail;
145dc0cb1cdSDale Ghent 		/* Re-start condition */
146dc0cb1cdSDale Ghent 		ixgbe_i2c_start(hw);
147dc0cb1cdSDale Ghent 		/* Device Address and read indication */
148dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, addr | 1))
149dc0cb1cdSDale Ghent 			goto fail;
150dc0cb1cdSDale Ghent 		/* Get upper bits */
151dc0cb1cdSDale Ghent 		if (ixgbe_in_i2c_byte_ack(hw, &high_bits))
152dc0cb1cdSDale Ghent 			goto fail;
153dc0cb1cdSDale Ghent 		/* Get low bits */
154dc0cb1cdSDale Ghent 		if (ixgbe_in_i2c_byte_ack(hw, &low_bits))
155dc0cb1cdSDale Ghent 			goto fail;
156dc0cb1cdSDale Ghent 		/* Get csum */
157dc0cb1cdSDale Ghent 		if (ixgbe_clock_in_i2c_byte(hw, &csum_byte))
158dc0cb1cdSDale Ghent 			goto fail;
159dc0cb1cdSDale Ghent 		/* NACK */
160dc0cb1cdSDale Ghent 		if (ixgbe_clock_out_i2c_bit(hw, FALSE))
161dc0cb1cdSDale Ghent 			goto fail;
162dc0cb1cdSDale Ghent 		ixgbe_i2c_stop(hw);
163dc0cb1cdSDale Ghent 		if (lock)
164dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
165dc0cb1cdSDale Ghent 		*val = (high_bits << 8) | low_bits;
166dc0cb1cdSDale Ghent 		return 0;
167dc0cb1cdSDale Ghent 
168dc0cb1cdSDale Ghent fail:
169dc0cb1cdSDale Ghent 		ixgbe_i2c_bus_clear(hw);
170dc0cb1cdSDale Ghent 		if (lock)
171dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
172dc0cb1cdSDale Ghent 		retry++;
173dc0cb1cdSDale Ghent 		if (retry < max_retry)
174dc0cb1cdSDale Ghent 			DEBUGOUT("I2C byte read combined error - Retrying.\n");
175dc0cb1cdSDale Ghent 		else
176dc0cb1cdSDale Ghent 			DEBUGOUT("I2C byte read combined error.\n");
177dc0cb1cdSDale Ghent 	} while (retry < max_retry);
178dc0cb1cdSDale Ghent 
179dc0cb1cdSDale Ghent 	return IXGBE_ERR_I2C;
180dc0cb1cdSDale Ghent }
181dc0cb1cdSDale Ghent 
182dc0cb1cdSDale Ghent /**
183dc0cb1cdSDale Ghent  * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation
184dc0cb1cdSDale Ghent  * @hw: pointer to the hardware structure
185dc0cb1cdSDale Ghent  * @addr: I2C bus address to write to
186dc0cb1cdSDale Ghent  * @reg: I2C device register to write to
187dc0cb1cdSDale Ghent  * @val: value to write
188dc0cb1cdSDale Ghent  * @lock: TRUE if to take and release semaphore
189dc0cb1cdSDale Ghent  *
190dc0cb1cdSDale Ghent  * Returns an error code on error.
191dc0cb1cdSDale Ghent  */
ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw * hw,u8 addr,u16 reg,u16 val,bool lock)192*48ed61a7SRobert Mustacchi s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg,
193*48ed61a7SRobert Mustacchi 					 u16 val, bool lock)
194dc0cb1cdSDale Ghent {
195dc0cb1cdSDale Ghent 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
196dc0cb1cdSDale Ghent 	int max_retry = 1;
197dc0cb1cdSDale Ghent 	int retry = 0;
198dc0cb1cdSDale Ghent 	u8 reg_high;
199dc0cb1cdSDale Ghent 	u8 csum;
200dc0cb1cdSDale Ghent 
201dc0cb1cdSDale Ghent 	reg_high = (reg >> 7) & 0xFE;	/* Indicate write combined */
202dc0cb1cdSDale Ghent 	csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
203dc0cb1cdSDale Ghent 	csum = ixgbe_ones_comp_byte_add(csum, val >> 8);
204dc0cb1cdSDale Ghent 	csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
205dc0cb1cdSDale Ghent 	csum = ~csum;
206dc0cb1cdSDale Ghent 	do {
207dc0cb1cdSDale Ghent 		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
208dc0cb1cdSDale Ghent 			return IXGBE_ERR_SWFW_SYNC;
209dc0cb1cdSDale Ghent 		ixgbe_i2c_start(hw);
210dc0cb1cdSDale Ghent 		/* Device Address and write indication */
211dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, addr))
212dc0cb1cdSDale Ghent 			goto fail;
213dc0cb1cdSDale Ghent 		/* Write bits 14:8 */
214dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, reg_high))
215dc0cb1cdSDale Ghent 			goto fail;
216dc0cb1cdSDale Ghent 		/* Write bits 7:0 */
217dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
218dc0cb1cdSDale Ghent 			goto fail;
219dc0cb1cdSDale Ghent 		/* Write data 15:8 */
220dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, val >> 8))
221dc0cb1cdSDale Ghent 			goto fail;
222dc0cb1cdSDale Ghent 		/* Write data 7:0 */
223dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF))
224dc0cb1cdSDale Ghent 			goto fail;
225dc0cb1cdSDale Ghent 		/* Write csum */
226dc0cb1cdSDale Ghent 		if (ixgbe_out_i2c_byte_ack(hw, csum))
227dc0cb1cdSDale Ghent 			goto fail;
228dc0cb1cdSDale Ghent 		ixgbe_i2c_stop(hw);
229dc0cb1cdSDale Ghent 		if (lock)
230dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
231dc0cb1cdSDale Ghent 		return 0;
232dc0cb1cdSDale Ghent 
233dc0cb1cdSDale Ghent fail:
234dc0cb1cdSDale Ghent 		ixgbe_i2c_bus_clear(hw);
235dc0cb1cdSDale Ghent 		if (lock)
236dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
237dc0cb1cdSDale Ghent 		retry++;
238dc0cb1cdSDale Ghent 		if (retry < max_retry)
239dc0cb1cdSDale Ghent 			DEBUGOUT("I2C byte write combined error - Retrying.\n");
240dc0cb1cdSDale Ghent 		else
241dc0cb1cdSDale Ghent 			DEBUGOUT("I2C byte write combined error.\n");
242dc0cb1cdSDale Ghent 	} while (retry < max_retry);
243dc0cb1cdSDale Ghent 
244dc0cb1cdSDale Ghent 	return IXGBE_ERR_I2C;
245dc0cb1cdSDale Ghent }
246dc0cb1cdSDale Ghent 
24763b3bba8SJerry Jelinek /**
24863b3bba8SJerry Jelinek  *  ixgbe_init_phy_ops_generic - Inits PHY function ptrs
24963b3bba8SJerry Jelinek  *  @hw: pointer to the hardware structure
2509da57d7bSbt  *
25163b3bba8SJerry Jelinek  *  Initialize the function pointers.
25263b3bba8SJerry Jelinek  **/
ixgbe_init_phy_ops_generic(struct ixgbe_hw * hw)25363b3bba8SJerry Jelinek s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
2549da57d7bSbt {
2559da57d7bSbt 	struct ixgbe_phy_info *phy = &hw->phy;
2569da57d7bSbt 
2573cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_init_phy_ops_generic");
2583cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
2599da57d7bSbt 	/* PHY */
260dc0cb1cdSDale Ghent 	phy->ops.identify = ixgbe_identify_phy_generic;
261dc0cb1cdSDale Ghent 	phy->ops.reset = ixgbe_reset_phy_generic;
262dc0cb1cdSDale Ghent 	phy->ops.read_reg = ixgbe_read_phy_reg_generic;
263dc0cb1cdSDale Ghent 	phy->ops.write_reg = ixgbe_write_phy_reg_generic;
264dc0cb1cdSDale Ghent 	phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi;
265dc0cb1cdSDale Ghent 	phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi;
266dc0cb1cdSDale Ghent 	phy->ops.setup_link = ixgbe_setup_phy_link_generic;
267dc0cb1cdSDale Ghent 	phy->ops.setup_link_speed = ixgbe_setup_phy_link_speed_generic;
26813740cb2SPaul Guo 	phy->ops.check_link = NULL;
2693cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic;
270dc0cb1cdSDale Ghent 	phy->ops.read_i2c_byte = ixgbe_read_i2c_byte_generic;
271dc0cb1cdSDale Ghent 	phy->ops.write_i2c_byte = ixgbe_write_i2c_byte_generic;
272dc0cb1cdSDale Ghent 	phy->ops.read_i2c_sff8472 = ixgbe_read_i2c_sff8472_generic;
273dc0cb1cdSDale Ghent 	phy->ops.read_i2c_eeprom = ixgbe_read_i2c_eeprom_generic;
274dc0cb1cdSDale Ghent 	phy->ops.write_i2c_eeprom = ixgbe_write_i2c_eeprom_generic;
275dc0cb1cdSDale Ghent 	phy->ops.i2c_bus_clear = ixgbe_i2c_bus_clear;
276dc0cb1cdSDale Ghent 	phy->ops.identify_sfp = ixgbe_identify_module_generic;
27713740cb2SPaul Guo 	phy->sfp_type = ixgbe_sfp_type_unknown;
278dc0cb1cdSDale Ghent 	phy->ops.read_i2c_byte_unlocked = ixgbe_read_i2c_byte_generic_unlocked;
279dc0cb1cdSDale Ghent 	phy->ops.write_i2c_byte_unlocked =
280dc0cb1cdSDale Ghent 				ixgbe_write_i2c_byte_generic_unlocked;
281dc0cb1cdSDale Ghent 	phy->ops.check_overtemp = ixgbe_tn_check_overtemp;
28263b3bba8SJerry Jelinek 	return IXGBE_SUCCESS;
2839da57d7bSbt }
2849da57d7bSbt 
285*48ed61a7SRobert Mustacchi /**
286*48ed61a7SRobert Mustacchi  * ixgbe_probe_phy - Probe a single address for a PHY
287*48ed61a7SRobert Mustacchi  * @hw: pointer to hardware structure
288*48ed61a7SRobert Mustacchi  * @phy_addr: PHY address to probe
289*48ed61a7SRobert Mustacchi  *
290*48ed61a7SRobert Mustacchi  * Returns TRUE if PHY found
291*48ed61a7SRobert Mustacchi  */
ixgbe_probe_phy(struct ixgbe_hw * hw,u16 phy_addr)292*48ed61a7SRobert Mustacchi static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr)
293*48ed61a7SRobert Mustacchi {
294*48ed61a7SRobert Mustacchi 	u16 ext_ability = 0;
295*48ed61a7SRobert Mustacchi 
296*48ed61a7SRobert Mustacchi 	if (!ixgbe_validate_phy_addr(hw, phy_addr)) {
297*48ed61a7SRobert Mustacchi 		DEBUGOUT1("Unable to validate PHY address 0x%04X\n",
298*48ed61a7SRobert Mustacchi 			phy_addr);
299*48ed61a7SRobert Mustacchi 		return FALSE;
300*48ed61a7SRobert Mustacchi 	}
301*48ed61a7SRobert Mustacchi 
302*48ed61a7SRobert Mustacchi 	if (ixgbe_get_phy_id(hw))
303*48ed61a7SRobert Mustacchi 		return FALSE;
304*48ed61a7SRobert Mustacchi 
305*48ed61a7SRobert Mustacchi 	hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
306*48ed61a7SRobert Mustacchi 
307*48ed61a7SRobert Mustacchi 	if (hw->phy.type == ixgbe_phy_unknown) {
308*48ed61a7SRobert Mustacchi 		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY,
309*48ed61a7SRobert Mustacchi 				     IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability);
310*48ed61a7SRobert Mustacchi 		if (ext_ability &
311*48ed61a7SRobert Mustacchi 		    (IXGBE_MDIO_PHY_10GBASET_ABILITY |
312*48ed61a7SRobert Mustacchi 		     IXGBE_MDIO_PHY_1000BASET_ABILITY))
313*48ed61a7SRobert Mustacchi 			hw->phy.type = ixgbe_phy_cu_unknown;
314*48ed61a7SRobert Mustacchi 		else
315*48ed61a7SRobert Mustacchi 			hw->phy.type = ixgbe_phy_generic;
316*48ed61a7SRobert Mustacchi 	}
317*48ed61a7SRobert Mustacchi 
318*48ed61a7SRobert Mustacchi 	return TRUE;
319*48ed61a7SRobert Mustacchi }
320*48ed61a7SRobert Mustacchi 
32163b3bba8SJerry Jelinek /**
32263b3bba8SJerry Jelinek  *  ixgbe_identify_phy_generic - Get physical layer module
32363b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
3249da57d7bSbt  *
32563b3bba8SJerry Jelinek  *  Determines the physical layer module found on the current adapter.
32663b3bba8SJerry Jelinek  **/
ixgbe_identify_phy_generic(struct ixgbe_hw * hw)32763b3bba8SJerry Jelinek s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
3289da57d7bSbt {
3299da57d7bSbt 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
330*48ed61a7SRobert Mustacchi 	u16 phy_addr;
3319da57d7bSbt 
3323cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_identify_phy_generic");
3333cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
334dc0cb1cdSDale Ghent 	if (!hw->phy.phy_semaphore_mask) {
335dc0cb1cdSDale Ghent 		if (hw->bus.lan_id)
336dc0cb1cdSDale Ghent 			hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM;
337dc0cb1cdSDale Ghent 		else
338dc0cb1cdSDale Ghent 			hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM;
339dc0cb1cdSDale Ghent 	}
340dc0cb1cdSDale Ghent 
341*48ed61a7SRobert Mustacchi 	if (hw->phy.type != ixgbe_phy_unknown)
342*48ed61a7SRobert Mustacchi 		return IXGBE_SUCCESS;
34373cd555cSBin Tu - Sun Microsystems - Beijing China 
344*48ed61a7SRobert Mustacchi 	if (hw->phy.nw_mng_if_sel) {
345*48ed61a7SRobert Mustacchi 		phy_addr = (hw->phy.nw_mng_if_sel &
346*48ed61a7SRobert Mustacchi 			    IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
347*48ed61a7SRobert Mustacchi 			   IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
348*48ed61a7SRobert Mustacchi 		if (ixgbe_probe_phy(hw, phy_addr))
349*48ed61a7SRobert Mustacchi 			return IXGBE_SUCCESS;
350*48ed61a7SRobert Mustacchi 		else
351*48ed61a7SRobert Mustacchi 			return IXGBE_ERR_PHY_ADDR_INVALID;
352*48ed61a7SRobert Mustacchi 	}
353dc0cb1cdSDale Ghent 
354*48ed61a7SRobert Mustacchi 	for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
355*48ed61a7SRobert Mustacchi 		if (ixgbe_probe_phy(hw, phy_addr)) {
356*48ed61a7SRobert Mustacchi 			status = IXGBE_SUCCESS;
357*48ed61a7SRobert Mustacchi 			break;
358dc0cb1cdSDale Ghent 		}
3599da57d7bSbt 	}
3609da57d7bSbt 
361*48ed61a7SRobert Mustacchi 	/* Certain media types do not have a phy so an address will not
362*48ed61a7SRobert Mustacchi 	 * be found and the code will take this path.  Caller has to
363*48ed61a7SRobert Mustacchi 	 * decide if it is an error or not.
364*48ed61a7SRobert Mustacchi 	 */
365*48ed61a7SRobert Mustacchi 	if (status != IXGBE_SUCCESS)
366*48ed61a7SRobert Mustacchi 		hw->phy.addr = 0;
367*48ed61a7SRobert Mustacchi 
36863b3bba8SJerry Jelinek 	return status;
3699da57d7bSbt }
3709da57d7bSbt 
371dc0cb1cdSDale Ghent /**
372dc0cb1cdSDale Ghent  * ixgbe_check_reset_blocked - check status of MNG FW veto bit
373dc0cb1cdSDale Ghent  * @hw: pointer to the hardware structure
374dc0cb1cdSDale Ghent  *
375dc0cb1cdSDale Ghent  * This function checks the MMNGC.MNG_VETO bit to see if there are
376dc0cb1cdSDale Ghent  * any constraints on link from manageability.  For MAC's that don't
377dc0cb1cdSDale Ghent  * have this bit just return faluse since the link can not be blocked
378dc0cb1cdSDale Ghent  * via this method.
379dc0cb1cdSDale Ghent  **/
ixgbe_check_reset_blocked(struct ixgbe_hw * hw)380dc0cb1cdSDale Ghent s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw)
381dc0cb1cdSDale Ghent {
382dc0cb1cdSDale Ghent 	u32 mmngc;
383dc0cb1cdSDale Ghent 
384dc0cb1cdSDale Ghent 	DEBUGFUNC("ixgbe_check_reset_blocked");
385dc0cb1cdSDale Ghent 
386dc0cb1cdSDale Ghent 	/* If we don't have this bit, it can't be blocking */
387dc0cb1cdSDale Ghent 	if (hw->mac.type == ixgbe_mac_82598EB)
388dc0cb1cdSDale Ghent 		return FALSE;
389dc0cb1cdSDale Ghent 
390dc0cb1cdSDale Ghent 	mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC);
391dc0cb1cdSDale Ghent 	if (mmngc & IXGBE_MMNGC_MNG_VETO) {
392dc0cb1cdSDale Ghent 		ERROR_REPORT1(IXGBE_ERROR_SOFTWARE,
393dc0cb1cdSDale Ghent 			      "MNG_VETO bit detected.\n");
394dc0cb1cdSDale Ghent 		return TRUE;
395dc0cb1cdSDale Ghent 	}
396dc0cb1cdSDale Ghent 
397dc0cb1cdSDale Ghent 	return FALSE;
398dc0cb1cdSDale Ghent }
399dc0cb1cdSDale Ghent 
40063b3bba8SJerry Jelinek /**
40163b3bba8SJerry Jelinek  *  ixgbe_validate_phy_addr - Determines phy address is valid
40263b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
403*48ed61a7SRobert Mustacchi  *  @phy_addr: PHY address
4049da57d7bSbt  *
40563b3bba8SJerry Jelinek  **/
ixgbe_validate_phy_addr(struct ixgbe_hw * hw,u32 phy_addr)40663b3bba8SJerry Jelinek bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
4079da57d7bSbt {
4089da57d7bSbt 	u16 phy_id = 0;
40963b3bba8SJerry Jelinek 	bool valid = FALSE;
4109da57d7bSbt 
4113cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_validate_phy_addr");
4123cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
4139da57d7bSbt 	hw->phy.addr = phy_addr;
4149da57d7bSbt 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
41569b5a878SDan McDonald 			     IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id);
4169da57d7bSbt 
4179da57d7bSbt 	if (phy_id != 0xFFFF && phy_id != 0x0)
41863b3bba8SJerry Jelinek 		valid = TRUE;
4199da57d7bSbt 
420*48ed61a7SRobert Mustacchi 	DEBUGOUT1("PHY ID HIGH is 0x%04X\n", phy_id);
421*48ed61a7SRobert Mustacchi 
42263b3bba8SJerry Jelinek 	return valid;
4239da57d7bSbt }
4249da57d7bSbt 
42563b3bba8SJerry Jelinek /**
42663b3bba8SJerry Jelinek  *  ixgbe_get_phy_id - Get the phy type
42763b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
4289da57d7bSbt  *
42963b3bba8SJerry Jelinek  **/
ixgbe_get_phy_id(struct ixgbe_hw * hw)43063b3bba8SJerry Jelinek s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
4319da57d7bSbt {
4329da57d7bSbt 	u32 status;
4339da57d7bSbt 	u16 phy_id_high = 0;
4349da57d7bSbt 	u16 phy_id_low = 0;
4359da57d7bSbt 
4363cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_phy_id");
4373cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
4389da57d7bSbt 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
43969b5a878SDan McDonald 				      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
44069b5a878SDan McDonald 				      &phy_id_high);
4419da57d7bSbt 
4429da57d7bSbt 	if (status == IXGBE_SUCCESS) {
4439da57d7bSbt 		hw->phy.id = (u32)(phy_id_high << 16);
4449da57d7bSbt 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW,
44569b5a878SDan McDonald 					      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
44669b5a878SDan McDonald 					      &phy_id_low);
4479da57d7bSbt 		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
4489da57d7bSbt 		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
4499da57d7bSbt 	}
450*48ed61a7SRobert Mustacchi 	DEBUGOUT2("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n",
451*48ed61a7SRobert Mustacchi 		  phy_id_high, phy_id_low);
452*48ed61a7SRobert Mustacchi 
45363b3bba8SJerry Jelinek 	return status;
4549da57d7bSbt }
4559da57d7bSbt 
45663b3bba8SJerry Jelinek /**
45763b3bba8SJerry Jelinek  *  ixgbe_get_phy_type_from_id - Get the phy type
458*48ed61a7SRobert Mustacchi  *  @phy_id: PHY ID information
4599da57d7bSbt  *
46063b3bba8SJerry Jelinek  **/
ixgbe_get_phy_type_from_id(u32 phy_id)46163b3bba8SJerry Jelinek enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
4629da57d7bSbt {
4639da57d7bSbt 	enum ixgbe_phy_type phy_type;
4649da57d7bSbt 
4653cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_phy_type_from_id");
4663cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
4679da57d7bSbt 	switch (phy_id) {
46813740cb2SPaul Guo 	case TN1010_PHY_ID:
46913740cb2SPaul Guo 		phy_type = ixgbe_phy_tn;
47013740cb2SPaul Guo 		break;
471dc0cb1cdSDale Ghent 	case X550_PHY_ID2:
472dc0cb1cdSDale Ghent 	case X550_PHY_ID3:
47369b5a878SDan McDonald 	case X540_PHY_ID:
474185c5677SPaul Guo 		phy_type = ixgbe_phy_aq;
475185c5677SPaul Guo 		break;
4769da57d7bSbt 	case QT2022_PHY_ID:
4779da57d7bSbt 		phy_type = ixgbe_phy_qt;
4789da57d7bSbt 		break;
47913740cb2SPaul Guo 	case ATH_PHY_ID:
48013740cb2SPaul Guo 		phy_type = ixgbe_phy_nl;
48113740cb2SPaul Guo 		break;
482dc0cb1cdSDale Ghent 	case X557_PHY_ID:
483*48ed61a7SRobert Mustacchi 	case X557_PHY_ID2:
484dc0cb1cdSDale Ghent 		phy_type = ixgbe_phy_x550em_ext_t;
485dc0cb1cdSDale Ghent 		break;
486*48ed61a7SRobert Mustacchi 	case IXGBE_M88E1500_E_PHY_ID:
487*48ed61a7SRobert Mustacchi 	case IXGBE_M88E1543_E_PHY_ID:
488*48ed61a7SRobert Mustacchi 		phy_type = ixgbe_phy_ext_1g_t;
489*48ed61a7SRobert Mustacchi 		break;
4909da57d7bSbt 	default:
4919da57d7bSbt 		phy_type = ixgbe_phy_unknown;
4929da57d7bSbt 		break;
4939da57d7bSbt 	}
49463b3bba8SJerry Jelinek 	return phy_type;
4959da57d7bSbt }
4969da57d7bSbt 
49763b3bba8SJerry Jelinek /**
49863b3bba8SJerry Jelinek  *  ixgbe_reset_phy_generic - Performs a PHY reset
49963b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
50063b3bba8SJerry Jelinek  **/
ixgbe_reset_phy_generic(struct ixgbe_hw * hw)50163b3bba8SJerry Jelinek s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
5029da57d7bSbt {
50373cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 i;
50473cd555cSBin Tu - Sun Microsystems - Beijing China 	u16 ctrl = 0;
50573cd555cSBin Tu - Sun Microsystems - Beijing China 	s32 status = IXGBE_SUCCESS;
50673cd555cSBin Tu - Sun Microsystems - Beijing China 
5073cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_reset_phy_generic");
5083cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
50973cd555cSBin Tu - Sun Microsystems - Beijing China 	if (hw->phy.type == ixgbe_phy_unknown)
51073cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_identify_phy_generic(hw);
51173cd555cSBin Tu - Sun Microsystems - Beijing China 
51273cd555cSBin Tu - Sun Microsystems - Beijing China 	if (status != IXGBE_SUCCESS || hw->phy.type == ixgbe_phy_none)
51373cd555cSBin Tu - Sun Microsystems - Beijing China 		goto out;
51473cd555cSBin Tu - Sun Microsystems - Beijing China 
51563b3bba8SJerry Jelinek 	/* Don't reset PHY if it's shut down due to overtemp. */
5165b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (!hw->phy.reset_if_overtemp &&
51763b3bba8SJerry Jelinek 	    (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
5185b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
5195b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
520dc0cb1cdSDale Ghent 	/* Blocked by MNG FW so bail */
521dc0cb1cdSDale Ghent 	if (ixgbe_check_reset_blocked(hw))
522dc0cb1cdSDale Ghent 		goto out;
523dc0cb1cdSDale Ghent 
5249da57d7bSbt 	/*
5259da57d7bSbt 	 * Perform soft PHY reset to the PHY_XS.
5269da57d7bSbt 	 * This will cause a soft reset to the PHY
5279da57d7bSbt 	 */
52873cd555cSBin Tu - Sun Microsystems - Beijing China 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
52969b5a878SDan McDonald 			      IXGBE_MDIO_PHY_XS_DEV_TYPE,
53069b5a878SDan McDonald 			      IXGBE_MDIO_PHY_XS_RESET);
53173cd555cSBin Tu - Sun Microsystems - Beijing China 
5325b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
5335b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Poll for reset bit to self-clear indicating reset is complete.
5345b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Some PHYs could take up to 3 seconds to complete and need about
5355b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * 1.7 usec delay after the reset is complete.
5365b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
5375b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < 30; i++) {
5385b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		msec_delay(100);
539*48ed61a7SRobert Mustacchi 		if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
540*48ed61a7SRobert Mustacchi 			status = hw->phy.ops.read_reg(hw,
541*48ed61a7SRobert Mustacchi 						  IXGBE_MDIO_TX_VENDOR_ALARMS_3,
542*48ed61a7SRobert Mustacchi 						  IXGBE_MDIO_PMA_PMD_DEV_TYPE,
543*48ed61a7SRobert Mustacchi 						  &ctrl);
544*48ed61a7SRobert Mustacchi 			if (status != IXGBE_SUCCESS)
545*48ed61a7SRobert Mustacchi 				return status;
546*48ed61a7SRobert Mustacchi 
547*48ed61a7SRobert Mustacchi 			if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
548*48ed61a7SRobert Mustacchi 				usec_delay(2);
549*48ed61a7SRobert Mustacchi 				break;
550*48ed61a7SRobert Mustacchi 			}
551*48ed61a7SRobert Mustacchi 		} else {
552*48ed61a7SRobert Mustacchi 			status = hw->phy.ops.read_reg(hw,
553*48ed61a7SRobert Mustacchi 						     IXGBE_MDIO_PHY_XS_CONTROL,
554*48ed61a7SRobert Mustacchi 						     IXGBE_MDIO_PHY_XS_DEV_TYPE,
555*48ed61a7SRobert Mustacchi 						     &ctrl);
556*48ed61a7SRobert Mustacchi 			if (status != IXGBE_SUCCESS)
557*48ed61a7SRobert Mustacchi 				return status;
558*48ed61a7SRobert Mustacchi 
559*48ed61a7SRobert Mustacchi 			if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) {
560*48ed61a7SRobert Mustacchi 				usec_delay(2);
561*48ed61a7SRobert Mustacchi 				break;
562*48ed61a7SRobert Mustacchi 			}
5635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
56473cd555cSBin Tu - Sun Microsystems - Beijing China 	}
56573cd555cSBin Tu - Sun Microsystems - Beijing China 
56673cd555cSBin Tu - Sun Microsystems - Beijing China 	if (ctrl & IXGBE_MDIO_PHY_XS_RESET) {
56773cd555cSBin Tu - Sun Microsystems - Beijing China 		status = IXGBE_ERR_RESET_FAILED;
568dc0cb1cdSDale Ghent 		ERROR_REPORT1(IXGBE_ERROR_POLLING,
569dc0cb1cdSDale Ghent 			     "PHY reset polling failed to complete.\n");
57073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
57173cd555cSBin Tu - Sun Microsystems - Beijing China 
57273cd555cSBin Tu - Sun Microsystems - Beijing China out:
57363b3bba8SJerry Jelinek 	return status;
5749da57d7bSbt }
5759da57d7bSbt 
57663b3bba8SJerry Jelinek /**
577dc0cb1cdSDale Ghent  *  ixgbe_read_phy_mdi - Reads a value from a specified PHY register without
578dc0cb1cdSDale Ghent  *  the SWFW lock
57963b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
58063b3bba8SJerry Jelinek  *  @reg_addr: 32 bit address of PHY register to read
581*48ed61a7SRobert Mustacchi  *  @device_type: 5 bit device type
58263b3bba8SJerry Jelinek  *  @phy_data: Pointer to read data from PHY register
58363b3bba8SJerry Jelinek  **/
ixgbe_read_phy_reg_mdi(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)584dc0cb1cdSDale Ghent s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
585*48ed61a7SRobert Mustacchi 			   u16 *phy_data)
5869da57d7bSbt {
587dc0cb1cdSDale Ghent 	u32 i, data, command;
5889da57d7bSbt 
589dc0cb1cdSDale Ghent 	/* Setup and write the address cycle command */
590dc0cb1cdSDale Ghent 	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
591dc0cb1cdSDale Ghent 		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
592dc0cb1cdSDale Ghent 		   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
593dc0cb1cdSDale Ghent 		   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
5943cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
595dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
5969da57d7bSbt 
597dc0cb1cdSDale Ghent 	/*
598dc0cb1cdSDale Ghent 	 * Check every 10 usec to see if the address cycle completed.
599dc0cb1cdSDale Ghent 	 * The MDI Command bit will clear when the operation is
600dc0cb1cdSDale Ghent 	 * complete
601dc0cb1cdSDale Ghent 	 */
602dc0cb1cdSDale Ghent 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
603dc0cb1cdSDale Ghent 		usec_delay(10);
6049da57d7bSbt 
605dc0cb1cdSDale Ghent 		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
606dc0cb1cdSDale Ghent 		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
607*48ed61a7SRobert Mustacchi 			break;
608dc0cb1cdSDale Ghent 	}
6099da57d7bSbt 
6109da57d7bSbt 
611dc0cb1cdSDale Ghent 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
612dc0cb1cdSDale Ghent 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address command did not complete.\n");
613*48ed61a7SRobert Mustacchi 		DEBUGOUT("PHY address command did not complete, returning IXGBE_ERR_PHY\n");
614dc0cb1cdSDale Ghent 		return IXGBE_ERR_PHY;
615dc0cb1cdSDale Ghent 	}
6169da57d7bSbt 
617dc0cb1cdSDale Ghent 	/*
618dc0cb1cdSDale Ghent 	 * Address cycle complete, setup and write the read
619dc0cb1cdSDale Ghent 	 * command
620dc0cb1cdSDale Ghent 	 */
621dc0cb1cdSDale Ghent 	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
622dc0cb1cdSDale Ghent 		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
623dc0cb1cdSDale Ghent 		   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
624dc0cb1cdSDale Ghent 		   (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
6259da57d7bSbt 
626dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
6279da57d7bSbt 
628dc0cb1cdSDale Ghent 	/*
629dc0cb1cdSDale Ghent 	 * Check every 10 usec to see if the address cycle
630dc0cb1cdSDale Ghent 	 * completed. The MDI Command bit will clear when the
631dc0cb1cdSDale Ghent 	 * operation is complete
632dc0cb1cdSDale Ghent 	 */
633dc0cb1cdSDale Ghent 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
634dc0cb1cdSDale Ghent 		usec_delay(10);
6359da57d7bSbt 
636dc0cb1cdSDale Ghent 		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
637dc0cb1cdSDale Ghent 		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
638dc0cb1cdSDale Ghent 			break;
639dc0cb1cdSDale Ghent 	}
6409da57d7bSbt 
641dc0cb1cdSDale Ghent 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
642dc0cb1cdSDale Ghent 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n");
643*48ed61a7SRobert Mustacchi 		DEBUGOUT("PHY read command didn't complete, returning IXGBE_ERR_PHY\n");
644dc0cb1cdSDale Ghent 		return IXGBE_ERR_PHY;
645dc0cb1cdSDale Ghent 	}
6469da57d7bSbt 
647dc0cb1cdSDale Ghent 	/*
648dc0cb1cdSDale Ghent 	 * Read operation is complete.  Get the data
649dc0cb1cdSDale Ghent 	 * from MSRWD
650dc0cb1cdSDale Ghent 	 */
651dc0cb1cdSDale Ghent 	data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
652dc0cb1cdSDale Ghent 	data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
653dc0cb1cdSDale Ghent 	*phy_data = (u16)(data);
654dc0cb1cdSDale Ghent 
655dc0cb1cdSDale Ghent 	return IXGBE_SUCCESS;
656dc0cb1cdSDale Ghent }
657dc0cb1cdSDale Ghent 
658dc0cb1cdSDale Ghent /**
659dc0cb1cdSDale Ghent  *  ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
660dc0cb1cdSDale Ghent  *  using the SWFW lock - this function is needed in most cases
661dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
662dc0cb1cdSDale Ghent  *  @reg_addr: 32 bit address of PHY register to read
663*48ed61a7SRobert Mustacchi  *  @device_type: 5 bit device type
664dc0cb1cdSDale Ghent  *  @phy_data: Pointer to read data from PHY register
665dc0cb1cdSDale Ghent  **/
ixgbe_read_phy_reg_generic(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)666dc0cb1cdSDale Ghent s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
667dc0cb1cdSDale Ghent 			       u32 device_type, u16 *phy_data)
668dc0cb1cdSDale Ghent {
669dc0cb1cdSDale Ghent 	s32 status;
670dc0cb1cdSDale Ghent 	u32 gssr = hw->phy.phy_semaphore_mask;
671dc0cb1cdSDale Ghent 
672dc0cb1cdSDale Ghent 	DEBUGFUNC("ixgbe_read_phy_reg_generic");
673dc0cb1cdSDale Ghent 
674*48ed61a7SRobert Mustacchi 	if (hw->mac.ops.acquire_swfw_sync(hw, gssr))
675*48ed61a7SRobert Mustacchi 		return IXGBE_ERR_SWFW_SYNC;
676*48ed61a7SRobert Mustacchi 
677*48ed61a7SRobert Mustacchi 	status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data);
678*48ed61a7SRobert Mustacchi 
679*48ed61a7SRobert Mustacchi 	hw->mac.ops.release_swfw_sync(hw, gssr);
6809da57d7bSbt 
68163b3bba8SJerry Jelinek 	return status;
6829da57d7bSbt }
6839da57d7bSbt 
68463b3bba8SJerry Jelinek /**
685dc0cb1cdSDale Ghent  *  ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register
686dc0cb1cdSDale Ghent  *  without SWFW lock
68763b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
68863b3bba8SJerry Jelinek  *  @reg_addr: 32 bit PHY register to write
68963b3bba8SJerry Jelinek  *  @device_type: 5 bit device type
69063b3bba8SJerry Jelinek  *  @phy_data: Data to write to the PHY register
69163b3bba8SJerry Jelinek  **/
ixgbe_write_phy_reg_mdi(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)692dc0cb1cdSDale Ghent s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
69369b5a878SDan McDonald 				u32 device_type, u16 phy_data)
6949da57d7bSbt {
695dc0cb1cdSDale Ghent 	u32 i, command;
6969da57d7bSbt 
697dc0cb1cdSDale Ghent 	/* Put the data in the MDI single read and write data register*/
698dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
6993cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
700dc0cb1cdSDale Ghent 	/* Setup and write the address cycle command */
701dc0cb1cdSDale Ghent 	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
702dc0cb1cdSDale Ghent 		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
703dc0cb1cdSDale Ghent 		   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
704dc0cb1cdSDale Ghent 		   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
7059da57d7bSbt 
706dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
7079da57d7bSbt 
708dc0cb1cdSDale Ghent 	/*
709dc0cb1cdSDale Ghent 	 * Check every 10 usec to see if the address cycle completed.
710dc0cb1cdSDale Ghent 	 * The MDI Command bit will clear when the operation is
711dc0cb1cdSDale Ghent 	 * complete
712dc0cb1cdSDale Ghent 	 */
713dc0cb1cdSDale Ghent 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
714dc0cb1cdSDale Ghent 		usec_delay(10);
7159da57d7bSbt 
716dc0cb1cdSDale Ghent 		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
717dc0cb1cdSDale Ghent 		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
718dc0cb1cdSDale Ghent 			break;
719dc0cb1cdSDale Ghent 	}
7209da57d7bSbt 
721dc0cb1cdSDale Ghent 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
722dc0cb1cdSDale Ghent 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address cmd didn't complete\n");
723dc0cb1cdSDale Ghent 		return IXGBE_ERR_PHY;
724dc0cb1cdSDale Ghent 	}
7259da57d7bSbt 
726dc0cb1cdSDale Ghent 	/*
727dc0cb1cdSDale Ghent 	 * Address cycle complete, setup and write the write
728dc0cb1cdSDale Ghent 	 * command
729dc0cb1cdSDale Ghent 	 */
730dc0cb1cdSDale Ghent 	command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
731dc0cb1cdSDale Ghent 		   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
732dc0cb1cdSDale Ghent 		   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
733dc0cb1cdSDale Ghent 		   (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
7349da57d7bSbt 
735dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
7369da57d7bSbt 
737dc0cb1cdSDale Ghent 	/*
738dc0cb1cdSDale Ghent 	 * Check every 10 usec to see if the address cycle
739dc0cb1cdSDale Ghent 	 * completed. The MDI Command bit will clear when the
740dc0cb1cdSDale Ghent 	 * operation is complete
741dc0cb1cdSDale Ghent 	 */
742dc0cb1cdSDale Ghent 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
743dc0cb1cdSDale Ghent 		usec_delay(10);
7449da57d7bSbt 
745dc0cb1cdSDale Ghent 		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
746dc0cb1cdSDale Ghent 		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
747dc0cb1cdSDale Ghent 			break;
748dc0cb1cdSDale Ghent 	}
7499da57d7bSbt 
750dc0cb1cdSDale Ghent 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
751dc0cb1cdSDale Ghent 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY write cmd didn't complete\n");
752dc0cb1cdSDale Ghent 		return IXGBE_ERR_PHY;
753dc0cb1cdSDale Ghent 	}
7549da57d7bSbt 
755dc0cb1cdSDale Ghent 	return IXGBE_SUCCESS;
756dc0cb1cdSDale Ghent }
757dc0cb1cdSDale Ghent 
758dc0cb1cdSDale Ghent /**
759dc0cb1cdSDale Ghent  *  ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
760dc0cb1cdSDale Ghent  *  using SWFW lock- this function is needed in most cases
761dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
762dc0cb1cdSDale Ghent  *  @reg_addr: 32 bit PHY register to write
763dc0cb1cdSDale Ghent  *  @device_type: 5 bit device type
764dc0cb1cdSDale Ghent  *  @phy_data: Data to write to the PHY register
765dc0cb1cdSDale Ghent  **/
ixgbe_write_phy_reg_generic(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)766dc0cb1cdSDale Ghent s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
767dc0cb1cdSDale Ghent 				u32 device_type, u16 phy_data)
768dc0cb1cdSDale Ghent {
769dc0cb1cdSDale Ghent 	s32 status;
770dc0cb1cdSDale Ghent 	u32 gssr = hw->phy.phy_semaphore_mask;
771dc0cb1cdSDale Ghent 
772dc0cb1cdSDale Ghent 	DEBUGFUNC("ixgbe_write_phy_reg_generic");
7739da57d7bSbt 
774dc0cb1cdSDale Ghent 	if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) {
775*48ed61a7SRobert Mustacchi 		status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type,
776dc0cb1cdSDale Ghent 						 phy_data);
77769b5a878SDan McDonald 		hw->mac.ops.release_swfw_sync(hw, gssr);
778dc0cb1cdSDale Ghent 	} else {
779dc0cb1cdSDale Ghent 		status = IXGBE_ERR_SWFW_SYNC;
7809da57d7bSbt 	}
7819da57d7bSbt 
78263b3bba8SJerry Jelinek 	return status;
7839da57d7bSbt }
7849da57d7bSbt 
78563b3bba8SJerry Jelinek /**
786dc0cb1cdSDale Ghent  *  ixgbe_setup_phy_link_generic - Set and restart auto-neg
78763b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
7889da57d7bSbt  *
789dc0cb1cdSDale Ghent  *  Restart auto-negotiation and PHY and waits for completion.
79063b3bba8SJerry Jelinek  **/
ixgbe_setup_phy_link_generic(struct ixgbe_hw * hw)79163b3bba8SJerry Jelinek s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
7929da57d7bSbt {
793dc0cb1cdSDale Ghent 	s32 status = IXGBE_SUCCESS;
7949da57d7bSbt 	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
79563b3bba8SJerry Jelinek 	bool autoneg = FALSE;
7963cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	ixgbe_link_speed speed;
7979da57d7bSbt 
7983cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_setup_phy_link_generic");
7999da57d7bSbt 
800dc0cb1cdSDale Ghent 	ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
8019da57d7bSbt 
802*48ed61a7SRobert Mustacchi 	/* Set or unset auto-negotiation 10G advertisement */
803*48ed61a7SRobert Mustacchi 	hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
804*48ed61a7SRobert Mustacchi 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
805*48ed61a7SRobert Mustacchi 			     &autoneg_reg);
8063cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
807*48ed61a7SRobert Mustacchi 	autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
808*48ed61a7SRobert Mustacchi 	if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) &&
809*48ed61a7SRobert Mustacchi 	    (speed & IXGBE_LINK_SPEED_10GB_FULL))
810*48ed61a7SRobert Mustacchi 		autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
8113cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
812*48ed61a7SRobert Mustacchi 	hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
813*48ed61a7SRobert Mustacchi 			      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
814*48ed61a7SRobert Mustacchi 			      autoneg_reg);
8153cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
816*48ed61a7SRobert Mustacchi 	hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
817*48ed61a7SRobert Mustacchi 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
818*48ed61a7SRobert Mustacchi 			     &autoneg_reg);
819dc0cb1cdSDale Ghent 
820*48ed61a7SRobert Mustacchi 	if (hw->mac.type == ixgbe_mac_X550) {
821*48ed61a7SRobert Mustacchi 		/* Set or unset auto-negotiation 5G advertisement */
822*48ed61a7SRobert Mustacchi 		autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE;
823*48ed61a7SRobert Mustacchi 		if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) &&
824*48ed61a7SRobert Mustacchi 		    (speed & IXGBE_LINK_SPEED_5GB_FULL))
825*48ed61a7SRobert Mustacchi 			autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE;
826*48ed61a7SRobert Mustacchi 
827*48ed61a7SRobert Mustacchi 		/* Set or unset auto-negotiation 2.5G advertisement */
828*48ed61a7SRobert Mustacchi 		autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE;
829*48ed61a7SRobert Mustacchi 		if ((hw->phy.autoneg_advertised &
830*48ed61a7SRobert Mustacchi 		     IXGBE_LINK_SPEED_2_5GB_FULL) &&
831*48ed61a7SRobert Mustacchi 		    (speed & IXGBE_LINK_SPEED_2_5GB_FULL))
832*48ed61a7SRobert Mustacchi 			autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE;
833dc0cb1cdSDale Ghent 	}
834dc0cb1cdSDale Ghent 
835*48ed61a7SRobert Mustacchi 	/* Set or unset auto-negotiation 1G advertisement */
836*48ed61a7SRobert Mustacchi 	autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE;
837*48ed61a7SRobert Mustacchi 	if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) &&
838*48ed61a7SRobert Mustacchi 	    (speed & IXGBE_LINK_SPEED_1GB_FULL))
839*48ed61a7SRobert Mustacchi 		autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE;
8403cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
841*48ed61a7SRobert Mustacchi 	hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
842*48ed61a7SRobert Mustacchi 			      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
843*48ed61a7SRobert Mustacchi 			      autoneg_reg);
8443cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
845*48ed61a7SRobert Mustacchi 	/* Set or unset auto-negotiation 100M advertisement */
846*48ed61a7SRobert Mustacchi 	hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
847*48ed61a7SRobert Mustacchi 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
848*48ed61a7SRobert Mustacchi 			     &autoneg_reg);
8493cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
850*48ed61a7SRobert Mustacchi 	autoneg_reg &= ~(IXGBE_MII_100BASE_T_ADVERTISE |
851*48ed61a7SRobert Mustacchi 			 IXGBE_MII_100BASE_T_ADVERTISE_HALF);
852*48ed61a7SRobert Mustacchi 	if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) &&
853*48ed61a7SRobert Mustacchi 	    (speed & IXGBE_LINK_SPEED_100_FULL))
854*48ed61a7SRobert Mustacchi 		autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
8553cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
856*48ed61a7SRobert Mustacchi 	hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
857*48ed61a7SRobert Mustacchi 			      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
858*48ed61a7SRobert Mustacchi 			      autoneg_reg);
8599da57d7bSbt 
860dc0cb1cdSDale Ghent 	/* Blocked by MNG FW so don't reset PHY */
861dc0cb1cdSDale Ghent 	if (ixgbe_check_reset_blocked(hw))
862dc0cb1cdSDale Ghent 		return status;
863dc0cb1cdSDale Ghent 
864dc0cb1cdSDale Ghent 	/* Restart PHY auto-negotiation. */
8659da57d7bSbt 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
86669b5a878SDan McDonald 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
8679da57d7bSbt 
8689da57d7bSbt 	autoneg_reg |= IXGBE_MII_RESTART;
8699da57d7bSbt 
8709da57d7bSbt 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
87169b5a878SDan McDonald 			      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
8729da57d7bSbt 
87363b3bba8SJerry Jelinek 	return status;
8749da57d7bSbt }
8759da57d7bSbt 
87663b3bba8SJerry Jelinek /**
87763b3bba8SJerry Jelinek  *  ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
87863b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
87963b3bba8SJerry Jelinek  *  @speed: new link speed
880*48ed61a7SRobert Mustacchi  *  @autoneg_wait_to_complete: unused
88163b3bba8SJerry Jelinek  **/
ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw * hw,ixgbe_link_speed speed,bool autoneg_wait_to_complete)88263b3bba8SJerry Jelinek s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
88369b5a878SDan McDonald 				       ixgbe_link_speed speed,
88469b5a878SDan McDonald 				       bool autoneg_wait_to_complete)
8859da57d7bSbt {
886dc0cb1cdSDale Ghent 	UNREFERENCED_1PARAMETER(autoneg_wait_to_complete);
8879da57d7bSbt 
8883cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_setup_phy_link_speed_generic");
8893cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
8909da57d7bSbt 	/*
8919da57d7bSbt 	 * Clear autoneg_advertised and set new values based on input link
8929da57d7bSbt 	 * speed.
8939da57d7bSbt 	 */
8949da57d7bSbt 	hw->phy.autoneg_advertised = 0;
8959da57d7bSbt 
89663b3bba8SJerry Jelinek 	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
8979da57d7bSbt 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
898185c5677SPaul Guo 
899dc0cb1cdSDale Ghent 	if (speed & IXGBE_LINK_SPEED_5GB_FULL)
900dc0cb1cdSDale Ghent 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL;
901dc0cb1cdSDale Ghent 
902dc0cb1cdSDale Ghent 	if (speed & IXGBE_LINK_SPEED_2_5GB_FULL)
903dc0cb1cdSDale Ghent 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
904dc0cb1cdSDale Ghent 
90563b3bba8SJerry Jelinek 	if (speed & IXGBE_LINK_SPEED_1GB_FULL)
9069da57d7bSbt 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
9079da57d7bSbt 
908185c5677SPaul Guo 	if (speed & IXGBE_LINK_SPEED_100_FULL)
909185c5677SPaul Guo 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
910185c5677SPaul Guo 
911*48ed61a7SRobert Mustacchi 	if (speed & IXGBE_LINK_SPEED_10_FULL)
912*48ed61a7SRobert Mustacchi 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL;
913*48ed61a7SRobert Mustacchi 
9149da57d7bSbt 	/* Setup link based on the new speed settings */
915dc0cb1cdSDale Ghent 	ixgbe_setup_phy_link(hw);
9169da57d7bSbt 
91763b3bba8SJerry Jelinek 	return IXGBE_SUCCESS;
9189da57d7bSbt }
91913740cb2SPaul Guo 
920dc0cb1cdSDale Ghent /**
921dc0cb1cdSDale Ghent  * ixgbe_get_copper_speeds_supported - Get copper link speeds from phy
922dc0cb1cdSDale Ghent  * @hw: pointer to hardware structure
923dc0cb1cdSDale Ghent  *
924dc0cb1cdSDale Ghent  * Determines the supported link capabilities by reading the PHY auto
925dc0cb1cdSDale Ghent  * negotiation register.
926dc0cb1cdSDale Ghent  **/
ixgbe_get_copper_speeds_supported(struct ixgbe_hw * hw)927dc0cb1cdSDale Ghent static s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw)
928dc0cb1cdSDale Ghent {
929dc0cb1cdSDale Ghent 	s32 status;
930dc0cb1cdSDale Ghent 	u16 speed_ability;
931dc0cb1cdSDale Ghent 
932dc0cb1cdSDale Ghent 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
933dc0cb1cdSDale Ghent 				      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
934dc0cb1cdSDale Ghent 				      &speed_ability);
935dc0cb1cdSDale Ghent 	if (status)
936dc0cb1cdSDale Ghent 		return status;
937dc0cb1cdSDale Ghent 
938dc0cb1cdSDale Ghent 	if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
939dc0cb1cdSDale Ghent 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
940dc0cb1cdSDale Ghent 	if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
941dc0cb1cdSDale Ghent 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
942dc0cb1cdSDale Ghent 	if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M)
943dc0cb1cdSDale Ghent 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
944dc0cb1cdSDale Ghent 
945dc0cb1cdSDale Ghent 	switch (hw->mac.type) {
946dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
947dc0cb1cdSDale Ghent 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
948dc0cb1cdSDale Ghent 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
949dc0cb1cdSDale Ghent 		break;
950dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
951*48ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
952dc0cb1cdSDale Ghent 		hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL;
953dc0cb1cdSDale Ghent 		break;
954dc0cb1cdSDale Ghent 	default:
955dc0cb1cdSDale Ghent 		break;
956dc0cb1cdSDale Ghent 	}
957dc0cb1cdSDale Ghent 
958dc0cb1cdSDale Ghent 	return status;
959dc0cb1cdSDale Ghent }
960dc0cb1cdSDale Ghent 
96163b3bba8SJerry Jelinek /**
96263b3bba8SJerry Jelinek  *  ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
96363b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
96463b3bba8SJerry Jelinek  *  @speed: pointer to link speed
96563b3bba8SJerry Jelinek  *  @autoneg: boolean auto-negotiation value
96663b3bba8SJerry Jelinek  **/
ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw * hw,ixgbe_link_speed * speed,bool * autoneg)96763b3bba8SJerry Jelinek s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
96869b5a878SDan McDonald 					       ixgbe_link_speed *speed,
96969b5a878SDan McDonald 					       bool *autoneg)
97073cd555cSBin Tu - Sun Microsystems - Beijing China {
971dc0cb1cdSDale Ghent 	s32 status = IXGBE_SUCCESS;
97273cd555cSBin Tu - Sun Microsystems - Beijing China 
9733cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic");
9743cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
97563b3bba8SJerry Jelinek 	*autoneg = TRUE;
976dc0cb1cdSDale Ghent 	if (!hw->phy.speeds_supported)
977dc0cb1cdSDale Ghent 		status = ixgbe_get_copper_speeds_supported(hw);
97873cd555cSBin Tu - Sun Microsystems - Beijing China 
979dc0cb1cdSDale Ghent 	*speed = hw->phy.speeds_supported;
98063b3bba8SJerry Jelinek 	return status;
98173cd555cSBin Tu - Sun Microsystems - Beijing China }
98273cd555cSBin Tu - Sun Microsystems - Beijing China 
98363b3bba8SJerry Jelinek /**
98463b3bba8SJerry Jelinek  *  ixgbe_check_phy_link_tnx - Determine link and speed status
98563b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
986*48ed61a7SRobert Mustacchi  *  @speed: current link speed
987*48ed61a7SRobert Mustacchi  *  @link_up: TRUE is link is up, FALSE otherwise
98813740cb2SPaul Guo  *
98963b3bba8SJerry Jelinek  *  Reads the VS1 register to determine if link is up and the current speed for
99063b3bba8SJerry Jelinek  *  the PHY.
99163b3bba8SJerry Jelinek  **/
ixgbe_check_phy_link_tnx(struct ixgbe_hw * hw,ixgbe_link_speed * speed,bool * link_up)99263b3bba8SJerry Jelinek s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
99369b5a878SDan McDonald 			     bool *link_up)
99413740cb2SPaul Guo {
99513740cb2SPaul Guo 	s32 status = IXGBE_SUCCESS;
99613740cb2SPaul Guo 	u32 time_out;
99713740cb2SPaul Guo 	u32 max_time_out = 10;
99813740cb2SPaul Guo 	u16 phy_link = 0;
99913740cb2SPaul Guo 	u16 phy_speed = 0;
100013740cb2SPaul Guo 	u16 phy_data = 0;
100113740cb2SPaul Guo 
10023cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_check_phy_link_tnx");
10033cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
100413740cb2SPaul Guo 	/* Initialize speed and link to default case */
100563b3bba8SJerry Jelinek 	*link_up = FALSE;
100613740cb2SPaul Guo 	*speed = IXGBE_LINK_SPEED_10GB_FULL;
100713740cb2SPaul Guo 
100813740cb2SPaul Guo 	/*
100913740cb2SPaul Guo 	 * Check current speed and link status of the PHY register.
101013740cb2SPaul Guo 	 * This is a vendor specific register and may have to
101113740cb2SPaul Guo 	 * be changed for other copper PHYs.
101213740cb2SPaul Guo 	 */
101313740cb2SPaul Guo 	for (time_out = 0; time_out < max_time_out; time_out++) {
101413740cb2SPaul Guo 		usec_delay(10);
101513740cb2SPaul Guo 		status = hw->phy.ops.read_reg(hw,
101669b5a878SDan McDonald 					IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
101769b5a878SDan McDonald 					IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
101869b5a878SDan McDonald 					&phy_data);
101969b5a878SDan McDonald 		phy_link = phy_data & IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
102013740cb2SPaul Guo 		phy_speed = phy_data &
102169b5a878SDan McDonald 				 IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
102213740cb2SPaul Guo 		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
102363b3bba8SJerry Jelinek 			*link_up = TRUE;
102413740cb2SPaul Guo 			if (phy_speed ==
102513740cb2SPaul Guo 			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
102613740cb2SPaul Guo 				*speed = IXGBE_LINK_SPEED_1GB_FULL;
102713740cb2SPaul Guo 			break;
102813740cb2SPaul Guo 		}
102913740cb2SPaul Guo 	}
103013740cb2SPaul Guo 
103163b3bba8SJerry Jelinek 	return status;
103213740cb2SPaul Guo }
103313740cb2SPaul Guo 
103463b3bba8SJerry Jelinek /**
1035dc0cb1cdSDale Ghent  *	ixgbe_setup_phy_link_tnx - Set and restart auto-neg
103663b3bba8SJerry Jelinek  *	@hw: pointer to hardware structure
10373cfa0eb9Schenlu chen - Sun Microsystems - Beijing China  *
1038dc0cb1cdSDale Ghent  *	Restart auto-negotiation and PHY and waits for completion.
103963b3bba8SJerry Jelinek  **/
ixgbe_setup_phy_link_tnx(struct ixgbe_hw * hw)104063b3bba8SJerry Jelinek s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
10413cfa0eb9Schenlu chen - Sun Microsystems - Beijing China {
1042dc0cb1cdSDale Ghent 	s32 status = IXGBE_SUCCESS;
10433cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
104463b3bba8SJerry Jelinek 	bool autoneg = FALSE;
10453cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	ixgbe_link_speed speed;
10463cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10473cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_setup_phy_link_tnx");
10483cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
1049dc0cb1cdSDale Ghent 	ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
10503cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10513cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
10523cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		/* Set or unset auto-negotiation 10G advertisement */
10533cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
105469b5a878SDan McDonald 				     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
105569b5a878SDan McDonald 				     &autoneg_reg);
10563cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10573cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
10583cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
10593cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 			autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
10603cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10613cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
106269b5a878SDan McDonald 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
106369b5a878SDan McDonald 				      autoneg_reg);
10643cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	}
10653cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10663cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
10673cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		/* Set or unset auto-negotiation 1G advertisement */
10683cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
106969b5a878SDan McDonald 				     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
107069b5a878SDan McDonald 				     &autoneg_reg);
10713cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10723cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
10733cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
10743cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 			autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
10753cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10763cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
107769b5a878SDan McDonald 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
107869b5a878SDan McDonald 				      autoneg_reg);
10793cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	}
10803cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10813cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	if (speed & IXGBE_LINK_SPEED_100_FULL) {
10823cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		/* Set or unset auto-negotiation 100M advertisement */
10833cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
108469b5a878SDan McDonald 				     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
108569b5a878SDan McDonald 				     &autoneg_reg);
10863cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10873cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		autoneg_reg &= ~IXGBE_MII_100BASE_T_ADVERTISE;
10883cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
10893cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 			autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
10903cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
10913cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
109269b5a878SDan McDonald 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
109369b5a878SDan McDonald 				      autoneg_reg);
10943cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	}
10953cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
1096dc0cb1cdSDale Ghent 	/* Blocked by MNG FW so don't reset PHY */
1097dc0cb1cdSDale Ghent 	if (ixgbe_check_reset_blocked(hw))
1098dc0cb1cdSDale Ghent 		return status;
1099dc0cb1cdSDale Ghent 
1100dc0cb1cdSDale Ghent 	/* Restart PHY auto-negotiation. */
11013cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
110269b5a878SDan McDonald 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
11033cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
11043cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	autoneg_reg |= IXGBE_MII_RESTART;
11053cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
11063cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
110769b5a878SDan McDonald 			      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
11083cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
110963b3bba8SJerry Jelinek 	return status;
11103cfa0eb9Schenlu chen - Sun Microsystems - Beijing China }
11113cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
111263b3bba8SJerry Jelinek /**
111363b3bba8SJerry Jelinek  *  ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version
111463b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
111563b3bba8SJerry Jelinek  *  @firmware_version: pointer to the PHY Firmware Version
111663b3bba8SJerry Jelinek  **/
ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw * hw,u16 * firmware_version)111763b3bba8SJerry Jelinek s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
111869b5a878SDan McDonald 				       u16 *firmware_version)
111913740cb2SPaul Guo {
1120dc0cb1cdSDale Ghent 	s32 status;
112113740cb2SPaul Guo 
11223cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_phy_firmware_version_tnx");
11233cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
112413740cb2SPaul Guo 	status = hw->phy.ops.read_reg(hw, TNX_FW_REV,
112569b5a878SDan McDonald 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
112669b5a878SDan McDonald 				      firmware_version);
112713740cb2SPaul Guo 
112863b3bba8SJerry Jelinek 	return status;
112913740cb2SPaul Guo }
113013740cb2SPaul Guo 
113163b3bba8SJerry Jelinek /**
113263b3bba8SJerry Jelinek  *  ixgbe_get_phy_firmware_version_generic - Gets the PHY Firmware Version
113363b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
113463b3bba8SJerry Jelinek  *  @firmware_version: pointer to the PHY Firmware Version
113563b3bba8SJerry Jelinek  **/
ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw * hw,u16 * firmware_version)113663b3bba8SJerry Jelinek s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
113769b5a878SDan McDonald 					   u16 *firmware_version)
1138185c5677SPaul Guo {
1139dc0cb1cdSDale Ghent 	s32 status;
1140185c5677SPaul Guo 
11413cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_phy_firmware_version_generic");
11423cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
1143185c5677SPaul Guo 	status = hw->phy.ops.read_reg(hw, AQ_FW_REV,
114469b5a878SDan McDonald 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
114569b5a878SDan McDonald 				      firmware_version);
1146185c5677SPaul Guo 
114763b3bba8SJerry Jelinek 	return status;
1148185c5677SPaul Guo }
1149185c5677SPaul Guo 
115063b3bba8SJerry Jelinek /**
115163b3bba8SJerry Jelinek  *  ixgbe_reset_phy_nl - Performs a PHY reset
115263b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
115363b3bba8SJerry Jelinek  **/
ixgbe_reset_phy_nl(struct ixgbe_hw * hw)115463b3bba8SJerry Jelinek s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
115513740cb2SPaul Guo {
115613740cb2SPaul Guo 	u16 phy_offset, control, eword, edata, block_crc;
115763b3bba8SJerry Jelinek 	bool end_data = FALSE;
115813740cb2SPaul Guo 	u16 list_offset, data_offset;
115913740cb2SPaul Guo 	u16 phy_data = 0;
116013740cb2SPaul Guo 	s32 ret_val = IXGBE_SUCCESS;
116113740cb2SPaul Guo 	u32 i;
116213740cb2SPaul Guo 
11633cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_reset_phy_nl");
11643cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
1165dc0cb1cdSDale Ghent 	/* Blocked by MNG FW so bail */
1166dc0cb1cdSDale Ghent 	if (ixgbe_check_reset_blocked(hw))
1167dc0cb1cdSDale Ghent 		goto out;
1168dc0cb1cdSDale Ghent 
116913740cb2SPaul Guo 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
117069b5a878SDan McDonald 			     IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
117113740cb2SPaul Guo 
117213740cb2SPaul Guo 	/* reset the PHY and poll for completion */
117313740cb2SPaul Guo 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
117469b5a878SDan McDonald 			      IXGBE_MDIO_PHY_XS_DEV_TYPE,
117569b5a878SDan McDonald 			      (phy_data | IXGBE_MDIO_PHY_XS_RESET));
117613740cb2SPaul Guo 
117713740cb2SPaul Guo 	for (i = 0; i < 100; i++) {
117813740cb2SPaul Guo 		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
117969b5a878SDan McDonald 				     IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
118013740cb2SPaul Guo 		if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0)
118113740cb2SPaul Guo 			break;
118213740cb2SPaul Guo 		msec_delay(10);
118313740cb2SPaul Guo 	}
118413740cb2SPaul Guo 
118513740cb2SPaul Guo 	if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) {
118613740cb2SPaul Guo 		DEBUGOUT("PHY reset did not complete.\n");
118713740cb2SPaul Guo 		ret_val = IXGBE_ERR_PHY;
118813740cb2SPaul Guo 		goto out;
118913740cb2SPaul Guo 	}
119013740cb2SPaul Guo 
119113740cb2SPaul Guo 	/* Get init offsets */
119213740cb2SPaul Guo 	ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
119369b5a878SDan McDonald 						      &data_offset);
119413740cb2SPaul Guo 	if (ret_val != IXGBE_SUCCESS)
119513740cb2SPaul Guo 		goto out;
119613740cb2SPaul Guo 
119713740cb2SPaul Guo 	ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
119813740cb2SPaul Guo 	data_offset++;
119913740cb2SPaul Guo 	while (!end_data) {
120013740cb2SPaul Guo 		/*
120113740cb2SPaul Guo 		 * Read control word from PHY init contents offset
120213740cb2SPaul Guo 		 */
120313740cb2SPaul Guo 		ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
1204dc0cb1cdSDale Ghent 		if (ret_val)
1205dc0cb1cdSDale Ghent 			goto err_eeprom;
120613740cb2SPaul Guo 		control = (eword & IXGBE_CONTROL_MASK_NL) >>
120769b5a878SDan McDonald 			   IXGBE_CONTROL_SHIFT_NL;
120813740cb2SPaul Guo 		edata = eword & IXGBE_DATA_MASK_NL;
120913740cb2SPaul Guo 		switch (control) {
121013740cb2SPaul Guo 		case IXGBE_DELAY_NL:
121113740cb2SPaul Guo 			data_offset++;
121213740cb2SPaul Guo 			DEBUGOUT1("DELAY: %d MS\n", edata);
121313740cb2SPaul Guo 			msec_delay(edata);
121413740cb2SPaul Guo 			break;
121513740cb2SPaul Guo 		case IXGBE_DATA_NL:
121669b5a878SDan McDonald 			DEBUGOUT("DATA:\n");
121713740cb2SPaul Guo 			data_offset++;
1218dc0cb1cdSDale Ghent 			ret_val = hw->eeprom.ops.read(hw, data_offset,
1219dc0cb1cdSDale Ghent 						      &phy_offset);
1220dc0cb1cdSDale Ghent 			if (ret_val)
1221dc0cb1cdSDale Ghent 				goto err_eeprom;
1222dc0cb1cdSDale Ghent 			data_offset++;
122313740cb2SPaul Guo 			for (i = 0; i < edata; i++) {
1224dc0cb1cdSDale Ghent 				ret_val = hw->eeprom.ops.read(hw, data_offset,
1225dc0cb1cdSDale Ghent 							      &eword);
1226dc0cb1cdSDale Ghent 				if (ret_val)
1227dc0cb1cdSDale Ghent 					goto err_eeprom;
122813740cb2SPaul Guo 				hw->phy.ops.write_reg(hw, phy_offset,
122969b5a878SDan McDonald 						      IXGBE_TWINAX_DEV, eword);
123013740cb2SPaul Guo 				DEBUGOUT2("Wrote %4.4x to %4.4x\n", eword,
123169b5a878SDan McDonald 					  phy_offset);
123213740cb2SPaul Guo 				data_offset++;
123313740cb2SPaul Guo 				phy_offset++;
123413740cb2SPaul Guo 			}
123513740cb2SPaul Guo 			break;
123613740cb2SPaul Guo 		case IXGBE_CONTROL_NL:
123713740cb2SPaul Guo 			data_offset++;
123869b5a878SDan McDonald 			DEBUGOUT("CONTROL:\n");
123913740cb2SPaul Guo 			if (edata == IXGBE_CONTROL_EOL_NL) {
124013740cb2SPaul Guo 				DEBUGOUT("EOL\n");
124163b3bba8SJerry Jelinek 				end_data = TRUE;
124213740cb2SPaul Guo 			} else if (edata == IXGBE_CONTROL_SOL_NL) {
124313740cb2SPaul Guo 				DEBUGOUT("SOL\n");
124413740cb2SPaul Guo 			} else {
124513740cb2SPaul Guo 				DEBUGOUT("Bad control value\n");
124613740cb2SPaul Guo 				ret_val = IXGBE_ERR_PHY;
124713740cb2SPaul Guo 				goto out;
124813740cb2SPaul Guo 			}
124913740cb2SPaul Guo 			break;
125013740cb2SPaul Guo 		default:
125113740cb2SPaul Guo 			DEBUGOUT("Bad control type\n");
125213740cb2SPaul Guo 			ret_val = IXGBE_ERR_PHY;
125313740cb2SPaul Guo 			goto out;
125413740cb2SPaul Guo 		}
125513740cb2SPaul Guo 	}
125613740cb2SPaul Guo 
125713740cb2SPaul Guo out:
125863b3bba8SJerry Jelinek 	return ret_val;
1259dc0cb1cdSDale Ghent 
1260dc0cb1cdSDale Ghent err_eeprom:
1261dc0cb1cdSDale Ghent 	ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
1262dc0cb1cdSDale Ghent 		      "eeprom read at offset %d failed", data_offset);
1263dc0cb1cdSDale Ghent 	return IXGBE_ERR_PHY;
126413740cb2SPaul Guo }
126513740cb2SPaul Guo 
126669b5a878SDan McDonald /**
126769b5a878SDan McDonald  *  ixgbe_identify_module_generic - Identifies module type
126869b5a878SDan McDonald  *  @hw: pointer to hardware structure
126969b5a878SDan McDonald  *
127069b5a878SDan McDonald  *  Determines HW type and calls appropriate function.
127169b5a878SDan McDonald  **/
ixgbe_identify_module_generic(struct ixgbe_hw * hw)127269b5a878SDan McDonald s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw)
127369b5a878SDan McDonald {
127469b5a878SDan McDonald 	s32 status = IXGBE_ERR_SFP_NOT_PRESENT;
127569b5a878SDan McDonald 
127669b5a878SDan McDonald 	DEBUGFUNC("ixgbe_identify_module_generic");
127769b5a878SDan McDonald 
127869b5a878SDan McDonald 	switch (hw->mac.ops.get_media_type(hw)) {
127969b5a878SDan McDonald 	case ixgbe_media_type_fiber:
128069b5a878SDan McDonald 		status = ixgbe_identify_sfp_module_generic(hw);
128169b5a878SDan McDonald 		break;
128269b5a878SDan McDonald 
1283dc0cb1cdSDale Ghent 	case ixgbe_media_type_fiber_qsfp:
1284dc0cb1cdSDale Ghent 		status = ixgbe_identify_qsfp_module_generic(hw);
1285dc0cb1cdSDale Ghent 		break;
128669b5a878SDan McDonald 
128769b5a878SDan McDonald 	default:
128869b5a878SDan McDonald 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
128969b5a878SDan McDonald 		status = IXGBE_ERR_SFP_NOT_PRESENT;
129069b5a878SDan McDonald 		break;
129169b5a878SDan McDonald 	}
129269b5a878SDan McDonald 
129369b5a878SDan McDonald 	return status;
129469b5a878SDan McDonald }
129569b5a878SDan McDonald 
129663b3bba8SJerry Jelinek /**
129763b3bba8SJerry Jelinek  *  ixgbe_identify_sfp_module_generic - Identifies SFP modules
129863b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
129913740cb2SPaul Guo  *
130063b3bba8SJerry Jelinek  *  Searches for and identifies the SFP module and assigns appropriate PHY type.
130163b3bba8SJerry Jelinek  **/
ixgbe_identify_sfp_module_generic(struct ixgbe_hw * hw)130263b3bba8SJerry Jelinek s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
130313740cb2SPaul Guo {
130413740cb2SPaul Guo 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
130513740cb2SPaul Guo 	u32 vendor_oui = 0;
130673cd555cSBin Tu - Sun Microsystems - Beijing China 	enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
130713740cb2SPaul Guo 	u8 identifier = 0;
130813740cb2SPaul Guo 	u8 comp_codes_1g = 0;
130913740cb2SPaul Guo 	u8 comp_codes_10g = 0;
131073cd555cSBin Tu - Sun Microsystems - Beijing China 	u8 oui_bytes[3] = {0, 0, 0};
1311185c5677SPaul Guo 	u8 cable_tech = 0;
13125b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	u8 cable_spec = 0;
131373cd555cSBin Tu - Sun Microsystems - Beijing China 	u16 enforce_sfp = 0;
131413740cb2SPaul Guo 
13153cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_identify_sfp_module_generic");
13163cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
1317185c5677SPaul Guo 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
1318185c5677SPaul Guo 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
1319185c5677SPaul Guo 		status = IXGBE_ERR_SFP_NOT_PRESENT;
1320185c5677SPaul Guo 		goto out;
1321185c5677SPaul Guo 	}
1322185c5677SPaul Guo 
1323dc0cb1cdSDale Ghent 	/* LAN ID is needed for I2C access */
1324dc0cb1cdSDale Ghent 	hw->mac.ops.set_lan_id(hw);
1325dc0cb1cdSDale Ghent 
132613740cb2SPaul Guo 	status = hw->phy.ops.read_i2c_eeprom(hw,
132769b5a878SDan McDonald 					     IXGBE_SFF_IDENTIFIER,
132869b5a878SDan McDonald 					     &identifier);
132913740cb2SPaul Guo 
1330dc0cb1cdSDale Ghent 	if (status != IXGBE_SUCCESS)
133163b3bba8SJerry Jelinek 		goto err_read_i2c_eeprom;
133213740cb2SPaul Guo 
1333185c5677SPaul Guo 	if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
1334185c5677SPaul Guo 		hw->phy.type = ixgbe_phy_sfp_unsupported;
1335185c5677SPaul Guo 		status = IXGBE_ERR_SFP_NOT_SUPPORTED;
1336185c5677SPaul Guo 	} else {
133763b3bba8SJerry Jelinek 		status = hw->phy.ops.read_i2c_eeprom(hw,
133869b5a878SDan McDonald 						     IXGBE_SFF_1GBE_COMP_CODES,
133969b5a878SDan McDonald 						     &comp_codes_1g);
134063b3bba8SJerry Jelinek 
1341dc0cb1cdSDale Ghent 		if (status != IXGBE_SUCCESS)
134263b3bba8SJerry Jelinek 			goto err_read_i2c_eeprom;
134363b3bba8SJerry Jelinek 
134463b3bba8SJerry Jelinek 		status = hw->phy.ops.read_i2c_eeprom(hw,
134569b5a878SDan McDonald 						     IXGBE_SFF_10GBE_COMP_CODES,
134669b5a878SDan McDonald 						     &comp_codes_10g);
134763b3bba8SJerry Jelinek 
1348dc0cb1cdSDale Ghent 		if (status != IXGBE_SUCCESS)
134963b3bba8SJerry Jelinek 			goto err_read_i2c_eeprom;
135063b3bba8SJerry Jelinek 		status = hw->phy.ops.read_i2c_eeprom(hw,
135169b5a878SDan McDonald 						     IXGBE_SFF_CABLE_TECHNOLOGY,
135269b5a878SDan McDonald 						     &cable_tech);
135363b3bba8SJerry Jelinek 
1354dc0cb1cdSDale Ghent 		if (status != IXGBE_SUCCESS)
135563b3bba8SJerry Jelinek 			goto err_read_i2c_eeprom;
135663b3bba8SJerry Jelinek 
135763b3bba8SJerry Jelinek 		 /* ID Module
135863b3bba8SJerry Jelinek 		  * =========
135963b3bba8SJerry Jelinek 		  * 0   SFP_DA_CU
136063b3bba8SJerry Jelinek 		  * 1   SFP_SR
136163b3bba8SJerry Jelinek 		  * 2   SFP_LR
136263b3bba8SJerry Jelinek 		  * 3   SFP_DA_CORE0 - 82599-specific
136363b3bba8SJerry Jelinek 		  * 4   SFP_DA_CORE1 - 82599-specific
136463b3bba8SJerry Jelinek 		  * 5   SFP_SR/LR_CORE0 - 82599-specific
136563b3bba8SJerry Jelinek 		  * 6   SFP_SR/LR_CORE1 - 82599-specific
136663b3bba8SJerry Jelinek 		  * 7   SFP_act_lmt_DA_CORE0 - 82599-specific
136763b3bba8SJerry Jelinek 		  * 8   SFP_act_lmt_DA_CORE1 - 82599-specific
136863b3bba8SJerry Jelinek 		  * 9   SFP_1g_cu_CORE0 - 82599-specific
136963b3bba8SJerry Jelinek 		  * 10  SFP_1g_cu_CORE1 - 82599-specific
137069b5a878SDan McDonald 		  * 11  SFP_1g_sx_CORE0 - 82599-specific
137169b5a878SDan McDonald 		  * 12  SFP_1g_sx_CORE1 - 82599-specific
137263b3bba8SJerry Jelinek 		  */
137373cd555cSBin Tu - Sun Microsystems - Beijing China 		if (hw->mac.type == ixgbe_mac_82598EB) {
1374185c5677SPaul Guo 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
137573cd555cSBin Tu - Sun Microsystems - Beijing China 				hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
137673cd555cSBin Tu - Sun Microsystems - Beijing China 			else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
137773cd555cSBin Tu - Sun Microsystems - Beijing China 				hw->phy.sfp_type = ixgbe_sfp_type_sr;
137873cd555cSBin Tu - Sun Microsystems - Beijing China 			else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
137973cd555cSBin Tu - Sun Microsystems - Beijing China 				hw->phy.sfp_type = ixgbe_sfp_type_lr;
138073cd555cSBin Tu - Sun Microsystems - Beijing China 			else
138173cd555cSBin Tu - Sun Microsystems - Beijing China 				hw->phy.sfp_type = ixgbe_sfp_type_unknown;
1382dc0cb1cdSDale Ghent 		} else {
13835b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) {
138473cd555cSBin Tu - Sun Microsystems - Beijing China 				if (hw->bus.lan_id == 0)
138573cd555cSBin Tu - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
138669b5a878SDan McDonald 						     ixgbe_sfp_type_da_cu_core0;
138773cd555cSBin Tu - Sun Microsystems - Beijing China 				else
138873cd555cSBin Tu - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
138969b5a878SDan McDonald 						     ixgbe_sfp_type_da_cu_core1;
13905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			} else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) {
13915b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				hw->phy.ops.read_i2c_eeprom(
139263b3bba8SJerry Jelinek 						hw, IXGBE_SFF_CABLE_SPEC_COMP,
139363b3bba8SJerry Jelinek 						&cable_spec);
13945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				if (cable_spec &
13955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				    IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
13965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 					if (hw->bus.lan_id == 0)
139763b3bba8SJerry Jelinek 						hw->phy.sfp_type =
139863b3bba8SJerry Jelinek 						ixgbe_sfp_type_da_act_lmt_core0;
13995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 					else
140063b3bba8SJerry Jelinek 						hw->phy.sfp_type =
140163b3bba8SJerry Jelinek 						ixgbe_sfp_type_da_act_lmt_core1;
140263b3bba8SJerry Jelinek 				} else {
14035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
140469b5a878SDan McDonald 							ixgbe_sfp_type_unknown;
140563b3bba8SJerry Jelinek 				}
14065b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			} else if (comp_codes_10g &
140763b3bba8SJerry Jelinek 				   (IXGBE_SFF_10GBASESR_CAPABLE |
140863b3bba8SJerry Jelinek 				    IXGBE_SFF_10GBASELR_CAPABLE)) {
140973cd555cSBin Tu - Sun Microsystems - Beijing China 				if (hw->bus.lan_id == 0)
141073cd555cSBin Tu - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
141169b5a878SDan McDonald 						      ixgbe_sfp_type_srlr_core0;
141273cd555cSBin Tu - Sun Microsystems - Beijing China 				else
141373cd555cSBin Tu - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
141469b5a878SDan McDonald 						      ixgbe_sfp_type_srlr_core1;
14155b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			} else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) {
141673cd555cSBin Tu - Sun Microsystems - Beijing China 				if (hw->bus.lan_id == 0)
141773cd555cSBin Tu - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
141863b3bba8SJerry Jelinek 						ixgbe_sfp_type_1g_cu_core0;
141973cd555cSBin Tu - Sun Microsystems - Beijing China 				else
142073cd555cSBin Tu - Sun Microsystems - Beijing China 					hw->phy.sfp_type =
142163b3bba8SJerry Jelinek 						ixgbe_sfp_type_1g_cu_core1;
142269b5a878SDan McDonald 			} else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) {
142369b5a878SDan McDonald 				if (hw->bus.lan_id == 0)
142469b5a878SDan McDonald 					hw->phy.sfp_type =
142569b5a878SDan McDonald 						ixgbe_sfp_type_1g_sx_core0;
142669b5a878SDan McDonald 				else
142769b5a878SDan McDonald 					hw->phy.sfp_type =
142869b5a878SDan McDonald 						ixgbe_sfp_type_1g_sx_core1;
1429eb341807SSaso Kiselkov 			} else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) {
1430eb341807SSaso Kiselkov 				if (hw->bus.lan_id == 0)
1431eb341807SSaso Kiselkov 					hw->phy.sfp_type =
1432eb341807SSaso Kiselkov 						ixgbe_sfp_type_1g_lx_core0;
1433eb341807SSaso Kiselkov 				else
1434eb341807SSaso Kiselkov 					hw->phy.sfp_type =
1435eb341807SSaso Kiselkov 						ixgbe_sfp_type_1g_lx_core1;
14365b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			} else {
143773cd555cSBin Tu - Sun Microsystems - Beijing China 				hw->phy.sfp_type = ixgbe_sfp_type_unknown;
14385b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			}
143973cd555cSBin Tu - Sun Microsystems - Beijing China 		}
144073cd555cSBin Tu - Sun Microsystems - Beijing China 
144173cd555cSBin Tu - Sun Microsystems - Beijing China 		if (hw->phy.sfp_type != stored_sfp_type)
144263b3bba8SJerry Jelinek 			hw->phy.sfp_setup_needed = TRUE;
144373cd555cSBin Tu - Sun Microsystems - Beijing China 
1444dc0cb1cdSDale Ghent 		/* Determine if the SFP+ PHY is dual speed or not. */
1445dc0cb1cdSDale Ghent 		hw->phy.multispeed_fiber = FALSE;
1446dc0cb1cdSDale Ghent 		if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
1447dc0cb1cdSDale Ghent 		   (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
1448dc0cb1cdSDale Ghent 		   ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
1449dc0cb1cdSDale Ghent 		   (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
1450dc0cb1cdSDale Ghent 			hw->phy.multispeed_fiber = TRUE;
1451dc0cb1cdSDale Ghent 
1452dc0cb1cdSDale Ghent 		/* Determine PHY vendor */
1453dc0cb1cdSDale Ghent 		if (hw->phy.type != ixgbe_phy_nl) {
1454dc0cb1cdSDale Ghent 			hw->phy.id = identifier;
1455dc0cb1cdSDale Ghent 			status = hw->phy.ops.read_i2c_eeprom(hw,
1456dc0cb1cdSDale Ghent 						    IXGBE_SFF_VENDOR_OUI_BYTE0,
1457dc0cb1cdSDale Ghent 						    &oui_bytes[0]);
1458dc0cb1cdSDale Ghent 
1459dc0cb1cdSDale Ghent 			if (status != IXGBE_SUCCESS)
1460dc0cb1cdSDale Ghent 				goto err_read_i2c_eeprom;
1461dc0cb1cdSDale Ghent 
1462dc0cb1cdSDale Ghent 			status = hw->phy.ops.read_i2c_eeprom(hw,
1463dc0cb1cdSDale Ghent 						    IXGBE_SFF_VENDOR_OUI_BYTE1,
1464dc0cb1cdSDale Ghent 						    &oui_bytes[1]);
1465dc0cb1cdSDale Ghent 
1466dc0cb1cdSDale Ghent 			if (status != IXGBE_SUCCESS)
1467dc0cb1cdSDale Ghent 				goto err_read_i2c_eeprom;
1468dc0cb1cdSDale Ghent 
1469dc0cb1cdSDale Ghent 			status = hw->phy.ops.read_i2c_eeprom(hw,
1470dc0cb1cdSDale Ghent 						    IXGBE_SFF_VENDOR_OUI_BYTE2,
1471dc0cb1cdSDale Ghent 						    &oui_bytes[2]);
1472dc0cb1cdSDale Ghent 
1473dc0cb1cdSDale Ghent 			if (status != IXGBE_SUCCESS)
1474dc0cb1cdSDale Ghent 				goto err_read_i2c_eeprom;
1475dc0cb1cdSDale Ghent 
1476dc0cb1cdSDale Ghent 			vendor_oui =
1477dc0cb1cdSDale Ghent 			  ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
1478dc0cb1cdSDale Ghent 			   (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
1479dc0cb1cdSDale Ghent 			   (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
1480dc0cb1cdSDale Ghent 
1481dc0cb1cdSDale Ghent 			switch (vendor_oui) {
1482dc0cb1cdSDale Ghent 			case IXGBE_SFF_VENDOR_OUI_TYCO:
1483dc0cb1cdSDale Ghent 				if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
1484dc0cb1cdSDale Ghent 					hw->phy.type =
1485dc0cb1cdSDale Ghent 						    ixgbe_phy_sfp_passive_tyco;
1486dc0cb1cdSDale Ghent 				break;
1487dc0cb1cdSDale Ghent 			case IXGBE_SFF_VENDOR_OUI_FTL:
1488dc0cb1cdSDale Ghent 				if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
1489dc0cb1cdSDale Ghent 					hw->phy.type = ixgbe_phy_sfp_ftl_active;
1490dc0cb1cdSDale Ghent 				else
1491dc0cb1cdSDale Ghent 					hw->phy.type = ixgbe_phy_sfp_ftl;
1492dc0cb1cdSDale Ghent 				break;
1493dc0cb1cdSDale Ghent 			case IXGBE_SFF_VENDOR_OUI_AVAGO:
1494dc0cb1cdSDale Ghent 				hw->phy.type = ixgbe_phy_sfp_avago;
1495dc0cb1cdSDale Ghent 				break;
1496dc0cb1cdSDale Ghent 			case IXGBE_SFF_VENDOR_OUI_INTEL:
1497dc0cb1cdSDale Ghent 				hw->phy.type = ixgbe_phy_sfp_intel;
1498dc0cb1cdSDale Ghent 				break;
1499dc0cb1cdSDale Ghent 			default:
1500*48ed61a7SRobert Mustacchi 				hw->phy.type = ixgbe_phy_sfp_unknown;
1501dc0cb1cdSDale Ghent 				break;
1502dc0cb1cdSDale Ghent 			}
1503dc0cb1cdSDale Ghent 		}
1504dc0cb1cdSDale Ghent 
1505dc0cb1cdSDale Ghent 		/* Allow any DA cable vendor */
1506dc0cb1cdSDale Ghent 		if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
1507*48ed61a7SRobert Mustacchi 			IXGBE_SFF_DA_ACTIVE_CABLE)) {
1508*48ed61a7SRobert Mustacchi 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
1509*48ed61a7SRobert Mustacchi 				hw->phy.type = ixgbe_phy_sfp_passive_unknown;
1510*48ed61a7SRobert Mustacchi 			else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
1511*48ed61a7SRobert Mustacchi 				hw->phy.type = ixgbe_phy_sfp_active_unknown;
1512dc0cb1cdSDale Ghent 			status = IXGBE_SUCCESS;
1513dc0cb1cdSDale Ghent 			goto out;
1514dc0cb1cdSDale Ghent 		}
1515dc0cb1cdSDale Ghent 
1516dc0cb1cdSDale Ghent 		/* Verify supported 1G SFP modules */
1517dc0cb1cdSDale Ghent 		if (comp_codes_10g == 0 &&
1518dc0cb1cdSDale Ghent 		    !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
1519dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
1520dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
1521dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
1522dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
1523dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
1524dc0cb1cdSDale Ghent 			hw->phy.type = ixgbe_phy_sfp_unsupported;
1525dc0cb1cdSDale Ghent 			status = IXGBE_ERR_SFP_NOT_SUPPORTED;
1526dc0cb1cdSDale Ghent 			goto out;
1527dc0cb1cdSDale Ghent 		}
1528dc0cb1cdSDale Ghent 
1529dc0cb1cdSDale Ghent 		/* Anything else 82598-based is supported */
1530dc0cb1cdSDale Ghent 		if (hw->mac.type == ixgbe_mac_82598EB) {
1531dc0cb1cdSDale Ghent 			status = IXGBE_SUCCESS;
1532dc0cb1cdSDale Ghent 			goto out;
1533dc0cb1cdSDale Ghent 		}
1534dc0cb1cdSDale Ghent 
1535dc0cb1cdSDale Ghent 		ixgbe_get_device_caps(hw, &enforce_sfp);
1536dc0cb1cdSDale Ghent 		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
1537dc0cb1cdSDale Ghent 		    !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
1538dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
1539dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
1540dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
1541dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
1542dc0cb1cdSDale Ghent 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
1543dc0cb1cdSDale Ghent 			/* Make sure we're a supported PHY type */
1544dc0cb1cdSDale Ghent 			if (hw->phy.type == ixgbe_phy_sfp_intel) {
1545dc0cb1cdSDale Ghent 				status = IXGBE_SUCCESS;
1546dc0cb1cdSDale Ghent 			} else {
1547dc0cb1cdSDale Ghent 				if (hw->allow_unsupported_sfp == TRUE) {
1548*48ed61a7SRobert Mustacchi 					EWARN(hw, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n");
1549dc0cb1cdSDale Ghent 					status = IXGBE_SUCCESS;
1550dc0cb1cdSDale Ghent 				} else {
1551dc0cb1cdSDale Ghent 					DEBUGOUT("SFP+ module not supported\n");
1552dc0cb1cdSDale Ghent 					hw->phy.type =
1553dc0cb1cdSDale Ghent 						ixgbe_phy_sfp_unsupported;
1554dc0cb1cdSDale Ghent 					status = IXGBE_ERR_SFP_NOT_SUPPORTED;
1555dc0cb1cdSDale Ghent 				}
1556dc0cb1cdSDale Ghent 			}
1557dc0cb1cdSDale Ghent 		} else {
1558dc0cb1cdSDale Ghent 			status = IXGBE_SUCCESS;
1559dc0cb1cdSDale Ghent 		}
1560dc0cb1cdSDale Ghent 	}
1561dc0cb1cdSDale Ghent 
1562dc0cb1cdSDale Ghent out:
1563dc0cb1cdSDale Ghent 	return status;
1564dc0cb1cdSDale Ghent 
1565dc0cb1cdSDale Ghent err_read_i2c_eeprom:
1566dc0cb1cdSDale Ghent 	hw->phy.sfp_type = ixgbe_sfp_type_not_present;
1567dc0cb1cdSDale Ghent 	if (hw->phy.type != ixgbe_phy_nl) {
1568dc0cb1cdSDale Ghent 		hw->phy.id = 0;
1569dc0cb1cdSDale Ghent 		hw->phy.type = ixgbe_phy_unknown;
1570dc0cb1cdSDale Ghent 	}
1571dc0cb1cdSDale Ghent 	return IXGBE_ERR_SFP_NOT_PRESENT;
1572dc0cb1cdSDale Ghent }
1573dc0cb1cdSDale Ghent 
1574dc0cb1cdSDale Ghent /**
1575dc0cb1cdSDale Ghent  *  ixgbe_get_supported_phy_sfp_layer_generic - Returns physical layer type
1576dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
1577dc0cb1cdSDale Ghent  *
1578dc0cb1cdSDale Ghent  *  Determines physical layer capabilities of the current SFP.
1579dc0cb1cdSDale Ghent  */
ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw * hw)1580*48ed61a7SRobert Mustacchi u64 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw)
1581dc0cb1cdSDale Ghent {
1582*48ed61a7SRobert Mustacchi 	u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
1583dc0cb1cdSDale Ghent 	u8 comp_codes_10g = 0;
1584dc0cb1cdSDale Ghent 	u8 comp_codes_1g = 0;
1585dc0cb1cdSDale Ghent 
1586dc0cb1cdSDale Ghent 	DEBUGFUNC("ixgbe_get_supported_phy_sfp_layer_generic");
1587dc0cb1cdSDale Ghent 
1588dc0cb1cdSDale Ghent 	hw->phy.ops.identify_sfp(hw);
1589dc0cb1cdSDale Ghent 	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
1590dc0cb1cdSDale Ghent 		return physical_layer;
1591dc0cb1cdSDale Ghent 
1592dc0cb1cdSDale Ghent 	switch (hw->phy.type) {
1593dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_passive_tyco:
1594dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_passive_unknown:
1595dc0cb1cdSDale Ghent 	case ixgbe_phy_qsfp_passive_unknown:
1596dc0cb1cdSDale Ghent 		physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
1597dc0cb1cdSDale Ghent 		break;
1598dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_ftl_active:
1599dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_active_unknown:
1600dc0cb1cdSDale Ghent 	case ixgbe_phy_qsfp_active_unknown:
1601dc0cb1cdSDale Ghent 		physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA;
1602dc0cb1cdSDale Ghent 		break;
1603dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_avago:
1604dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_ftl:
1605dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_intel:
1606dc0cb1cdSDale Ghent 	case ixgbe_phy_sfp_unknown:
1607dc0cb1cdSDale Ghent 		hw->phy.ops.read_i2c_eeprom(hw,
1608dc0cb1cdSDale Ghent 		      IXGBE_SFF_1GBE_COMP_CODES, &comp_codes_1g);
1609dc0cb1cdSDale Ghent 		hw->phy.ops.read_i2c_eeprom(hw,
1610dc0cb1cdSDale Ghent 		      IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g);
1611dc0cb1cdSDale Ghent 		if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
1612dc0cb1cdSDale Ghent 			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
1613dc0cb1cdSDale Ghent 		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
1614dc0cb1cdSDale Ghent 			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
1615dc0cb1cdSDale Ghent 		else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
1616dc0cb1cdSDale Ghent 			physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
1617dc0cb1cdSDale Ghent 		else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE)
1618dc0cb1cdSDale Ghent 			physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_SX;
1619dc0cb1cdSDale Ghent 		break;
1620dc0cb1cdSDale Ghent 	case ixgbe_phy_qsfp_intel:
1621dc0cb1cdSDale Ghent 	case ixgbe_phy_qsfp_unknown:
1622dc0cb1cdSDale Ghent 		hw->phy.ops.read_i2c_eeprom(hw,
1623dc0cb1cdSDale Ghent 		      IXGBE_SFF_QSFP_10GBE_COMP, &comp_codes_10g);
1624dc0cb1cdSDale Ghent 		if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
1625dc0cb1cdSDale Ghent 			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
1626dc0cb1cdSDale Ghent 		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
1627dc0cb1cdSDale Ghent 			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
1628dc0cb1cdSDale Ghent 		break;
1629dc0cb1cdSDale Ghent 	default:
1630dc0cb1cdSDale Ghent 		break;
1631dc0cb1cdSDale Ghent 	}
1632dc0cb1cdSDale Ghent 
1633dc0cb1cdSDale Ghent 	return physical_layer;
1634dc0cb1cdSDale Ghent }
1635dc0cb1cdSDale Ghent 
1636dc0cb1cdSDale Ghent /**
1637dc0cb1cdSDale Ghent  *  ixgbe_identify_qsfp_module_generic - Identifies QSFP modules
1638dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
1639dc0cb1cdSDale Ghent  *
1640dc0cb1cdSDale Ghent  *  Searches for and identifies the QSFP module and assigns appropriate PHY type
1641dc0cb1cdSDale Ghent  **/
ixgbe_identify_qsfp_module_generic(struct ixgbe_hw * hw)1642dc0cb1cdSDale Ghent s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
1643dc0cb1cdSDale Ghent {
1644dc0cb1cdSDale Ghent 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
1645dc0cb1cdSDale Ghent 	u32 vendor_oui = 0;
1646dc0cb1cdSDale Ghent 	enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
1647dc0cb1cdSDale Ghent 	u8 identifier = 0;
1648dc0cb1cdSDale Ghent 	u8 comp_codes_1g = 0;
1649dc0cb1cdSDale Ghent 	u8 comp_codes_10g = 0;
1650dc0cb1cdSDale Ghent 	u8 oui_bytes[3] = {0, 0, 0};
1651dc0cb1cdSDale Ghent 	u16 enforce_sfp = 0;
1652dc0cb1cdSDale Ghent 	u8 connector = 0;
1653dc0cb1cdSDale Ghent 	u8 cable_length = 0;
1654dc0cb1cdSDale Ghent 	u8 device_tech = 0;
1655dc0cb1cdSDale Ghent 	bool active_cable = FALSE;
1656dc0cb1cdSDale Ghent 
1657dc0cb1cdSDale Ghent 	DEBUGFUNC("ixgbe_identify_qsfp_module_generic");
1658dc0cb1cdSDale Ghent 
1659dc0cb1cdSDale Ghent 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) {
1660dc0cb1cdSDale Ghent 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
1661dc0cb1cdSDale Ghent 		status = IXGBE_ERR_SFP_NOT_PRESENT;
1662dc0cb1cdSDale Ghent 		goto out;
1663dc0cb1cdSDale Ghent 	}
1664dc0cb1cdSDale Ghent 
1665dc0cb1cdSDale Ghent 	/* LAN ID is needed for I2C access */
1666dc0cb1cdSDale Ghent 	hw->mac.ops.set_lan_id(hw);
166713740cb2SPaul Guo 
1668dc0cb1cdSDale Ghent 	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
1669dc0cb1cdSDale Ghent 					     &identifier);
167063b3bba8SJerry Jelinek 
1671dc0cb1cdSDale Ghent 	if (status != IXGBE_SUCCESS)
1672dc0cb1cdSDale Ghent 		goto err_read_i2c_eeprom;
167363b3bba8SJerry Jelinek 
1674dc0cb1cdSDale Ghent 	if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
1675dc0cb1cdSDale Ghent 		hw->phy.type = ixgbe_phy_sfp_unsupported;
1676dc0cb1cdSDale Ghent 		status = IXGBE_ERR_SFP_NOT_SUPPORTED;
1677dc0cb1cdSDale Ghent 		goto out;
1678dc0cb1cdSDale Ghent 	}
167963b3bba8SJerry Jelinek 
1680dc0cb1cdSDale Ghent 	hw->phy.id = identifier;
168163b3bba8SJerry Jelinek 
1682dc0cb1cdSDale Ghent 	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
1683dc0cb1cdSDale Ghent 					     &comp_codes_10g);
168463b3bba8SJerry Jelinek 
1685dc0cb1cdSDale Ghent 	if (status != IXGBE_SUCCESS)
1686dc0cb1cdSDale Ghent 		goto err_read_i2c_eeprom;
168713740cb2SPaul Guo 
1688dc0cb1cdSDale Ghent 	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_1GBE_COMP,
1689dc0cb1cdSDale Ghent 					     &comp_codes_1g);
169013740cb2SPaul Guo 
1691dc0cb1cdSDale Ghent 	if (status != IXGBE_SUCCESS)
1692dc0cb1cdSDale Ghent 		goto err_read_i2c_eeprom;
169373cd555cSBin Tu - Sun Microsystems - Beijing China 
1694dc0cb1cdSDale Ghent 	if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) {
1695dc0cb1cdSDale Ghent 		hw->phy.type = ixgbe_phy_qsfp_passive_unknown;
1696dc0cb1cdSDale Ghent 		if (hw->bus.lan_id == 0)
1697dc0cb1cdSDale Ghent 			hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0;
1698dc0cb1cdSDale Ghent 		else
1699dc0cb1cdSDale Ghent 			hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1;
1700dc0cb1cdSDale Ghent 	} else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
1701dc0cb1cdSDale Ghent 				     IXGBE_SFF_10GBASELR_CAPABLE)) {
1702dc0cb1cdSDale Ghent 		if (hw->bus.lan_id == 0)
1703dc0cb1cdSDale Ghent 			hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0;
1704dc0cb1cdSDale Ghent 		else
1705dc0cb1cdSDale Ghent 			hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1;
1706dc0cb1cdSDale Ghent 	} else {
1707dc0cb1cdSDale Ghent 		if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE)
1708dc0cb1cdSDale Ghent 			active_cable = TRUE;
1709dc0cb1cdSDale Ghent 
1710dc0cb1cdSDale Ghent 		if (!active_cable) {
1711dc0cb1cdSDale Ghent 			/* check for active DA cables that pre-date
1712dc0cb1cdSDale Ghent 			 * SFF-8436 v3.6 */
1713dc0cb1cdSDale Ghent 			hw->phy.ops.read_i2c_eeprom(hw,
1714dc0cb1cdSDale Ghent 					IXGBE_SFF_QSFP_CONNECTOR,
1715dc0cb1cdSDale Ghent 					&connector);
1716dc0cb1cdSDale Ghent 
1717dc0cb1cdSDale Ghent 			hw->phy.ops.read_i2c_eeprom(hw,
1718dc0cb1cdSDale Ghent 					IXGBE_SFF_QSFP_CABLE_LENGTH,
1719dc0cb1cdSDale Ghent 					&cable_length);
1720dc0cb1cdSDale Ghent 
1721dc0cb1cdSDale Ghent 			hw->phy.ops.read_i2c_eeprom(hw,
1722dc0cb1cdSDale Ghent 					IXGBE_SFF_QSFP_DEVICE_TECH,
1723dc0cb1cdSDale Ghent 					&device_tech);
1724dc0cb1cdSDale Ghent 
1725dc0cb1cdSDale Ghent 			if ((connector ==
1726dc0cb1cdSDale Ghent 				     IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE) &&
1727dc0cb1cdSDale Ghent 			    (cable_length > 0) &&
1728dc0cb1cdSDale Ghent 			    ((device_tech >> 4) ==
1729dc0cb1cdSDale Ghent 				     IXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL))
1730dc0cb1cdSDale Ghent 				active_cable = TRUE;
1731185c5677SPaul Guo 		}
1732185c5677SPaul Guo 
1733dc0cb1cdSDale Ghent 		if (active_cable) {
1734dc0cb1cdSDale Ghent 			hw->phy.type = ixgbe_phy_qsfp_active_unknown;
1735dc0cb1cdSDale Ghent 			if (hw->bus.lan_id == 0)
1736dc0cb1cdSDale Ghent 				hw->phy.sfp_type =
1737dc0cb1cdSDale Ghent 						ixgbe_sfp_type_da_act_lmt_core0;
1738dc0cb1cdSDale Ghent 			else
1739dc0cb1cdSDale Ghent 				hw->phy.sfp_type =
1740dc0cb1cdSDale Ghent 						ixgbe_sfp_type_da_act_lmt_core1;
1741dc0cb1cdSDale Ghent 		} else {
1742dc0cb1cdSDale Ghent 			/* unsupported module type */
1743185c5677SPaul Guo 			hw->phy.type = ixgbe_phy_sfp_unsupported;
1744185c5677SPaul Guo 			status = IXGBE_ERR_SFP_NOT_SUPPORTED;
1745185c5677SPaul Guo 			goto out;
1746185c5677SPaul Guo 		}
1747dc0cb1cdSDale Ghent 	}
1748185c5677SPaul Guo 
1749dc0cb1cdSDale Ghent 	if (hw->phy.sfp_type != stored_sfp_type)
1750dc0cb1cdSDale Ghent 		hw->phy.sfp_setup_needed = TRUE;
175173cd555cSBin Tu - Sun Microsystems - Beijing China 
1752dc0cb1cdSDale Ghent 	/* Determine if the QSFP+ PHY is dual speed or not. */
1753dc0cb1cdSDale Ghent 	hw->phy.multispeed_fiber = FALSE;
1754dc0cb1cdSDale Ghent 	if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
1755dc0cb1cdSDale Ghent 	   (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
1756dc0cb1cdSDale Ghent 	   ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
1757dc0cb1cdSDale Ghent 	   (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
1758dc0cb1cdSDale Ghent 		hw->phy.multispeed_fiber = TRUE;
1759dc0cb1cdSDale Ghent 
1760dc0cb1cdSDale Ghent 	/* Determine PHY vendor for optical modules */
1761dc0cb1cdSDale Ghent 	if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
1762dc0cb1cdSDale Ghent 			      IXGBE_SFF_10GBASELR_CAPABLE))  {
1763dc0cb1cdSDale Ghent 		status = hw->phy.ops.read_i2c_eeprom(hw,
1764dc0cb1cdSDale Ghent 					    IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0,
1765dc0cb1cdSDale Ghent 					    &oui_bytes[0]);
1766dc0cb1cdSDale Ghent 
1767dc0cb1cdSDale Ghent 		if (status != IXGBE_SUCCESS)
1768dc0cb1cdSDale Ghent 			goto err_read_i2c_eeprom;
1769dc0cb1cdSDale Ghent 
1770dc0cb1cdSDale Ghent 		status = hw->phy.ops.read_i2c_eeprom(hw,
1771dc0cb1cdSDale Ghent 					    IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1,
1772dc0cb1cdSDale Ghent 					    &oui_bytes[1]);
1773dc0cb1cdSDale Ghent 
1774dc0cb1cdSDale Ghent 		if (status != IXGBE_SUCCESS)
1775dc0cb1cdSDale Ghent 			goto err_read_i2c_eeprom;
1776dc0cb1cdSDale Ghent 
1777dc0cb1cdSDale Ghent 		status = hw->phy.ops.read_i2c_eeprom(hw,
1778dc0cb1cdSDale Ghent 					    IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2,
1779dc0cb1cdSDale Ghent 					    &oui_bytes[2]);
1780dc0cb1cdSDale Ghent 
1781dc0cb1cdSDale Ghent 		if (status != IXGBE_SUCCESS)
1782dc0cb1cdSDale Ghent 			goto err_read_i2c_eeprom;
1783dc0cb1cdSDale Ghent 
1784dc0cb1cdSDale Ghent 		vendor_oui =
1785dc0cb1cdSDale Ghent 		  ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
1786dc0cb1cdSDale Ghent 		   (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
1787dc0cb1cdSDale Ghent 		   (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
1788dc0cb1cdSDale Ghent 
1789dc0cb1cdSDale Ghent 		if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL)
1790dc0cb1cdSDale Ghent 			hw->phy.type = ixgbe_phy_qsfp_intel;
1791dc0cb1cdSDale Ghent 		else
1792dc0cb1cdSDale Ghent 			hw->phy.type = ixgbe_phy_qsfp_unknown;
1793dc0cb1cdSDale Ghent 
1794dc0cb1cdSDale Ghent 		ixgbe_get_device_caps(hw, &enforce_sfp);
1795dc0cb1cdSDale Ghent 		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
179673cd555cSBin Tu - Sun Microsystems - Beijing China 			/* Make sure we're a supported PHY type */
1797dc0cb1cdSDale Ghent 			if (hw->phy.type == ixgbe_phy_qsfp_intel) {
179873cd555cSBin Tu - Sun Microsystems - Beijing China 				status = IXGBE_SUCCESS;
179973cd555cSBin Tu - Sun Microsystems - Beijing China 			} else {
180069b5a878SDan McDonald 				if (hw->allow_unsupported_sfp == TRUE) {
1801*48ed61a7SRobert Mustacchi 					EWARN(hw, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n");
180269b5a878SDan McDonald 					status = IXGBE_SUCCESS;
180369b5a878SDan McDonald 				} else {
1804dc0cb1cdSDale Ghent 					DEBUGOUT("QSFP module not supported\n");
180569b5a878SDan McDonald 					hw->phy.type =
180669b5a878SDan McDonald 						ixgbe_phy_sfp_unsupported;
180769b5a878SDan McDonald 					status = IXGBE_ERR_SFP_NOT_SUPPORTED;
180869b5a878SDan McDonald 				}
180973cd555cSBin Tu - Sun Microsystems - Beijing China 			}
181073cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
181173cd555cSBin Tu - Sun Microsystems - Beijing China 			status = IXGBE_SUCCESS;
181273cd555cSBin Tu - Sun Microsystems - Beijing China 		}
181313740cb2SPaul Guo 	}
181413740cb2SPaul Guo 
181513740cb2SPaul Guo out:
181663b3bba8SJerry Jelinek 	return status;
181713740cb2SPaul Guo 
181863b3bba8SJerry Jelinek err_read_i2c_eeprom:
181963b3bba8SJerry Jelinek 	hw->phy.sfp_type = ixgbe_sfp_type_not_present;
1820dc0cb1cdSDale Ghent 	hw->phy.id = 0;
1821dc0cb1cdSDale Ghent 	hw->phy.type = ixgbe_phy_unknown;
1822dc0cb1cdSDale Ghent 
182363b3bba8SJerry Jelinek 	return IXGBE_ERR_SFP_NOT_PRESENT;
182463b3bba8SJerry Jelinek }
182513740cb2SPaul Guo 
182663b3bba8SJerry Jelinek /**
182763b3bba8SJerry Jelinek  *  ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
182863b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
182963b3bba8SJerry Jelinek  *  @list_offset: offset to the SFP ID list
183063b3bba8SJerry Jelinek  *  @data_offset: offset to the SFP data block
183173cd555cSBin Tu - Sun Microsystems - Beijing China  *
183263b3bba8SJerry Jelinek  *  Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if
183363b3bba8SJerry Jelinek  *  so it returns the offsets to the phy init sequence block.
183463b3bba8SJerry Jelinek  **/
ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw * hw,u16 * list_offset,u16 * data_offset)183513740cb2SPaul Guo s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
183669b5a878SDan McDonald 					u16 *list_offset,
183769b5a878SDan McDonald 					u16 *data_offset)
183813740cb2SPaul Guo {
183913740cb2SPaul Guo 	u16 sfp_id;
18405b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	u16 sfp_type = hw->phy.sfp_type;
184113740cb2SPaul Guo 
18423cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_sfp_init_sequence_offsets");
18433cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
184413740cb2SPaul Guo 	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
184563b3bba8SJerry Jelinek 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
184613740cb2SPaul Guo 
184713740cb2SPaul Guo 	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
184863b3bba8SJerry Jelinek 		return IXGBE_ERR_SFP_NOT_PRESENT;
184913740cb2SPaul Guo 
185013740cb2SPaul Guo 	if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
185113740cb2SPaul Guo 	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
185263b3bba8SJerry Jelinek 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
185313740cb2SPaul Guo 
18545b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
18555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Limiting active cables and 1G Phys must be initialized as
18565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * SR modules
18575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
18585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
1859eb341807SSaso Kiselkov 	    sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
186069b5a878SDan McDonald 	    sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
186169b5a878SDan McDonald 	    sfp_type == ixgbe_sfp_type_1g_sx_core0)
18625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		sfp_type = ixgbe_sfp_type_srlr_core0;
18635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
1864eb341807SSaso Kiselkov 		 sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
186569b5a878SDan McDonald 		 sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
186669b5a878SDan McDonald 		 sfp_type == ixgbe_sfp_type_1g_sx_core1)
18675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		sfp_type = ixgbe_sfp_type_srlr_core1;
18685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
186913740cb2SPaul Guo 	/* Read offset to PHY init contents */
1870dc0cb1cdSDale Ghent 	if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) {
1871dc0cb1cdSDale Ghent 		ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
1872dc0cb1cdSDale Ghent 			      "eeprom read at offset %d failed",
1873dc0cb1cdSDale Ghent 			      IXGBE_PHY_INIT_OFFSET_NL);
1874dc0cb1cdSDale Ghent 		return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
1875dc0cb1cdSDale Ghent 	}
187613740cb2SPaul Guo 
187713740cb2SPaul Guo 	if ((!*list_offset) || (*list_offset == 0xFFFF))
187863b3bba8SJerry Jelinek 		return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
187913740cb2SPaul Guo 
188013740cb2SPaul Guo 	/* Shift offset to first ID word */
188113740cb2SPaul Guo 	(*list_offset)++;
188213740cb2SPaul Guo 
188313740cb2SPaul Guo 	/*
188413740cb2SPaul Guo 	 * Find the matching SFP ID in the EEPROM
188513740cb2SPaul Guo 	 * and program the init sequence
188613740cb2SPaul Guo 	 */
1887dc0cb1cdSDale Ghent 	if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
1888dc0cb1cdSDale Ghent 		goto err_phy;
188913740cb2SPaul Guo 
189013740cb2SPaul Guo 	while (sfp_id != IXGBE_PHY_INIT_END_NL) {
18915b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if (sfp_id == sfp_type) {
189213740cb2SPaul Guo 			(*list_offset)++;
1893dc0cb1cdSDale Ghent 			if (hw->eeprom.ops.read(hw, *list_offset, data_offset))
1894dc0cb1cdSDale Ghent 				goto err_phy;
189513740cb2SPaul Guo 			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
189613740cb2SPaul Guo 				DEBUGOUT("SFP+ module not supported\n");
189763b3bba8SJerry Jelinek 				return IXGBE_ERR_SFP_NOT_SUPPORTED;
189813740cb2SPaul Guo 			} else {
189913740cb2SPaul Guo 				break;
190013740cb2SPaul Guo 			}
190113740cb2SPaul Guo 		} else {
190213740cb2SPaul Guo 			(*list_offset) += 2;
190313740cb2SPaul Guo 			if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
1904dc0cb1cdSDale Ghent 				goto err_phy;
190513740cb2SPaul Guo 		}
190613740cb2SPaul Guo 	}
190713740cb2SPaul Guo 
190813740cb2SPaul Guo 	if (sfp_id == IXGBE_PHY_INIT_END_NL) {
190913740cb2SPaul Guo 		DEBUGOUT("No matching SFP+ module found\n");
191063b3bba8SJerry Jelinek 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
191113740cb2SPaul Guo 	}
191213740cb2SPaul Guo 
191363b3bba8SJerry Jelinek 	return IXGBE_SUCCESS;
1914dc0cb1cdSDale Ghent 
1915dc0cb1cdSDale Ghent err_phy:
1916dc0cb1cdSDale Ghent 	ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
1917dc0cb1cdSDale Ghent 		      "eeprom read at offset %d failed", *list_offset);
1918dc0cb1cdSDale Ghent 	return IXGBE_ERR_PHY;
191913740cb2SPaul Guo }
192073cd555cSBin Tu - Sun Microsystems - Beijing China 
192163b3bba8SJerry Jelinek /**
192263b3bba8SJerry Jelinek  *  ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface
192363b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
192463b3bba8SJerry Jelinek  *  @byte_offset: EEPROM byte offset to read
192563b3bba8SJerry Jelinek  *  @eeprom_data: value read
192673cd555cSBin Tu - Sun Microsystems - Beijing China  *
192763b3bba8SJerry Jelinek  *  Performs byte read operation to SFP module's EEPROM over I2C interface.
192863b3bba8SJerry Jelinek  **/
ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 * eeprom_data)192963b3bba8SJerry Jelinek s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
193069b5a878SDan McDonald 				  u8 *eeprom_data)
193173cd555cSBin Tu - Sun Microsystems - Beijing China {
193273cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_read_i2c_eeprom_generic");
193373cd555cSBin Tu - Sun Microsystems - Beijing China 
193463b3bba8SJerry Jelinek 	return hw->phy.ops.read_i2c_byte(hw, byte_offset,
193569b5a878SDan McDonald 					 IXGBE_I2C_EEPROM_DEV_ADDR,
193669b5a878SDan McDonald 					 eeprom_data);
193773cd555cSBin Tu - Sun Microsystems - Beijing China }
193873cd555cSBin Tu - Sun Microsystems - Beijing China 
1939dc0cb1cdSDale Ghent /**
1940dc0cb1cdSDale Ghent  *  ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface
1941dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
1942dc0cb1cdSDale Ghent  *  @byte_offset: byte offset at address 0xA2
1943*48ed61a7SRobert Mustacchi  *  @sff8472_data: value read
1944dc0cb1cdSDale Ghent  *
1945dc0cb1cdSDale Ghent  *  Performs byte read operation to SFP module's SFF-8472 data over I2C
1946dc0cb1cdSDale Ghent  **/
ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 * sff8472_data)1947dc0cb1cdSDale Ghent static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
1948dc0cb1cdSDale Ghent 					  u8 *sff8472_data)
1949dc0cb1cdSDale Ghent {
1950dc0cb1cdSDale Ghent 	return hw->phy.ops.read_i2c_byte(hw, byte_offset,
1951dc0cb1cdSDale Ghent 					 IXGBE_I2C_EEPROM_DEV_ADDR2,
1952dc0cb1cdSDale Ghent 					 sff8472_data);
1953dc0cb1cdSDale Ghent }
1954dc0cb1cdSDale Ghent 
195563b3bba8SJerry Jelinek /**
195663b3bba8SJerry Jelinek  *  ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
195763b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
195863b3bba8SJerry Jelinek  *  @byte_offset: EEPROM byte offset to write
195963b3bba8SJerry Jelinek  *  @eeprom_data: value to write
196073cd555cSBin Tu - Sun Microsystems - Beijing China  *
196163b3bba8SJerry Jelinek  *  Performs byte write operation to SFP module's EEPROM over I2C interface.
196263b3bba8SJerry Jelinek  **/
ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 eeprom_data)196373cd555cSBin Tu - Sun Microsystems - Beijing China s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
196469b5a878SDan McDonald 				   u8 eeprom_data)
196573cd555cSBin Tu - Sun Microsystems - Beijing China {
196673cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_write_i2c_eeprom_generic");
196773cd555cSBin Tu - Sun Microsystems - Beijing China 
196863b3bba8SJerry Jelinek 	return hw->phy.ops.write_i2c_byte(hw, byte_offset,
196969b5a878SDan McDonald 					  IXGBE_I2C_EEPROM_DEV_ADDR,
197069b5a878SDan McDonald 					  eeprom_data);
197173cd555cSBin Tu - Sun Microsystems - Beijing China }
197273cd555cSBin Tu - Sun Microsystems - Beijing China 
197363b3bba8SJerry Jelinek /**
1974dc0cb1cdSDale Ghent  * ixgbe_is_sfp_probe - Returns TRUE if SFP is being detected
1975dc0cb1cdSDale Ghent  * @hw: pointer to hardware structure
1976dc0cb1cdSDale Ghent  * @offset: eeprom offset to be read
1977dc0cb1cdSDale Ghent  * @addr: I2C address to be read
1978dc0cb1cdSDale Ghent  */
ixgbe_is_sfp_probe(struct ixgbe_hw * hw,u8 offset,u8 addr)1979dc0cb1cdSDale Ghent static bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr)
1980dc0cb1cdSDale Ghent {
1981dc0cb1cdSDale Ghent 	if (addr == IXGBE_I2C_EEPROM_DEV_ADDR &&
1982dc0cb1cdSDale Ghent 	    offset == IXGBE_SFF_IDENTIFIER &&
1983dc0cb1cdSDale Ghent 	    hw->phy.sfp_type == ixgbe_sfp_type_not_present)
1984dc0cb1cdSDale Ghent 		return TRUE;
1985dc0cb1cdSDale Ghent 	return FALSE;
1986dc0cb1cdSDale Ghent }
1987dc0cb1cdSDale Ghent 
1988dc0cb1cdSDale Ghent /**
1989dc0cb1cdSDale Ghent  *  ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C
199063b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
199163b3bba8SJerry Jelinek  *  @byte_offset: byte offset to read
1992*48ed61a7SRobert Mustacchi  *  @dev_addr: address to read from
199363b3bba8SJerry Jelinek  *  @data: value read
1994dc0cb1cdSDale Ghent  *  @lock: TRUE if to take and release semaphore
199573cd555cSBin Tu - Sun Microsystems - Beijing China  *
199663b3bba8SJerry Jelinek  *  Performs byte read operation to SFP module's EEPROM over I2C interface at
199769b5a878SDan McDonald  *  a specified device address.
199863b3bba8SJerry Jelinek  **/
ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 * data,bool lock)1999dc0cb1cdSDale Ghent static s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
2000dc0cb1cdSDale Ghent 					   u8 dev_addr, u8 *data, bool lock)
200173cd555cSBin Tu - Sun Microsystems - Beijing China {
2002dc0cb1cdSDale Ghent 	s32 status;
2003185c5677SPaul Guo 	u32 max_retry = 10;
200473cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 retry = 0;
2005dc0cb1cdSDale Ghent 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
200673cd555cSBin Tu - Sun Microsystems - Beijing China 	bool nack = 1;
200769b5a878SDan McDonald 	*data = 0;
200873cd555cSBin Tu - Sun Microsystems - Beijing China 
200973cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_read_i2c_byte_generic");
201073cd555cSBin Tu - Sun Microsystems - Beijing China 
2011dc0cb1cdSDale Ghent 	if (hw->mac.type >= ixgbe_mac_X550)
2012dc0cb1cdSDale Ghent 		max_retry = 3;
2013dc0cb1cdSDale Ghent 	if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr))
2014dc0cb1cdSDale Ghent 		max_retry = IXGBE_SFP_DETECT_RETRIES;
201573cd555cSBin Tu - Sun Microsystems - Beijing China 
201673cd555cSBin Tu - Sun Microsystems - Beijing China 	do {
2017dc0cb1cdSDale Ghent 		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
2018dc0cb1cdSDale Ghent 			return IXGBE_ERR_SWFW_SYNC;
2019185c5677SPaul Guo 
202073cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_start(hw);
202173cd555cSBin Tu - Sun Microsystems - Beijing China 
202273cd555cSBin Tu - Sun Microsystems - Beijing China 		/* Device Address and write indication */
202373cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
202473cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
202573cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
202673cd555cSBin Tu - Sun Microsystems - Beijing China 
202773cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_get_i2c_ack(hw);
202873cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
202973cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
203073cd555cSBin Tu - Sun Microsystems - Beijing China 
203173cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
203273cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
203373cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
203473cd555cSBin Tu - Sun Microsystems - Beijing China 
203573cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_get_i2c_ack(hw);
203673cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
203773cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
203873cd555cSBin Tu - Sun Microsystems - Beijing China 
203973cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_start(hw);
204073cd555cSBin Tu - Sun Microsystems - Beijing China 
204173cd555cSBin Tu - Sun Microsystems - Beijing China 		/* Device Address and read indication */
204273cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1));
204373cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
204473cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
204573cd555cSBin Tu - Sun Microsystems - Beijing China 
204673cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_get_i2c_ack(hw);
204773cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
204873cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
204973cd555cSBin Tu - Sun Microsystems - Beijing China 
205073cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_in_i2c_byte(hw, data);
205173cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
205273cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
205373cd555cSBin Tu - Sun Microsystems - Beijing China 
205473cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_bit(hw, nack);
205573cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
205673cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
205773cd555cSBin Tu - Sun Microsystems - Beijing China 
205873cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_stop(hw);
2059dc0cb1cdSDale Ghent 		if (lock)
2060dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
2061dc0cb1cdSDale Ghent 		return IXGBE_SUCCESS;
206273cd555cSBin Tu - Sun Microsystems - Beijing China 
206373cd555cSBin Tu - Sun Microsystems - Beijing China fail:
206473cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_bus_clear(hw);
2065dc0cb1cdSDale Ghent 		if (lock) {
2066dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
2067dc0cb1cdSDale Ghent 			msec_delay(100);
2068dc0cb1cdSDale Ghent 		}
206973cd555cSBin Tu - Sun Microsystems - Beijing China 		retry++;
207073cd555cSBin Tu - Sun Microsystems - Beijing China 		if (retry < max_retry)
207173cd555cSBin Tu - Sun Microsystems - Beijing China 			DEBUGOUT("I2C byte read error - Retrying.\n");
207273cd555cSBin Tu - Sun Microsystems - Beijing China 		else
207373cd555cSBin Tu - Sun Microsystems - Beijing China 			DEBUGOUT("I2C byte read error.\n");
207463b3bba8SJerry Jelinek 
207573cd555cSBin Tu - Sun Microsystems - Beijing China 	} while (retry < max_retry);
207673cd555cSBin Tu - Sun Microsystems - Beijing China 
207763b3bba8SJerry Jelinek 	return status;
207873cd555cSBin Tu - Sun Microsystems - Beijing China }
207973cd555cSBin Tu - Sun Microsystems - Beijing China 
208063b3bba8SJerry Jelinek /**
2081dc0cb1cdSDale Ghent  *  ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
2082dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
2083dc0cb1cdSDale Ghent  *  @byte_offset: byte offset to read
2084*48ed61a7SRobert Mustacchi  *  @dev_addr: address to read from
2085dc0cb1cdSDale Ghent  *  @data: value read
2086dc0cb1cdSDale Ghent  *
2087dc0cb1cdSDale Ghent  *  Performs byte read operation to SFP module's EEPROM over I2C interface at
2088dc0cb1cdSDale Ghent  *  a specified device address.
2089dc0cb1cdSDale Ghent  **/
ixgbe_read_i2c_byte_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 * data)2090dc0cb1cdSDale Ghent s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
2091dc0cb1cdSDale Ghent 				u8 dev_addr, u8 *data)
2092dc0cb1cdSDale Ghent {
2093dc0cb1cdSDale Ghent 	return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
2094dc0cb1cdSDale Ghent 					       data, TRUE);
2095dc0cb1cdSDale Ghent }
2096dc0cb1cdSDale Ghent 
2097dc0cb1cdSDale Ghent /**
2098dc0cb1cdSDale Ghent  *  ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C
2099dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
2100dc0cb1cdSDale Ghent  *  @byte_offset: byte offset to read
2101*48ed61a7SRobert Mustacchi  *  @dev_addr: address to read from
2102dc0cb1cdSDale Ghent  *  @data: value read
2103dc0cb1cdSDale Ghent  *
2104dc0cb1cdSDale Ghent  *  Performs byte read operation to SFP module's EEPROM over I2C interface at
2105dc0cb1cdSDale Ghent  *  a specified device address.
2106dc0cb1cdSDale Ghent  **/
ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 * data)2107dc0cb1cdSDale Ghent s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
2108dc0cb1cdSDale Ghent 					 u8 dev_addr, u8 *data)
2109dc0cb1cdSDale Ghent {
2110dc0cb1cdSDale Ghent 	return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
2111dc0cb1cdSDale Ghent 					       data, FALSE);
2112dc0cb1cdSDale Ghent }
2113dc0cb1cdSDale Ghent 
2114dc0cb1cdSDale Ghent /**
2115dc0cb1cdSDale Ghent  *  ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C
211663b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
211763b3bba8SJerry Jelinek  *  @byte_offset: byte offset to write
2118*48ed61a7SRobert Mustacchi  *  @dev_addr: address to write to
211963b3bba8SJerry Jelinek  *  @data: value to write
2120dc0cb1cdSDale Ghent  *  @lock: TRUE if to take and release semaphore
212173cd555cSBin Tu - Sun Microsystems - Beijing China  *
212263b3bba8SJerry Jelinek  *  Performs byte write operation to SFP module's EEPROM over I2C interface at
212363b3bba8SJerry Jelinek  *  a specified device address.
212463b3bba8SJerry Jelinek  **/
ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 data,bool lock)2125dc0cb1cdSDale Ghent static s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
2126dc0cb1cdSDale Ghent 					    u8 dev_addr, u8 data, bool lock)
212773cd555cSBin Tu - Sun Microsystems - Beijing China {
2128dc0cb1cdSDale Ghent 	s32 status;
212973cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 max_retry = 1;
213073cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 retry = 0;
2131dc0cb1cdSDale Ghent 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
213273cd555cSBin Tu - Sun Microsystems - Beijing China 
213373cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_write_i2c_byte_generic");
213473cd555cSBin Tu - Sun Microsystems - Beijing China 
2135dc0cb1cdSDale Ghent 	if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) !=
2136dc0cb1cdSDale Ghent 	    IXGBE_SUCCESS)
2137dc0cb1cdSDale Ghent 		return IXGBE_ERR_SWFW_SYNC;
213873cd555cSBin Tu - Sun Microsystems - Beijing China 
213973cd555cSBin Tu - Sun Microsystems - Beijing China 	do {
214073cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_start(hw);
214173cd555cSBin Tu - Sun Microsystems - Beijing China 
214273cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
214373cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
214473cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
214573cd555cSBin Tu - Sun Microsystems - Beijing China 
214673cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_get_i2c_ack(hw);
214773cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
214873cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
214973cd555cSBin Tu - Sun Microsystems - Beijing China 
215073cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
215173cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
215273cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
215373cd555cSBin Tu - Sun Microsystems - Beijing China 
215473cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_get_i2c_ack(hw);
215573cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
215673cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
215773cd555cSBin Tu - Sun Microsystems - Beijing China 
215873cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_byte(hw, data);
215973cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
216073cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
216173cd555cSBin Tu - Sun Microsystems - Beijing China 
216273cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_get_i2c_ack(hw);
216373cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
216473cd555cSBin Tu - Sun Microsystems - Beijing China 			goto fail;
216573cd555cSBin Tu - Sun Microsystems - Beijing China 
216673cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_stop(hw);
2167dc0cb1cdSDale Ghent 		if (lock)
2168dc0cb1cdSDale Ghent 			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
2169dc0cb1cdSDale Ghent 		return IXGBE_SUCCESS;
217073cd555cSBin Tu - Sun Microsystems - Beijing China 
217173cd555cSBin Tu - Sun Microsystems - Beijing China fail:
217273cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_i2c_bus_clear(hw);
217373cd555cSBin Tu - Sun Microsystems - Beijing China 		retry++;
217473cd555cSBin Tu - Sun Microsystems - Beijing China 		if (retry < max_retry)
217573cd555cSBin Tu - Sun Microsystems - Beijing China 			DEBUGOUT("I2C byte write error - Retrying.\n");
217673cd555cSBin Tu - Sun Microsystems - Beijing China 		else
217773cd555cSBin Tu - Sun Microsystems - Beijing China 			DEBUGOUT("I2C byte write error.\n");
217873cd555cSBin Tu - Sun Microsystems - Beijing China 	} while (retry < max_retry);
217973cd555cSBin Tu - Sun Microsystems - Beijing China 
2180dc0cb1cdSDale Ghent 	if (lock)
2181dc0cb1cdSDale Ghent 		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
218273cd555cSBin Tu - Sun Microsystems - Beijing China 
218363b3bba8SJerry Jelinek 	return status;
218473cd555cSBin Tu - Sun Microsystems - Beijing China }
218573cd555cSBin Tu - Sun Microsystems - Beijing China 
2186dc0cb1cdSDale Ghent /**
2187dc0cb1cdSDale Ghent  *  ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
2188dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
2189dc0cb1cdSDale Ghent  *  @byte_offset: byte offset to write
2190*48ed61a7SRobert Mustacchi  *  @dev_addr: address to write to
2191dc0cb1cdSDale Ghent  *  @data: value to write
2192dc0cb1cdSDale Ghent  *
2193dc0cb1cdSDale Ghent  *  Performs byte write operation to SFP module's EEPROM over I2C interface at
2194dc0cb1cdSDale Ghent  *  a specified device address.
2195dc0cb1cdSDale Ghent  **/
ixgbe_write_i2c_byte_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 data)2196dc0cb1cdSDale Ghent s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
2197dc0cb1cdSDale Ghent 				 u8 dev_addr, u8 data)
2198dc0cb1cdSDale Ghent {
2199dc0cb1cdSDale Ghent 	return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
2200dc0cb1cdSDale Ghent 						data, TRUE);
2201dc0cb1cdSDale Ghent }
2202dc0cb1cdSDale Ghent 
2203dc0cb1cdSDale Ghent /**
2204dc0cb1cdSDale Ghent  *  ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C
2205dc0cb1cdSDale Ghent  *  @hw: pointer to hardware structure
2206dc0cb1cdSDale Ghent  *  @byte_offset: byte offset to write
2207*48ed61a7SRobert Mustacchi  *  @dev_addr: address to write to
2208dc0cb1cdSDale Ghent  *  @data: value to write
2209dc0cb1cdSDale Ghent  *
2210dc0cb1cdSDale Ghent  *  Performs byte write operation to SFP module's EEPROM over I2C interface at
2211dc0cb1cdSDale Ghent  *  a specified device address.
2212dc0cb1cdSDale Ghent  **/
ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 data)2213dc0cb1cdSDale Ghent s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
2214dc0cb1cdSDale Ghent 					  u8 dev_addr, u8 data)
2215dc0cb1cdSDale Ghent {
2216dc0cb1cdSDale Ghent 	return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
2217dc0cb1cdSDale Ghent 						data, FALSE);
2218dc0cb1cdSDale Ghent }
2219dc0cb1cdSDale Ghent 
222063b3bba8SJerry Jelinek /**
222163b3bba8SJerry Jelinek  *  ixgbe_i2c_start - Sets I2C start condition
222263b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
222373cd555cSBin Tu - Sun Microsystems - Beijing China  *
222463b3bba8SJerry Jelinek  *  Sets I2C start condition (High -> Low on SDA while SCL is High)
2225dc0cb1cdSDale Ghent  *  Set bit-bang mode on X550 hardware.
222663b3bba8SJerry Jelinek  **/
ixgbe_i2c_start(struct ixgbe_hw * hw)222763b3bba8SJerry Jelinek static void ixgbe_i2c_start(struct ixgbe_hw *hw)
222873cd555cSBin Tu - Sun Microsystems - Beijing China {
2229dc0cb1cdSDale Ghent 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
223073cd555cSBin Tu - Sun Microsystems - Beijing China 
223173cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_i2c_start");
223273cd555cSBin Tu - Sun Microsystems - Beijing China 
2233dc0cb1cdSDale Ghent 	i2cctl |= IXGBE_I2C_BB_EN_BY_MAC(hw);
2234dc0cb1cdSDale Ghent 
223573cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Start condition must begin with data and clock high */
2236dc0cb1cdSDale Ghent 	ixgbe_set_i2c_data(hw, &i2cctl, 1);
223769b5a878SDan McDonald 	ixgbe_raise_i2c_clk(hw, &i2cctl);
223873cd555cSBin Tu - Sun Microsystems - Beijing China 
223973cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Setup time for start condition (4.7us) */
224073cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_SU_STA);
224173cd555cSBin Tu - Sun Microsystems - Beijing China 
2242dc0cb1cdSDale Ghent 	ixgbe_set_i2c_data(hw, &i2cctl, 0);
224373cd555cSBin Tu - Sun Microsystems - Beijing China 
224473cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Hold time for start condition (4us) */
224573cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_HD_STA);
224673cd555cSBin Tu - Sun Microsystems - Beijing China 
224773cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_lower_i2c_clk(hw, &i2cctl);
224873cd555cSBin Tu - Sun Microsystems - Beijing China 
224973cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Minimum low period of clock is 4.7 us */
225073cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_LOW);
225163b3bba8SJerry Jelinek 
225273cd555cSBin Tu - Sun Microsystems - Beijing China }
225373cd555cSBin Tu - Sun Microsystems - Beijing China 
225463b3bba8SJerry Jelinek /**
225563b3bba8SJerry Jelinek  *  ixgbe_i2c_stop - Sets I2C stop condition
225663b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
225773cd555cSBin Tu - Sun Microsystems - Beijing China  *
225863b3bba8SJerry Jelinek  *  Sets I2C stop condition (Low -> High on SDA while SCL is High)
2259dc0cb1cdSDale Ghent  *  Disables bit-bang mode and negates data output enable on X550
2260dc0cb1cdSDale Ghent  *  hardware.
226163b3bba8SJerry Jelinek  **/
ixgbe_i2c_stop(struct ixgbe_hw * hw)226263b3bba8SJerry Jelinek static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
226373cd555cSBin Tu - Sun Microsystems - Beijing China {
2264dc0cb1cdSDale Ghent 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2265dc0cb1cdSDale Ghent 	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
2266dc0cb1cdSDale Ghent 	u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
2267dc0cb1cdSDale Ghent 	u32 bb_en_bit = IXGBE_I2C_BB_EN_BY_MAC(hw);
226873cd555cSBin Tu - Sun Microsystems - Beijing China 
226973cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_i2c_stop");
227073cd555cSBin Tu - Sun Microsystems - Beijing China 
227173cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Stop condition must begin with data low and clock high */
2272dc0cb1cdSDale Ghent 	ixgbe_set_i2c_data(hw, &i2cctl, 0);
227369b5a878SDan McDonald 	ixgbe_raise_i2c_clk(hw, &i2cctl);
227473cd555cSBin Tu - Sun Microsystems - Beijing China 
227573cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Setup time for stop condition (4us) */
227673cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_SU_STO);
227773cd555cSBin Tu - Sun Microsystems - Beijing China 
2278dc0cb1cdSDale Ghent 	ixgbe_set_i2c_data(hw, &i2cctl, 1);
227973cd555cSBin Tu - Sun Microsystems - Beijing China 
228063b3bba8SJerry Jelinek 	/* bus free time between stop and start (4.7us)*/
228173cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_BUF);
2282dc0cb1cdSDale Ghent 
2283dc0cb1cdSDale Ghent 	if (bb_en_bit || data_oe_bit || clk_oe_bit) {
2284dc0cb1cdSDale Ghent 		i2cctl &= ~bb_en_bit;
2285dc0cb1cdSDale Ghent 		i2cctl |= data_oe_bit | clk_oe_bit;
2286dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
2287dc0cb1cdSDale Ghent 		IXGBE_WRITE_FLUSH(hw);
2288dc0cb1cdSDale Ghent 	}
228973cd555cSBin Tu - Sun Microsystems - Beijing China }
229073cd555cSBin Tu - Sun Microsystems - Beijing China 
229163b3bba8SJerry Jelinek /**
229263b3bba8SJerry Jelinek  *  ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C
229363b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
229463b3bba8SJerry Jelinek  *  @data: data byte to clock in
229573cd555cSBin Tu - Sun Microsystems - Beijing China  *
229663b3bba8SJerry Jelinek  *  Clocks in one byte data via I2C data/clock
229763b3bba8SJerry Jelinek  **/
ixgbe_clock_in_i2c_byte(struct ixgbe_hw * hw,u8 * data)229863b3bba8SJerry Jelinek static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
229973cd555cSBin Tu - Sun Microsystems - Beijing China {
2300dc0cb1cdSDale Ghent 	s32 i;
230173cd555cSBin Tu - Sun Microsystems - Beijing China 	bool bit = 0;
230273cd555cSBin Tu - Sun Microsystems - Beijing China 
230373cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_clock_in_i2c_byte");
230473cd555cSBin Tu - Sun Microsystems - Beijing China 
2305dc0cb1cdSDale Ghent 	*data = 0;
230673cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 7; i >= 0; i--) {
2307dc0cb1cdSDale Ghent 		ixgbe_clock_in_i2c_bit(hw, &bit);
230863b3bba8SJerry Jelinek 		*data |= bit << i;
230973cd555cSBin Tu - Sun Microsystems - Beijing China 	}
231073cd555cSBin Tu - Sun Microsystems - Beijing China 
2311dc0cb1cdSDale Ghent 	return IXGBE_SUCCESS;
231273cd555cSBin Tu - Sun Microsystems - Beijing China }
231373cd555cSBin Tu - Sun Microsystems - Beijing China 
231463b3bba8SJerry Jelinek /**
231563b3bba8SJerry Jelinek  *  ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C
231663b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
231763b3bba8SJerry Jelinek  *  @data: data byte clocked out
231873cd555cSBin Tu - Sun Microsystems - Beijing China  *
231963b3bba8SJerry Jelinek  *  Clocks out one byte data via I2C data/clock
232063b3bba8SJerry Jelinek  **/
ixgbe_clock_out_i2c_byte(struct ixgbe_hw * hw,u8 data)232163b3bba8SJerry Jelinek static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
232273cd555cSBin Tu - Sun Microsystems - Beijing China {
232373cd555cSBin Tu - Sun Microsystems - Beijing China 	s32 status = IXGBE_SUCCESS;
232473cd555cSBin Tu - Sun Microsystems - Beijing China 	s32 i;
232573cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 i2cctl;
2326dc0cb1cdSDale Ghent 	bool bit;
232773cd555cSBin Tu - Sun Microsystems - Beijing China 
232873cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_clock_out_i2c_byte");
232973cd555cSBin Tu - Sun Microsystems - Beijing China 
233073cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 7; i >= 0; i--) {
233173cd555cSBin Tu - Sun Microsystems - Beijing China 		bit = (data >> i) & 0x1;
233273cd555cSBin Tu - Sun Microsystems - Beijing China 		status = ixgbe_clock_out_i2c_bit(hw, bit);
233373cd555cSBin Tu - Sun Microsystems - Beijing China 
233473cd555cSBin Tu - Sun Microsystems - Beijing China 		if (status != IXGBE_SUCCESS)
233573cd555cSBin Tu - Sun Microsystems - Beijing China 			break;
233673cd555cSBin Tu - Sun Microsystems - Beijing China 	}
233773cd555cSBin Tu - Sun Microsystems - Beijing China 
233873cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Release SDA line (set high) */
2339dc0cb1cdSDale Ghent 	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2340dc0cb1cdSDale Ghent 	i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
2341dc0cb1cdSDale Ghent 	i2cctl |= IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
2342dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
234369b5a878SDan McDonald 	IXGBE_WRITE_FLUSH(hw);
234473cd555cSBin Tu - Sun Microsystems - Beijing China 
234563b3bba8SJerry Jelinek 	return status;
234673cd555cSBin Tu - Sun Microsystems - Beijing China }
234773cd555cSBin Tu - Sun Microsystems - Beijing China 
234863b3bba8SJerry Jelinek /**
234963b3bba8SJerry Jelinek  *  ixgbe_get_i2c_ack - Polls for I2C ACK
235063b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
235173cd555cSBin Tu - Sun Microsystems - Beijing China  *
235263b3bba8SJerry Jelinek  *  Clocks in/out one bit via I2C data/clock
235363b3bba8SJerry Jelinek  **/
ixgbe_get_i2c_ack(struct ixgbe_hw * hw)235463b3bba8SJerry Jelinek static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
235573cd555cSBin Tu - Sun Microsystems - Beijing China {
2356dc0cb1cdSDale Ghent 	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
235769b5a878SDan McDonald 	s32 status = IXGBE_SUCCESS;
235873cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 i = 0;
2359dc0cb1cdSDale Ghent 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
236073cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 timeout = 10;
236173cd555cSBin Tu - Sun Microsystems - Beijing China 	bool ack = 1;
236273cd555cSBin Tu - Sun Microsystems - Beijing China 
236373cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_i2c_ack");
236473cd555cSBin Tu - Sun Microsystems - Beijing China 
2365dc0cb1cdSDale Ghent 	if (data_oe_bit) {
2366dc0cb1cdSDale Ghent 		i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
2367dc0cb1cdSDale Ghent 		i2cctl |= data_oe_bit;
2368dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
2369dc0cb1cdSDale Ghent 		IXGBE_WRITE_FLUSH(hw);
2370dc0cb1cdSDale Ghent 	}
237169b5a878SDan McDonald 	ixgbe_raise_i2c_clk(hw, &i2cctl);
237273cd555cSBin Tu - Sun Microsystems - Beijing China 
237373cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Minimum high period of clock is 4us */
237473cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_HIGH);
237573cd555cSBin Tu - Sun Microsystems - Beijing China 
237663b3bba8SJerry Jelinek 	/* Poll for ACK.  Note that ACK in I2C spec is
237763b3bba8SJerry Jelinek 	 * transition from 1 to 0 */
237873cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < timeout; i++) {
2379dc0cb1cdSDale Ghent 		i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2380dc0cb1cdSDale Ghent 		ack = ixgbe_get_i2c_data(hw, &i2cctl);
238173cd555cSBin Tu - Sun Microsystems - Beijing China 
238273cd555cSBin Tu - Sun Microsystems - Beijing China 		usec_delay(1);
2383dc0cb1cdSDale Ghent 		if (!ack)
238473cd555cSBin Tu - Sun Microsystems - Beijing China 			break;
238573cd555cSBin Tu - Sun Microsystems - Beijing China 	}
238673cd555cSBin Tu - Sun Microsystems - Beijing China 
2387dc0cb1cdSDale Ghent 	if (ack) {
238873cd555cSBin Tu - Sun Microsystems - Beijing China 		DEBUGOUT("I2C ack was not received.\n");
238973cd555cSBin Tu - Sun Microsystems - Beijing China 		status = IXGBE_ERR_I2C;
239073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
239173cd555cSBin Tu - Sun Microsystems - Beijing China 
239273cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_lower_i2c_clk(hw, &i2cctl);
239373cd555cSBin Tu - Sun Microsystems - Beijing China 
239473cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Minimum low period of clock is 4.7 us */
239573cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_LOW);
239673cd555cSBin Tu - Sun Microsystems - Beijing China 
239763b3bba8SJerry Jelinek 	return status;
239873cd555cSBin Tu - Sun Microsystems - Beijing China }
239973cd555cSBin Tu - Sun Microsystems - Beijing China 
240063b3bba8SJerry Jelinek /**
240163b3bba8SJerry Jelinek  *  ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
240263b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
240363b3bba8SJerry Jelinek  *  @data: read data value
240473cd555cSBin Tu - Sun Microsystems - Beijing China  *
240563b3bba8SJerry Jelinek  *  Clocks in one bit via I2C data/clock
240663b3bba8SJerry Jelinek  **/
ixgbe_clock_in_i2c_bit(struct ixgbe_hw * hw,bool * data)240763b3bba8SJerry Jelinek static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
240873cd555cSBin Tu - Sun Microsystems - Beijing China {
2409dc0cb1cdSDale Ghent 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2410dc0cb1cdSDale Ghent 	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
241173cd555cSBin Tu - Sun Microsystems - Beijing China 
24123cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_clock_in_i2c_bit");
24133cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
2414dc0cb1cdSDale Ghent 	if (data_oe_bit) {
2415dc0cb1cdSDale Ghent 		i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
2416dc0cb1cdSDale Ghent 		i2cctl |= data_oe_bit;
2417dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
2418dc0cb1cdSDale Ghent 		IXGBE_WRITE_FLUSH(hw);
2419dc0cb1cdSDale Ghent 	}
242069b5a878SDan McDonald 	ixgbe_raise_i2c_clk(hw, &i2cctl);
242173cd555cSBin Tu - Sun Microsystems - Beijing China 
242273cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Minimum high period of clock is 4us */
242373cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_HIGH);
242473cd555cSBin Tu - Sun Microsystems - Beijing China 
2425dc0cb1cdSDale Ghent 	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2426dc0cb1cdSDale Ghent 	*data = ixgbe_get_i2c_data(hw, &i2cctl);
242773cd555cSBin Tu - Sun Microsystems - Beijing China 
242873cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_lower_i2c_clk(hw, &i2cctl);
242973cd555cSBin Tu - Sun Microsystems - Beijing China 
243073cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Minimum low period of clock is 4.7 us */
243173cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_LOW);
243273cd555cSBin Tu - Sun Microsystems - Beijing China 
243369b5a878SDan McDonald 	return IXGBE_SUCCESS;
243473cd555cSBin Tu - Sun Microsystems - Beijing China }
243573cd555cSBin Tu - Sun Microsystems - Beijing China 
243663b3bba8SJerry Jelinek /**
243763b3bba8SJerry Jelinek  *  ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
243863b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
243963b3bba8SJerry Jelinek  *  @data: data value to write
244073cd555cSBin Tu - Sun Microsystems - Beijing China  *
244163b3bba8SJerry Jelinek  *  Clocks out one bit via I2C data/clock
244263b3bba8SJerry Jelinek  **/
ixgbe_clock_out_i2c_bit(struct ixgbe_hw * hw,bool data)244363b3bba8SJerry Jelinek static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
244473cd555cSBin Tu - Sun Microsystems - Beijing China {
244573cd555cSBin Tu - Sun Microsystems - Beijing China 	s32 status;
2446dc0cb1cdSDale Ghent 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
244773cd555cSBin Tu - Sun Microsystems - Beijing China 
24483cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_clock_out_i2c_bit");
24493cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
245073cd555cSBin Tu - Sun Microsystems - Beijing China 	status = ixgbe_set_i2c_data(hw, &i2cctl, data);
245173cd555cSBin Tu - Sun Microsystems - Beijing China 	if (status == IXGBE_SUCCESS) {
245269b5a878SDan McDonald 		ixgbe_raise_i2c_clk(hw, &i2cctl);
245373cd555cSBin Tu - Sun Microsystems - Beijing China 
245473cd555cSBin Tu - Sun Microsystems - Beijing China 		/* Minimum high period of clock is 4us */
245573cd555cSBin Tu - Sun Microsystems - Beijing China 		usec_delay(IXGBE_I2C_T_HIGH);
245673cd555cSBin Tu - Sun Microsystems - Beijing China 
245773cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_lower_i2c_clk(hw, &i2cctl);
245873cd555cSBin Tu - Sun Microsystems - Beijing China 
245963b3bba8SJerry Jelinek 		/* Minimum low period of clock is 4.7 us.
246073cd555cSBin Tu - Sun Microsystems - Beijing China 		 * This also takes care of the data hold time.
246173cd555cSBin Tu - Sun Microsystems - Beijing China 		 */
246273cd555cSBin Tu - Sun Microsystems - Beijing China 		usec_delay(IXGBE_I2C_T_LOW);
246373cd555cSBin Tu - Sun Microsystems - Beijing China 	} else {
246473cd555cSBin Tu - Sun Microsystems - Beijing China 		status = IXGBE_ERR_I2C;
2465dc0cb1cdSDale Ghent 		ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
2466dc0cb1cdSDale Ghent 			     "I2C data was not set to %X\n", data);
246773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
246873cd555cSBin Tu - Sun Microsystems - Beijing China 
246963b3bba8SJerry Jelinek 	return status;
247073cd555cSBin Tu - Sun Microsystems - Beijing China }
2471dc0cb1cdSDale Ghent 
247263b3bba8SJerry Jelinek /**
247363b3bba8SJerry Jelinek  *  ixgbe_raise_i2c_clk - Raises the I2C SCL clock
247463b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
247563b3bba8SJerry Jelinek  *  @i2cctl: Current value of I2CCTL register
247673cd555cSBin Tu - Sun Microsystems - Beijing China  *
247763b3bba8SJerry Jelinek  *  Raises the I2C clock line '0'->'1'
2478dc0cb1cdSDale Ghent  *  Negates the I2C clock output enable on X550 hardware.
247963b3bba8SJerry Jelinek  **/
ixgbe_raise_i2c_clk(struct ixgbe_hw * hw,u32 * i2cctl)248069b5a878SDan McDonald static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
248173cd555cSBin Tu - Sun Microsystems - Beijing China {
2482dc0cb1cdSDale Ghent 	u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
248369b5a878SDan McDonald 	u32 i = 0;
248469b5a878SDan McDonald 	u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT;
248569b5a878SDan McDonald 	u32 i2cctl_r = 0;
248673cd555cSBin Tu - Sun Microsystems - Beijing China 
24873cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_raise_i2c_clk");
24883cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
2489dc0cb1cdSDale Ghent 	if (clk_oe_bit) {
2490dc0cb1cdSDale Ghent 		*i2cctl |= clk_oe_bit;
2491dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
2492dc0cb1cdSDale Ghent 	}
2493dc0cb1cdSDale Ghent 
249469b5a878SDan McDonald 	for (i = 0; i < timeout; i++) {
2495dc0cb1cdSDale Ghent 		*i2cctl |= IXGBE_I2C_CLK_OUT_BY_MAC(hw);
249673cd555cSBin Tu - Sun Microsystems - Beijing China 
2497dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
249869b5a878SDan McDonald 		IXGBE_WRITE_FLUSH(hw);
249969b5a878SDan McDonald 		/* SCL rise time (1000ns) */
250069b5a878SDan McDonald 		usec_delay(IXGBE_I2C_T_RISE);
250173cd555cSBin Tu - Sun Microsystems - Beijing China 
2502dc0cb1cdSDale Ghent 		i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2503dc0cb1cdSDale Ghent 		if (i2cctl_r & IXGBE_I2C_CLK_IN_BY_MAC(hw))
250469b5a878SDan McDonald 			break;
250569b5a878SDan McDonald 	}
250673cd555cSBin Tu - Sun Microsystems - Beijing China }
250773cd555cSBin Tu - Sun Microsystems - Beijing China 
250863b3bba8SJerry Jelinek /**
250963b3bba8SJerry Jelinek  *  ixgbe_lower_i2c_clk - Lowers the I2C SCL clock
251063b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
251163b3bba8SJerry Jelinek  *  @i2cctl: Current value of I2CCTL register
251273cd555cSBin Tu - Sun Microsystems - Beijing China  *
251363b3bba8SJerry Jelinek  *  Lowers the I2C clock line '1'->'0'
2514dc0cb1cdSDale Ghent  *  Asserts the I2C clock output enable on X550 hardware.
251563b3bba8SJerry Jelinek  **/
ixgbe_lower_i2c_clk(struct ixgbe_hw * hw,u32 * i2cctl)251663b3bba8SJerry Jelinek static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
251773cd555cSBin Tu - Sun Microsystems - Beijing China {
25183cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_lower_i2c_clk");
25193cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
2520dc0cb1cdSDale Ghent 	*i2cctl &= ~(IXGBE_I2C_CLK_OUT_BY_MAC(hw));
2521dc0cb1cdSDale Ghent 	*i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw);
252273cd555cSBin Tu - Sun Microsystems - Beijing China 
2523dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
252469b5a878SDan McDonald 	IXGBE_WRITE_FLUSH(hw);
252573cd555cSBin Tu - Sun Microsystems - Beijing China 
252673cd555cSBin Tu - Sun Microsystems - Beijing China 	/* SCL fall time (300ns) */
252773cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_FALL);
252873cd555cSBin Tu - Sun Microsystems - Beijing China }
252973cd555cSBin Tu - Sun Microsystems - Beijing China 
253063b3bba8SJerry Jelinek /**
253163b3bba8SJerry Jelinek  *  ixgbe_set_i2c_data - Sets the I2C data bit
253263b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
253363b3bba8SJerry Jelinek  *  @i2cctl: Current value of I2CCTL register
253463b3bba8SJerry Jelinek  *  @data: I2C data value (0 or 1) to set
253573cd555cSBin Tu - Sun Microsystems - Beijing China  *
253663b3bba8SJerry Jelinek  *  Sets the I2C data bit
2537dc0cb1cdSDale Ghent  *  Asserts the I2C data output enable on X550 hardware.
253863b3bba8SJerry Jelinek  **/
ixgbe_set_i2c_data(struct ixgbe_hw * hw,u32 * i2cctl,bool data)253963b3bba8SJerry Jelinek static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
254073cd555cSBin Tu - Sun Microsystems - Beijing China {
2541dc0cb1cdSDale Ghent 	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
254273cd555cSBin Tu - Sun Microsystems - Beijing China 	s32 status = IXGBE_SUCCESS;
254373cd555cSBin Tu - Sun Microsystems - Beijing China 
25443cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_set_i2c_data");
25453cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
254673cd555cSBin Tu - Sun Microsystems - Beijing China 	if (data)
2547dc0cb1cdSDale Ghent 		*i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
254873cd555cSBin Tu - Sun Microsystems - Beijing China 	else
2549dc0cb1cdSDale Ghent 		*i2cctl &= ~(IXGBE_I2C_DATA_OUT_BY_MAC(hw));
2550dc0cb1cdSDale Ghent 	*i2cctl &= ~data_oe_bit;
255173cd555cSBin Tu - Sun Microsystems - Beijing China 
2552dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
255369b5a878SDan McDonald 	IXGBE_WRITE_FLUSH(hw);
255473cd555cSBin Tu - Sun Microsystems - Beijing China 
255573cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
255673cd555cSBin Tu - Sun Microsystems - Beijing China 	usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
255773cd555cSBin Tu - Sun Microsystems - Beijing China 
2558dc0cb1cdSDale Ghent 	if (!data)	/* Can't verify data in this case */
2559dc0cb1cdSDale Ghent 		return IXGBE_SUCCESS;
2560dc0cb1cdSDale Ghent 	if (data_oe_bit) {
2561dc0cb1cdSDale Ghent 		*i2cctl |= data_oe_bit;
2562dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
2563dc0cb1cdSDale Ghent 		IXGBE_WRITE_FLUSH(hw);
2564dc0cb1cdSDale Ghent 	}
2565dc0cb1cdSDale Ghent 
256673cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Verify data was set correctly */
2567dc0cb1cdSDale Ghent 	*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
2568dc0cb1cdSDale Ghent 	if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
256973cd555cSBin Tu - Sun Microsystems - Beijing China 		status = IXGBE_ERR_I2C;
2570dc0cb1cdSDale Ghent 		ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
2571dc0cb1cdSDale Ghent 			     "Error - I2C data was not set to %X.\n",
2572dc0cb1cdSDale Ghent 			     data);
257373cd555cSBin Tu - Sun Microsystems - Beijing China 	}
257473cd555cSBin Tu - Sun Microsystems - Beijing China 
257563b3bba8SJerry Jelinek 	return status;
257673cd555cSBin Tu - Sun Microsystems - Beijing China }
257773cd555cSBin Tu - Sun Microsystems - Beijing China 
257863b3bba8SJerry Jelinek /**
257963b3bba8SJerry Jelinek  *  ixgbe_get_i2c_data - Reads the I2C SDA data bit
258063b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
258163b3bba8SJerry Jelinek  *  @i2cctl: Current value of I2CCTL register
258273cd555cSBin Tu - Sun Microsystems - Beijing China  *
258363b3bba8SJerry Jelinek  *  Returns the I2C data bit value
2584dc0cb1cdSDale Ghent  *  Negates the I2C data output enable on X550 hardware.
258563b3bba8SJerry Jelinek  **/
ixgbe_get_i2c_data(struct ixgbe_hw * hw,u32 * i2cctl)2586dc0cb1cdSDale Ghent static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
258773cd555cSBin Tu - Sun Microsystems - Beijing China {
2588dc0cb1cdSDale Ghent 	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
258973cd555cSBin Tu - Sun Microsystems - Beijing China 	bool data;
2590*48ed61a7SRobert Mustacchi 	UNREFERENCED_1PARAMETER(hw);
259173cd555cSBin Tu - Sun Microsystems - Beijing China 
25923cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_get_i2c_data");
25933cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 
2594dc0cb1cdSDale Ghent 	if (data_oe_bit) {
2595dc0cb1cdSDale Ghent 		*i2cctl |= data_oe_bit;
2596dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
2597dc0cb1cdSDale Ghent 		IXGBE_WRITE_FLUSH(hw);
2598dc0cb1cdSDale Ghent 		usec_delay(IXGBE_I2C_T_FALL);
2599dc0cb1cdSDale Ghent 	}
2600dc0cb1cdSDale Ghent 
2601dc0cb1cdSDale Ghent 	if (*i2cctl & IXGBE_I2C_DATA_IN_BY_MAC(hw))
260273cd555cSBin Tu - Sun Microsystems - Beijing China 		data = 1;
260373cd555cSBin Tu - Sun Microsystems - Beijing China 	else
260473cd555cSBin Tu - Sun Microsystems - Beijing China 		data = 0;
260573cd555cSBin Tu - Sun Microsystems - Beijing China 
260663b3bba8SJerry Jelinek 	return data;
260773cd555cSBin Tu - Sun Microsystems - Beijing China }
260873cd555cSBin Tu - Sun Microsystems - Beijing China 
260963b3bba8SJerry Jelinek /**
261063b3bba8SJerry Jelinek  *  ixgbe_i2c_bus_clear - Clears the I2C bus
261163b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
261273cd555cSBin Tu - Sun Microsystems - Beijing China  *
261363b3bba8SJerry Jelinek  *  Clears the I2C bus by sending nine clock pulses.
261463b3bba8SJerry Jelinek  *  Used when data line is stuck low.
261563b3bba8SJerry Jelinek  **/
ixgbe_i2c_bus_clear(struct ixgbe_hw * hw)261663b3bba8SJerry Jelinek void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
261773cd555cSBin Tu - Sun Microsystems - Beijing China {
2618dc0cb1cdSDale Ghent 	u32 i2cctl;
261973cd555cSBin Tu - Sun Microsystems - Beijing China 	u32 i;
262073cd555cSBin Tu - Sun Microsystems - Beijing China 
262173cd555cSBin Tu - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_i2c_bus_clear");
262273cd555cSBin Tu - Sun Microsystems - Beijing China 
262373cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_i2c_start(hw);
2624dc0cb1cdSDale Ghent 	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
262573cd555cSBin Tu - Sun Microsystems - Beijing China 
2626dc0cb1cdSDale Ghent 	ixgbe_set_i2c_data(hw, &i2cctl, 1);
262773cd555cSBin Tu - Sun Microsystems - Beijing China 
262873cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < 9; i++) {
262969b5a878SDan McDonald 		ixgbe_raise_i2c_clk(hw, &i2cctl);
263073cd555cSBin Tu - Sun Microsystems - Beijing China 
263173cd555cSBin Tu - Sun Microsystems - Beijing China 		/* Min high period of clock is 4us */
263273cd555cSBin Tu - Sun Microsystems - Beijing China 		usec_delay(IXGBE_I2C_T_HIGH);
263373cd555cSBin Tu - Sun Microsystems - Beijing China 
263473cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_lower_i2c_clk(hw, &i2cctl);
263573cd555cSBin Tu - Sun Microsystems - Beijing China 
263663b3bba8SJerry Jelinek 		/* Min low period of clock is 4.7us*/
263773cd555cSBin Tu - Sun Microsystems - Beijing China 		usec_delay(IXGBE_I2C_T_LOW);
263873cd555cSBin Tu - Sun Microsystems - Beijing China 	}
263973cd555cSBin Tu - Sun Microsystems - Beijing China 
264073cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_i2c_start(hw);
264173cd555cSBin Tu - Sun Microsystems - Beijing China 
264273cd555cSBin Tu - Sun Microsystems - Beijing China 	/* Put the i2c bus back to default state */
264373cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_i2c_stop(hw);
264473cd555cSBin Tu - Sun Microsystems - Beijing China }
26455b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
264663b3bba8SJerry Jelinek /**
264769b5a878SDan McDonald  *  ixgbe_tn_check_overtemp - Checks if an overtemp occurred.
264863b3bba8SJerry Jelinek  *  @hw: pointer to hardware structure
26495b6dd21fSchenlu chen - Sun Microsystems - Beijing China  *
265063b3bba8SJerry Jelinek  *  Checks if the LASI temp alarm status was triggered due to overtemp
265163b3bba8SJerry Jelinek  **/
ixgbe_tn_check_overtemp(struct ixgbe_hw * hw)265263b3bba8SJerry Jelinek s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
26535b6dd21fSchenlu chen - Sun Microsystems - Beijing China {
26545b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	s32 status = IXGBE_SUCCESS;
26555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	u16 phy_data = 0;
26565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	DEBUGFUNC("ixgbe_tn_check_overtemp");
26585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
26605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
26615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* Check that the LASI temp alarm status was triggered */
26635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
266463b3bba8SJerry Jelinek 			     IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_data);
26655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
26675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
26685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26695b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	status = IXGBE_ERR_OVERTEMP;
2670dc0cb1cdSDale Ghent 	ERROR_REPORT1(IXGBE_ERROR_CAUTION, "Device over temperature");
26715b6dd21fSchenlu chen - Sun Microsystems - Beijing China out:
267263b3bba8SJerry Jelinek 	return status;
26735b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
2674dc0cb1cdSDale Ghent 
2675dc0cb1cdSDale Ghent /**
2676dc0cb1cdSDale Ghent  * ixgbe_set_copper_phy_power - Control power for copper phy
2677dc0cb1cdSDale Ghent  * @hw: pointer to hardware structure
2678dc0cb1cdSDale Ghent  * @on: TRUE for on, FALSE for off
2679dc0cb1cdSDale Ghent  */
ixgbe_set_copper_phy_power(struct ixgbe_hw * hw,bool on)2680dc0cb1cdSDale Ghent s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on)
2681dc0cb1cdSDale Ghent {
2682dc0cb1cdSDale Ghent 	u32 status;
2683dc0cb1cdSDale Ghent 	u16 reg;
2684dc0cb1cdSDale Ghent 
2685dc0cb1cdSDale Ghent 	if (!on && ixgbe_mng_present(hw))
2686dc0cb1cdSDale Ghent 		return 0;
2687dc0cb1cdSDale Ghent 
2688dc0cb1cdSDale Ghent 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
2689dc0cb1cdSDale Ghent 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2690dc0cb1cdSDale Ghent 				      &reg);
2691dc0cb1cdSDale Ghent 	if (status)
2692dc0cb1cdSDale Ghent 		return status;
2693dc0cb1cdSDale Ghent 
2694dc0cb1cdSDale Ghent 	if (on) {
2695dc0cb1cdSDale Ghent 		reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
2696dc0cb1cdSDale Ghent 	} else {
2697dc0cb1cdSDale Ghent 		if (ixgbe_check_reset_blocked(hw))
2698dc0cb1cdSDale Ghent 			return 0;
2699dc0cb1cdSDale Ghent 		reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
2700dc0cb1cdSDale Ghent 	}
2701dc0cb1cdSDale Ghent 
2702dc0cb1cdSDale Ghent 	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
2703dc0cb1cdSDale Ghent 				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2704dc0cb1cdSDale Ghent 				       reg);
2705dc0cb1cdSDale Ghent 	return status;
2706dc0cb1cdSDale Ghent }
2707