xref: /onnv-gate/usr/src/uts/common/io/igb/igb_phy.c (revision 11155:1d6534291026)
15779Sxy150489 /*
25779Sxy150489  * CDDL HEADER START
35779Sxy150489  *
48571SChenlu.Chen@Sun.COM  * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
55779Sxy150489  * The contents of this file are subject to the terms of the
65779Sxy150489  * Common Development and Distribution License (the "License").
75779Sxy150489  * You may not use this file except in compliance with the License.
85779Sxy150489  *
95779Sxy150489  * You can obtain a copy of the license at:
105779Sxy150489  *	http://www.opensolaris.org/os/licensing.
115779Sxy150489  * See the License for the specific language governing permissions
125779Sxy150489  * and limitations under the License.
135779Sxy150489  *
145779Sxy150489  * When using or redistributing this file, you may do so under the
155779Sxy150489  * License only. No other modification of this header is permitted.
165779Sxy150489  *
175779Sxy150489  * If applicable, add the following below this CDDL HEADER, with the
185779Sxy150489  * fields enclosed by brackets "[]" replaced with your own identifying
195779Sxy150489  * information: Portions Copyright [yyyy] [name of copyright owner]
205779Sxy150489  *
215779Sxy150489  * CDDL HEADER END
225779Sxy150489  */
235779Sxy150489 
245779Sxy150489 /*
258571SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
265779Sxy150489  * Use is subject to license terms of the CDDL.
275779Sxy150489  */
285779Sxy150489 
29*11155SJason.Xu@Sun.COM /* IntelVersion: 1.155 scm_100809_154340 */
305779Sxy150489 
315779Sxy150489 #include "igb_api.h"
325779Sxy150489 
33*11155SJason.Xu@Sun.COM static s32 e1000_copper_link_autoneg(struct e1000_hw *hw);
348571SChenlu.Chen@Sun.COM static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
355779Sxy150489 
365779Sxy150489 /* Cable length tables */
375779Sxy150489 static const u16 e1000_m88_cable_length_table[] =
385779Sxy150489 	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
395779Sxy150489 
405779Sxy150489 #define	M88E1000_CABLE_LENGTH_TABLE_SIZE \
415779Sxy150489 	(sizeof (e1000_m88_cable_length_table) / \
425779Sxy150489 	sizeof (e1000_m88_cable_length_table[0]))
435779Sxy150489 
445779Sxy150489 static const u16 e1000_igp_2_cable_length_table[] =
455779Sxy150489 	{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
465779Sxy150489 	0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
475779Sxy150489 	6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
485779Sxy150489 	21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
495779Sxy150489 	40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
505779Sxy150489 	60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
515779Sxy150489 	83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
525779Sxy150489 	104, 109, 114, 118, 121, 124};
535779Sxy150489 
545779Sxy150489 #define	IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
555779Sxy150489 	(sizeof (e1000_igp_2_cable_length_table) / \
565779Sxy150489 	sizeof (e1000_igp_2_cable_length_table[0]))
575779Sxy150489 
585779Sxy150489 /*
598571SChenlu.Chen@Sun.COM  * e1000_init_phy_ops_generic - Initialize PHY function pointers
608571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
618571SChenlu.Chen@Sun.COM  *
628571SChenlu.Chen@Sun.COM  * Setups up the function pointers to no-op functions
638571SChenlu.Chen@Sun.COM  */
648571SChenlu.Chen@Sun.COM void
658571SChenlu.Chen@Sun.COM e1000_init_phy_ops_generic(struct e1000_hw *hw)
668571SChenlu.Chen@Sun.COM {
678571SChenlu.Chen@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
688571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_init_phy_ops_generic");
698571SChenlu.Chen@Sun.COM 
708571SChenlu.Chen@Sun.COM 	/* Initialize function pointers */
718571SChenlu.Chen@Sun.COM 	phy->ops.init_params = e1000_null_ops_generic;
728571SChenlu.Chen@Sun.COM 	phy->ops.acquire = e1000_null_ops_generic;
738571SChenlu.Chen@Sun.COM 	phy->ops.check_polarity = e1000_null_ops_generic;
748571SChenlu.Chen@Sun.COM 	phy->ops.check_reset_block = e1000_null_ops_generic;
758571SChenlu.Chen@Sun.COM 	phy->ops.commit = e1000_null_ops_generic;
768571SChenlu.Chen@Sun.COM 	phy->ops.force_speed_duplex = e1000_null_ops_generic;
778571SChenlu.Chen@Sun.COM 	phy->ops.get_cfg_done = e1000_null_ops_generic;
788571SChenlu.Chen@Sun.COM 	phy->ops.get_cable_length = e1000_null_ops_generic;
798571SChenlu.Chen@Sun.COM 	phy->ops.get_info = e1000_null_ops_generic;
808571SChenlu.Chen@Sun.COM 	phy->ops.read_reg = e1000_null_read_reg;
81*11155SJason.Xu@Sun.COM 	phy->ops.read_reg_locked = e1000_null_read_reg;
828571SChenlu.Chen@Sun.COM 	phy->ops.release = e1000_null_phy_generic;
838571SChenlu.Chen@Sun.COM 	phy->ops.reset = e1000_null_ops_generic;
848571SChenlu.Chen@Sun.COM 	phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
858571SChenlu.Chen@Sun.COM 	phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
868571SChenlu.Chen@Sun.COM 	phy->ops.write_reg = e1000_null_write_reg;
87*11155SJason.Xu@Sun.COM 	phy->ops.write_reg_locked = e1000_null_write_reg;
888571SChenlu.Chen@Sun.COM 	phy->ops.power_up = e1000_null_phy_generic;
898571SChenlu.Chen@Sun.COM 	phy->ops.power_down = e1000_null_phy_generic;
908571SChenlu.Chen@Sun.COM }
918571SChenlu.Chen@Sun.COM 
928571SChenlu.Chen@Sun.COM /*
938571SChenlu.Chen@Sun.COM  * e1000_null_read_reg - No-op function, return 0
948571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
958571SChenlu.Chen@Sun.COM  */
968571SChenlu.Chen@Sun.COM s32
978571SChenlu.Chen@Sun.COM e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data)
988571SChenlu.Chen@Sun.COM {
998571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_read_reg");
1008571SChenlu.Chen@Sun.COM 	UNREFERENCED_3PARAMETER(hw, offset, data);
1018571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
1028571SChenlu.Chen@Sun.COM }
1038571SChenlu.Chen@Sun.COM 
1048571SChenlu.Chen@Sun.COM /*
1058571SChenlu.Chen@Sun.COM  * e1000_null_phy_generic - No-op function, return void
1068571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
1078571SChenlu.Chen@Sun.COM  */
1088571SChenlu.Chen@Sun.COM void
1098571SChenlu.Chen@Sun.COM e1000_null_phy_generic(struct e1000_hw *hw)
1108571SChenlu.Chen@Sun.COM {
1118571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_phy_generic");
1128571SChenlu.Chen@Sun.COM 	UNREFERENCED_1PARAMETER(hw);
1138571SChenlu.Chen@Sun.COM }
1148571SChenlu.Chen@Sun.COM 
1158571SChenlu.Chen@Sun.COM /*
1168571SChenlu.Chen@Sun.COM  * e1000_null_lplu_state - No-op function, return 0
1178571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
1188571SChenlu.Chen@Sun.COM  */
1198571SChenlu.Chen@Sun.COM s32
1208571SChenlu.Chen@Sun.COM e1000_null_lplu_state(struct e1000_hw *hw, bool active)
1218571SChenlu.Chen@Sun.COM {
1228571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_lplu_state");
1238571SChenlu.Chen@Sun.COM 	UNREFERENCED_2PARAMETER(hw, active);
1248571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
1258571SChenlu.Chen@Sun.COM }
1268571SChenlu.Chen@Sun.COM 
1278571SChenlu.Chen@Sun.COM /*
1288571SChenlu.Chen@Sun.COM  * e1000_null_write_reg - No-op function, return 0
1298571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
1308571SChenlu.Chen@Sun.COM  */
1318571SChenlu.Chen@Sun.COM s32
1328571SChenlu.Chen@Sun.COM e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
1338571SChenlu.Chen@Sun.COM {
1348571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_write_reg");
1358571SChenlu.Chen@Sun.COM 	UNREFERENCED_3PARAMETER(hw, offset, data);
1368571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
1378571SChenlu.Chen@Sun.COM }
1388571SChenlu.Chen@Sun.COM 
1398571SChenlu.Chen@Sun.COM /*
1405779Sxy150489  * e1000_check_reset_block_generic - Check if PHY reset is blocked
1415779Sxy150489  * @hw: pointer to the HW structure
1425779Sxy150489  *
1435779Sxy150489  * Read the PHY management control register and check whether a PHY reset
1445779Sxy150489  * is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
1455779Sxy150489  * return E1000_BLK_PHY_RESET (12).
1465779Sxy150489  */
1475779Sxy150489 s32
1485779Sxy150489 e1000_check_reset_block_generic(struct e1000_hw *hw)
1495779Sxy150489 {
1505779Sxy150489 	u32 manc;
1515779Sxy150489 
1525779Sxy150489 	DEBUGFUNC("e1000_check_reset_block");
1535779Sxy150489 
1545779Sxy150489 	manc = E1000_READ_REG(hw, E1000_MANC);
1555779Sxy150489 
1565779Sxy150489 	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
1575779Sxy150489 	    E1000_BLK_PHY_RESET : E1000_SUCCESS;
1585779Sxy150489 }
1595779Sxy150489 
1605779Sxy150489 /*
1615779Sxy150489  * e1000_get_phy_id - Retrieve the PHY ID and revision
1625779Sxy150489  * @hw: pointer to the HW structure
1635779Sxy150489  *
1645779Sxy150489  * Reads the PHY registers and stores the PHY ID and possibly the PHY
1655779Sxy150489  * revision in the hardware structure.
1665779Sxy150489  */
1675779Sxy150489 s32
1685779Sxy150489 e1000_get_phy_id(struct e1000_hw *hw)
1695779Sxy150489 {
1705779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
1715779Sxy150489 	s32 ret_val = E1000_SUCCESS;
1725779Sxy150489 	u16 phy_id;
1735779Sxy150489 
1745779Sxy150489 	DEBUGFUNC("e1000_get_phy_id");
1755779Sxy150489 
1768571SChenlu.Chen@Sun.COM 	if (!(phy->ops.read_reg))
1778571SChenlu.Chen@Sun.COM 		goto out;
1788571SChenlu.Chen@Sun.COM 
1798571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
1805779Sxy150489 	if (ret_val)
1815779Sxy150489 		goto out;
1825779Sxy150489 
1835779Sxy150489 	phy->id = (u32)(phy_id << 16);
1845779Sxy150489 	usec_delay(20);
1858571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
1865779Sxy150489 	if (ret_val)
1875779Sxy150489 		goto out;
1885779Sxy150489 
1895779Sxy150489 	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
1905779Sxy150489 	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
1915779Sxy150489 
1925779Sxy150489 out:
1935779Sxy150489 	return (ret_val);
1945779Sxy150489 }
1955779Sxy150489 
1965779Sxy150489 /*
1975779Sxy150489  * e1000_phy_reset_dsp_generic - Reset PHY DSP
1985779Sxy150489  * @hw: pointer to the HW structure
1995779Sxy150489  *
2005779Sxy150489  * Reset the digital signal processor.
2015779Sxy150489  */
2025779Sxy150489 s32
2035779Sxy150489 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
2045779Sxy150489 {
2058571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
2065779Sxy150489 
2075779Sxy150489 	DEBUGFUNC("e1000_phy_reset_dsp_generic");
2085779Sxy150489 
2098571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.write_reg))
2108571SChenlu.Chen@Sun.COM 		goto out;
2118571SChenlu.Chen@Sun.COM 
2128571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
2135779Sxy150489 	if (ret_val)
2145779Sxy150489 		goto out;
2155779Sxy150489 
2168571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
2175779Sxy150489 
2185779Sxy150489 out:
2195779Sxy150489 	return (ret_val);
2205779Sxy150489 }
2215779Sxy150489 
2225779Sxy150489 /*
2235779Sxy150489  * e1000_read_phy_reg_mdic - Read MDI control register
2245779Sxy150489  * @hw: pointer to the HW structure
2255779Sxy150489  * @offset: register offset to be read
2265779Sxy150489  * @data: pointer to the read data
2275779Sxy150489  *
2288571SChenlu.Chen@Sun.COM  * Reads the MDI control register in the PHY at offset and stores the
2295779Sxy150489  * information read to data.
2305779Sxy150489  */
2315779Sxy150489 s32
2325779Sxy150489 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
2335779Sxy150489 {
2345779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
2355779Sxy150489 	u32 i, mdic = 0;
2365779Sxy150489 	s32 ret_val = E1000_SUCCESS;
2375779Sxy150489 
2385779Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_mdic");
2395779Sxy150489 
2405779Sxy150489 	/*
2415779Sxy150489 	 * Set up Op-code, Phy Address, and register offset in the MDI
2425779Sxy150489 	 * Control register.  The MAC will take care of interfacing with the
2435779Sxy150489 	 * PHY to retrieve the desired data.
2445779Sxy150489 	 */
2455779Sxy150489 	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
2465779Sxy150489 	    (phy->addr << E1000_MDIC_PHY_SHIFT) |
2475779Sxy150489 	    (E1000_MDIC_OP_READ));
2485779Sxy150489 
2495779Sxy150489 	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
2505779Sxy150489 
2515779Sxy150489 	/*
2525779Sxy150489 	 * Poll the ready bit to see if the MDI read completed
2535779Sxy150489 	 * Increasing the time out as testing showed failures with
2545779Sxy150489 	 * the lower time out
2555779Sxy150489 	 */
2565779Sxy150489 	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
2575779Sxy150489 		usec_delay(50);
2585779Sxy150489 		mdic = E1000_READ_REG(hw, E1000_MDIC);
2595779Sxy150489 		if (mdic & E1000_MDIC_READY)
2605779Sxy150489 			break;
2615779Sxy150489 	}
2625779Sxy150489 	if (!(mdic & E1000_MDIC_READY)) {
2635779Sxy150489 		DEBUGOUT("MDI Read did not complete\n");
2645779Sxy150489 		ret_val = -E1000_ERR_PHY;
2655779Sxy150489 		goto out;
2665779Sxy150489 	}
2675779Sxy150489 	if (mdic & E1000_MDIC_ERROR) {
2685779Sxy150489 		DEBUGOUT("MDI Error\n");
2695779Sxy150489 		ret_val = -E1000_ERR_PHY;
2705779Sxy150489 		goto out;
2715779Sxy150489 	}
2725779Sxy150489 	*data = (u16) mdic;
2735779Sxy150489 
2745779Sxy150489 out:
2755779Sxy150489 	return (ret_val);
2765779Sxy150489 }
2775779Sxy150489 
2785779Sxy150489 /*
2795779Sxy150489  * e1000_write_phy_reg_mdic - Write MDI control register
2805779Sxy150489  * @hw: pointer to the HW structure
2815779Sxy150489  * @offset: register offset to write to
2825779Sxy150489  * @data: data to write to register at offset
2835779Sxy150489  *
2845779Sxy150489  * Writes data to MDI control register in the PHY at offset.
2855779Sxy150489  */
2865779Sxy150489 s32
2875779Sxy150489 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
2885779Sxy150489 {
2895779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
2905779Sxy150489 	u32 i, mdic = 0;
2915779Sxy150489 	s32 ret_val = E1000_SUCCESS;
2925779Sxy150489 
2935779Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_mdic");
2945779Sxy150489 
2955779Sxy150489 	/*
2965779Sxy150489 	 * Set up Op-code, Phy Address, and register offset in the MDI
2975779Sxy150489 	 * Control register.  The MAC will take care of interfacing with the
2985779Sxy150489 	 * PHY to retrieve the desired data.
2995779Sxy150489 	 */
3005779Sxy150489 	mdic = (((u32)data) |
3015779Sxy150489 	    (offset << E1000_MDIC_REG_SHIFT) |
3025779Sxy150489 	    (phy->addr << E1000_MDIC_PHY_SHIFT) |
3035779Sxy150489 	    (E1000_MDIC_OP_WRITE));
3045779Sxy150489 
3055779Sxy150489 	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
3065779Sxy150489 
3075779Sxy150489 	/*
3085779Sxy150489 	 * Poll the ready bit to see if the MDI read completed
3095779Sxy150489 	 * Increasing the time out as testing showed failures with
3105779Sxy150489 	 * the lower time out
3115779Sxy150489 	 */
3125779Sxy150489 	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
3135779Sxy150489 		usec_delay(50);
3145779Sxy150489 		mdic = E1000_READ_REG(hw, E1000_MDIC);
3155779Sxy150489 		if (mdic & E1000_MDIC_READY)
3165779Sxy150489 			break;
3175779Sxy150489 	}
3185779Sxy150489 	if (!(mdic & E1000_MDIC_READY)) {
3195779Sxy150489 		DEBUGOUT("MDI Write did not complete\n");
3205779Sxy150489 		ret_val = -E1000_ERR_PHY;
3215779Sxy150489 		goto out;
3225779Sxy150489 	}
3235779Sxy150489 	if (mdic & E1000_MDIC_ERROR) {
3245779Sxy150489 		DEBUGOUT("MDI Error\n");
3255779Sxy150489 		ret_val = -E1000_ERR_PHY;
3265779Sxy150489 		goto out;
3275779Sxy150489 	}
3285779Sxy150489 
3295779Sxy150489 out:
3305779Sxy150489 	return (ret_val);
3315779Sxy150489 }
3325779Sxy150489 
3335779Sxy150489 /*
334*11155SJason.Xu@Sun.COM  * e1000_read_phy_reg_i2c - Read PHY register using i2c
335*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
336*11155SJason.Xu@Sun.COM  * @offset: register offset to be read
337*11155SJason.Xu@Sun.COM  * @data: pointer to the read data
338*11155SJason.Xu@Sun.COM  *
339*11155SJason.Xu@Sun.COM  * Reads the PHY register at offset using the i2c interface and stores the
340*11155SJason.Xu@Sun.COM  * retrieved information in data.
341*11155SJason.Xu@Sun.COM  */
342*11155SJason.Xu@Sun.COM s32
343*11155SJason.Xu@Sun.COM e1000_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
344*11155SJason.Xu@Sun.COM {
345*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
346*11155SJason.Xu@Sun.COM 	u32 i, i2ccmd = 0;
347*11155SJason.Xu@Sun.COM 
348*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_read_phy_reg_i2c");
349*11155SJason.Xu@Sun.COM 
350*11155SJason.Xu@Sun.COM 	/*
351*11155SJason.Xu@Sun.COM 	 * Set up Op-code, Phy Address, and register address in the I2CCMD
352*11155SJason.Xu@Sun.COM 	 * register.  The MAC will take care of interfacing with the
353*11155SJason.Xu@Sun.COM 	 * PHY to retrieve the desired data.
354*11155SJason.Xu@Sun.COM 	 */
355*11155SJason.Xu@Sun.COM 	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
356*11155SJason.Xu@Sun.COM 	    (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
357*11155SJason.Xu@Sun.COM 	    (E1000_I2CCMD_OPCODE_READ));
358*11155SJason.Xu@Sun.COM 
359*11155SJason.Xu@Sun.COM 	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
360*11155SJason.Xu@Sun.COM 
361*11155SJason.Xu@Sun.COM 	/* Poll the ready bit to see if the I2C read completed */
362*11155SJason.Xu@Sun.COM 	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
363*11155SJason.Xu@Sun.COM 		usec_delay(50);
364*11155SJason.Xu@Sun.COM 		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
365*11155SJason.Xu@Sun.COM 		if (i2ccmd & E1000_I2CCMD_READY)
366*11155SJason.Xu@Sun.COM 			break;
367*11155SJason.Xu@Sun.COM 	}
368*11155SJason.Xu@Sun.COM 	if (!(i2ccmd & E1000_I2CCMD_READY)) {
369*11155SJason.Xu@Sun.COM 		DEBUGOUT("I2CCMD Read did not complete\n");
370*11155SJason.Xu@Sun.COM 		return (-E1000_ERR_PHY);
371*11155SJason.Xu@Sun.COM 	}
372*11155SJason.Xu@Sun.COM 	if (i2ccmd & E1000_I2CCMD_ERROR) {
373*11155SJason.Xu@Sun.COM 		DEBUGOUT("I2CCMD Error bit set\n");
374*11155SJason.Xu@Sun.COM 		return (-E1000_ERR_PHY);
375*11155SJason.Xu@Sun.COM 	}
376*11155SJason.Xu@Sun.COM 
377*11155SJason.Xu@Sun.COM 	/* Need to byte-swap the 16-bit value. */
378*11155SJason.Xu@Sun.COM 	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
379*11155SJason.Xu@Sun.COM 
380*11155SJason.Xu@Sun.COM 	return (E1000_SUCCESS);
381*11155SJason.Xu@Sun.COM }
382*11155SJason.Xu@Sun.COM 
383*11155SJason.Xu@Sun.COM /*
384*11155SJason.Xu@Sun.COM  * e1000_write_phy_reg_i2c - Write PHY register using i2c
385*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
386*11155SJason.Xu@Sun.COM  * @offset: register offset to write to
387*11155SJason.Xu@Sun.COM  * @data: data to write at register offset
388*11155SJason.Xu@Sun.COM  *
389*11155SJason.Xu@Sun.COM  * Writes the data to PHY register at the offset using the i2c interface.
390*11155SJason.Xu@Sun.COM  */
391*11155SJason.Xu@Sun.COM s32
392*11155SJason.Xu@Sun.COM e1000_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
393*11155SJason.Xu@Sun.COM {
394*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
395*11155SJason.Xu@Sun.COM 	u32 i, i2ccmd = 0;
396*11155SJason.Xu@Sun.COM 	u16 phy_data_swapped;
397*11155SJason.Xu@Sun.COM 
398*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_write_phy_reg_i2c");
399*11155SJason.Xu@Sun.COM 
400*11155SJason.Xu@Sun.COM 	/* Swap the data bytes for the I2C interface */
401*11155SJason.Xu@Sun.COM 	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
402*11155SJason.Xu@Sun.COM 
403*11155SJason.Xu@Sun.COM 	/*
404*11155SJason.Xu@Sun.COM 	 * Set up Op-code, Phy Address, and register address in the I2CCMD
405*11155SJason.Xu@Sun.COM 	 * register.  The MAC will take care of interfacing with the
406*11155SJason.Xu@Sun.COM 	 * PHY to retrieve the desired data.
407*11155SJason.Xu@Sun.COM 	 */
408*11155SJason.Xu@Sun.COM 	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
409*11155SJason.Xu@Sun.COM 	    (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
410*11155SJason.Xu@Sun.COM 	    E1000_I2CCMD_OPCODE_WRITE |
411*11155SJason.Xu@Sun.COM 	    phy_data_swapped);
412*11155SJason.Xu@Sun.COM 
413*11155SJason.Xu@Sun.COM 	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
414*11155SJason.Xu@Sun.COM 
415*11155SJason.Xu@Sun.COM 	/* Poll the ready bit to see if the I2C read completed */
416*11155SJason.Xu@Sun.COM 	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
417*11155SJason.Xu@Sun.COM 		usec_delay(50);
418*11155SJason.Xu@Sun.COM 		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
419*11155SJason.Xu@Sun.COM 		if (i2ccmd & E1000_I2CCMD_READY)
420*11155SJason.Xu@Sun.COM 			break;
421*11155SJason.Xu@Sun.COM 	}
422*11155SJason.Xu@Sun.COM 	if (!(i2ccmd & E1000_I2CCMD_READY)) {
423*11155SJason.Xu@Sun.COM 		DEBUGOUT("I2CCMD Write did not complete\n");
424*11155SJason.Xu@Sun.COM 		return (-E1000_ERR_PHY);
425*11155SJason.Xu@Sun.COM 	}
426*11155SJason.Xu@Sun.COM 	if (i2ccmd & E1000_I2CCMD_ERROR) {
427*11155SJason.Xu@Sun.COM 		DEBUGOUT("I2CCMD Error bit set\n");
428*11155SJason.Xu@Sun.COM 		return (-E1000_ERR_PHY);
429*11155SJason.Xu@Sun.COM 	}
430*11155SJason.Xu@Sun.COM 
431*11155SJason.Xu@Sun.COM 	return (E1000_SUCCESS);
432*11155SJason.Xu@Sun.COM }
433*11155SJason.Xu@Sun.COM 
434*11155SJason.Xu@Sun.COM /*
4355779Sxy150489  * e1000_read_phy_reg_m88 - Read m88 PHY register
4365779Sxy150489  * @hw: pointer to the HW structure
4375779Sxy150489  * @offset: register offset to be read
4385779Sxy150489  * @data: pointer to the read data
4395779Sxy150489  *
4405779Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
4415779Sxy150489  * and storing the retrieved information in data.  Release any acquired
4425779Sxy150489  * semaphores before exiting.
4435779Sxy150489  */
4445779Sxy150489 s32
4455779Sxy150489 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
4465779Sxy150489 {
4478571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
4485779Sxy150489 
4495779Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_m88");
4505779Sxy150489 
4518571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
4528571SChenlu.Chen@Sun.COM 		goto out;
4538571SChenlu.Chen@Sun.COM 
4548571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
4555779Sxy150489 	if (ret_val)
4565779Sxy150489 		goto out;
4575779Sxy150489 
4585779Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw,
4595779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
4605779Sxy150489 
4618571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
4625779Sxy150489 
4635779Sxy150489 out:
4645779Sxy150489 	return (ret_val);
4655779Sxy150489 }
4665779Sxy150489 
4675779Sxy150489 /*
4685779Sxy150489  * e1000_write_phy_reg_m88 - Write m88 PHY register
4695779Sxy150489  * @hw: pointer to the HW structure
4705779Sxy150489  * @offset: register offset to write to
4715779Sxy150489  * @data: data to write at register offset
4725779Sxy150489  *
4735779Sxy150489  * Acquires semaphore, if necessary, then writes the data to PHY register
4745779Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
4755779Sxy150489  */
4765779Sxy150489 s32
4775779Sxy150489 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
4785779Sxy150489 {
4798571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
4805779Sxy150489 
4815779Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_m88");
4825779Sxy150489 
4838571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
4848571SChenlu.Chen@Sun.COM 		goto out;
4858571SChenlu.Chen@Sun.COM 
4868571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
4875779Sxy150489 	if (ret_val)
4885779Sxy150489 		goto out;
4895779Sxy150489 
4905779Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
4915779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
4925779Sxy150489 
4938571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
4945779Sxy150489 
4955779Sxy150489 out:
4965779Sxy150489 	return (ret_val);
4975779Sxy150489 }
4985779Sxy150489 
4995779Sxy150489 /*
500*11155SJason.Xu@Sun.COM  * __e1000_read_phy_reg_igp - Read igp PHY register
501*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
502*11155SJason.Xu@Sun.COM  * @offset: register offset to be read
503*11155SJason.Xu@Sun.COM  * @data: pointer to the read data
504*11155SJason.Xu@Sun.COM  * @locked: semaphore has already been acquired or not
505*11155SJason.Xu@Sun.COM  *
506*11155SJason.Xu@Sun.COM  * Acquires semaphore, if necessary, then reads the PHY register at offset
507*11155SJason.Xu@Sun.COM  * and stores the retrieved information in data.  Release any acquired
508*11155SJason.Xu@Sun.COM  * semaphores before exiting.
509*11155SJason.Xu@Sun.COM  */
510*11155SJason.Xu@Sun.COM static s32
511*11155SJason.Xu@Sun.COM __e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
512*11155SJason.Xu@Sun.COM     bool locked)
513*11155SJason.Xu@Sun.COM {
514*11155SJason.Xu@Sun.COM 	s32 ret_val = E1000_SUCCESS;
515*11155SJason.Xu@Sun.COM 
516*11155SJason.Xu@Sun.COM 	DEBUGFUNC("__e1000_read_phy_reg_igp");
517*11155SJason.Xu@Sun.COM 
518*11155SJason.Xu@Sun.COM 	if (!locked) {
519*11155SJason.Xu@Sun.COM 		if (!(hw->phy.ops.acquire))
520*11155SJason.Xu@Sun.COM 			goto out;
521*11155SJason.Xu@Sun.COM 
522*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.acquire(hw);
523*11155SJason.Xu@Sun.COM 		if (ret_val)
524*11155SJason.Xu@Sun.COM 			goto out;
525*11155SJason.Xu@Sun.COM 	}
526*11155SJason.Xu@Sun.COM 
527*11155SJason.Xu@Sun.COM 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
528*11155SJason.Xu@Sun.COM 		ret_val = e1000_write_phy_reg_mdic(hw,
529*11155SJason.Xu@Sun.COM 		    IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
530*11155SJason.Xu@Sun.COM 		if (ret_val)
531*11155SJason.Xu@Sun.COM 			goto release;
532*11155SJason.Xu@Sun.COM 	}
533*11155SJason.Xu@Sun.COM 
534*11155SJason.Xu@Sun.COM 	ret_val = e1000_read_phy_reg_mdic(hw,
535*11155SJason.Xu@Sun.COM 	    MAX_PHY_REG_ADDRESS & offset, data);
536*11155SJason.Xu@Sun.COM 
537*11155SJason.Xu@Sun.COM release:
538*11155SJason.Xu@Sun.COM 	if (!locked)
539*11155SJason.Xu@Sun.COM 		hw->phy.ops.release(hw);
540*11155SJason.Xu@Sun.COM 
541*11155SJason.Xu@Sun.COM out:
542*11155SJason.Xu@Sun.COM 	return (ret_val);
543*11155SJason.Xu@Sun.COM }
544*11155SJason.Xu@Sun.COM 
545*11155SJason.Xu@Sun.COM /*
5465779Sxy150489  * e1000_read_phy_reg_igp - Read igp PHY register
5475779Sxy150489  * @hw: pointer to the HW structure
5485779Sxy150489  * @offset: register offset to be read
5495779Sxy150489  * @data: pointer to the read data
5505779Sxy150489  *
551*11155SJason.Xu@Sun.COM  * Acquires semaphore then reads the PHY register at offset and stores the
552*11155SJason.Xu@Sun.COM  * retrieved information in data.
553*11155SJason.Xu@Sun.COM  * Release the acquired semaphore before exiting.
5545779Sxy150489  */
5555779Sxy150489 s32
5565779Sxy150489 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
5575779Sxy150489 {
558*11155SJason.Xu@Sun.COM 	return (__e1000_read_phy_reg_igp(hw, offset, data, false));
559*11155SJason.Xu@Sun.COM }
560*11155SJason.Xu@Sun.COM 
561*11155SJason.Xu@Sun.COM /*
562*11155SJason.Xu@Sun.COM  * e1000_read_phy_reg_igp_locked - Read igp PHY register
563*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
564*11155SJason.Xu@Sun.COM  * @offset: register offset to be read
565*11155SJason.Xu@Sun.COM  * @data: pointer to the read data
566*11155SJason.Xu@Sun.COM  *
567*11155SJason.Xu@Sun.COM  * Reads the PHY register at offset and stores the retrieved information
568*11155SJason.Xu@Sun.COM  * in data.  Assumes semaphore already acquired.
569*11155SJason.Xu@Sun.COM  */
570*11155SJason.Xu@Sun.COM s32
571*11155SJason.Xu@Sun.COM e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
572*11155SJason.Xu@Sun.COM {
573*11155SJason.Xu@Sun.COM 	return (__e1000_read_phy_reg_igp(hw, offset, data, true));
574*11155SJason.Xu@Sun.COM }
575*11155SJason.Xu@Sun.COM 
576*11155SJason.Xu@Sun.COM /*
577*11155SJason.Xu@Sun.COM  * __e1000_write_phy_reg_igp - Write igp PHY register
578*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
579*11155SJason.Xu@Sun.COM  * @offset: register offset to write to
580*11155SJason.Xu@Sun.COM  * @data: data to write at register offset
581*11155SJason.Xu@Sun.COM  * @locked: semaphore has already been acquired or not
582*11155SJason.Xu@Sun.COM  *
583*11155SJason.Xu@Sun.COM  * Acquires semaphore, if necessary, then writes the data to PHY register
584*11155SJason.Xu@Sun.COM  * at the offset.  Release any acquired semaphores before exiting.
585*11155SJason.Xu@Sun.COM  */
586*11155SJason.Xu@Sun.COM static s32
587*11155SJason.Xu@Sun.COM __e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
588*11155SJason.Xu@Sun.COM     bool locked)
589*11155SJason.Xu@Sun.COM {
5908571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
5915779Sxy150489 
592*11155SJason.Xu@Sun.COM 	DEBUGFUNC("__e1000_write_phy_reg_igp");
593*11155SJason.Xu@Sun.COM 
594*11155SJason.Xu@Sun.COM 	if (!locked) {
595*11155SJason.Xu@Sun.COM 		if (!(hw->phy.ops.acquire))
596*11155SJason.Xu@Sun.COM 			goto out;
597*11155SJason.Xu@Sun.COM 
598*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.acquire(hw);
599*11155SJason.Xu@Sun.COM 		if (ret_val)
600*11155SJason.Xu@Sun.COM 			goto out;
601*11155SJason.Xu@Sun.COM 	}
6025779Sxy150489 
6035779Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
6045779Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw,
6055779Sxy150489 		    IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
606*11155SJason.Xu@Sun.COM 		if (ret_val)
607*11155SJason.Xu@Sun.COM 			goto release;
6085779Sxy150489 	}
6095779Sxy150489 
610*11155SJason.Xu@Sun.COM 	ret_val = e1000_write_phy_reg_mdic(hw,
6115779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
6125779Sxy150489 
613*11155SJason.Xu@Sun.COM release:
614*11155SJason.Xu@Sun.COM 	if (!locked)
615*11155SJason.Xu@Sun.COM 		hw->phy.ops.release(hw);
6165779Sxy150489 
6175779Sxy150489 out:
6185779Sxy150489 	return (ret_val);
6195779Sxy150489 }
6205779Sxy150489 
6215779Sxy150489 /*
6225779Sxy150489  * e1000_write_phy_reg_igp - Write igp PHY register
6235779Sxy150489  * @hw: pointer to the HW structure
6245779Sxy150489  * @offset: register offset to write to
6255779Sxy150489  * @data: data to write at register offset
6265779Sxy150489  *
627*11155SJason.Xu@Sun.COM  * Acquires semaphore then writes the data to PHY register
6285779Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
6295779Sxy150489  */
6305779Sxy150489 s32
6315779Sxy150489 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
6325779Sxy150489 {
633*11155SJason.Xu@Sun.COM 	return (__e1000_write_phy_reg_igp(hw, offset, data, false));
6345779Sxy150489 }
6355779Sxy150489 
6365779Sxy150489 /*
637*11155SJason.Xu@Sun.COM  * e1000_write_phy_reg_igp_locked - Write igp PHY register
638*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
639*11155SJason.Xu@Sun.COM  * @offset: register offset to write to
640*11155SJason.Xu@Sun.COM  * @data: data to write at register offset
641*11155SJason.Xu@Sun.COM  *
642*11155SJason.Xu@Sun.COM  * Writes the data to PHY register at the offset.
643*11155SJason.Xu@Sun.COM  * Assumes semaphore already acquired.
644*11155SJason.Xu@Sun.COM  */
645*11155SJason.Xu@Sun.COM s32
646*11155SJason.Xu@Sun.COM e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
647*11155SJason.Xu@Sun.COM {
648*11155SJason.Xu@Sun.COM 	return (__e1000_write_phy_reg_igp(hw, offset, data, true));
649*11155SJason.Xu@Sun.COM }
650*11155SJason.Xu@Sun.COM 
651*11155SJason.Xu@Sun.COM /*
652*11155SJason.Xu@Sun.COM  * __e1000_read_kmrn_reg - Read kumeran register
6535779Sxy150489  * @hw: pointer to the HW structure
6545779Sxy150489  * @offset: register offset to be read
6555779Sxy150489  * @data: pointer to the read data
656*11155SJason.Xu@Sun.COM  * @locked: semaphore has already been acquired or not
6575779Sxy150489  *
6585779Sxy150489  * Acquires semaphore, if necessary.  Then reads the PHY register at offset
6595779Sxy150489  * using the kumeran interface.  The information retrieved is stored in data.
6605779Sxy150489  * Release any acquired semaphores before exiting.
6615779Sxy150489  */
662*11155SJason.Xu@Sun.COM static s32
663*11155SJason.Xu@Sun.COM __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, bool locked)
6645779Sxy150489 {
6655779Sxy150489 	u32 kmrnctrlsta;
6668571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
6675779Sxy150489 
668*11155SJason.Xu@Sun.COM 	DEBUGFUNC("__e1000_read_kmrn_reg_generic");
669*11155SJason.Xu@Sun.COM 
670*11155SJason.Xu@Sun.COM 	if (!locked) {
671*11155SJason.Xu@Sun.COM 		if (!(hw->phy.ops.acquire))
672*11155SJason.Xu@Sun.COM 			goto out;
673*11155SJason.Xu@Sun.COM 
674*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.acquire(hw);
675*11155SJason.Xu@Sun.COM 		if (ret_val)
676*11155SJason.Xu@Sun.COM 			goto out;
677*11155SJason.Xu@Sun.COM 	}
6785779Sxy150489 
6795779Sxy150489 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
6805779Sxy150489 	    E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
6815779Sxy150489 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
6825779Sxy150489 
6835779Sxy150489 	usec_delay(2);
6845779Sxy150489 
6855779Sxy150489 	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
6865779Sxy150489 	*data = (u16)kmrnctrlsta;
6875779Sxy150489 
688*11155SJason.Xu@Sun.COM 	if (!locked)
689*11155SJason.Xu@Sun.COM 		hw->phy.ops.release(hw);
6905779Sxy150489 
6915779Sxy150489 out:
6925779Sxy150489 	return (ret_val);
6935779Sxy150489 }
6945779Sxy150489 
6955779Sxy150489 /*
696*11155SJason.Xu@Sun.COM  * e1000_read_kmrn_reg_generic -  Read kumeran register
697*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
698*11155SJason.Xu@Sun.COM  * @offset: register offset to be read
699*11155SJason.Xu@Sun.COM  * @data: pointer to the read data
700*11155SJason.Xu@Sun.COM  *
701*11155SJason.Xu@Sun.COM  * Acquires semaphore then reads the PHY register at offset using the
702*11155SJason.Xu@Sun.COM  * kumeran interface.  The information retrieved is stored in data.
703*11155SJason.Xu@Sun.COM  * Release the acquired semaphore before exiting.
704*11155SJason.Xu@Sun.COM  */
705*11155SJason.Xu@Sun.COM s32
706*11155SJason.Xu@Sun.COM e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
707*11155SJason.Xu@Sun.COM {
708*11155SJason.Xu@Sun.COM 	return (__e1000_read_kmrn_reg(hw, offset, data, false));
709*11155SJason.Xu@Sun.COM }
710*11155SJason.Xu@Sun.COM 
711*11155SJason.Xu@Sun.COM /*
712*11155SJason.Xu@Sun.COM  * e1000_read_kmrn_reg_locked -  Read kumeran register
713*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
714*11155SJason.Xu@Sun.COM  * @offset: register offset to be read
715*11155SJason.Xu@Sun.COM  * @data: pointer to the read data
716*11155SJason.Xu@Sun.COM  *
717*11155SJason.Xu@Sun.COM  * Reads the PHY register at offset using the kumeran interface.  The
718*11155SJason.Xu@Sun.COM  * information retrieved is stored in data.
719*11155SJason.Xu@Sun.COM  * Assumes semaphore already acquired.
720*11155SJason.Xu@Sun.COM  */
721*11155SJason.Xu@Sun.COM s32
722*11155SJason.Xu@Sun.COM e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
723*11155SJason.Xu@Sun.COM {
724*11155SJason.Xu@Sun.COM 	return (__e1000_read_kmrn_reg(hw, offset, data, true));
725*11155SJason.Xu@Sun.COM }
726*11155SJason.Xu@Sun.COM 
727*11155SJason.Xu@Sun.COM /*
728*11155SJason.Xu@Sun.COM  * __e1000_write_kmrn_reg - Write kumeran register
7295779Sxy150489  * @hw: pointer to the HW structure
7305779Sxy150489  * @offset: register offset to write to
7315779Sxy150489  * @data: data to write at register offset
732*11155SJason.Xu@Sun.COM  * @locked: semaphore has already been acquired or not
7335779Sxy150489  *
7345779Sxy150489  * Acquires semaphore, if necessary.  Then write the data to PHY register
7355779Sxy150489  * at the offset using the kumeran interface.  Release any acquired semaphores
7365779Sxy150489  * before exiting.
7375779Sxy150489  */
738*11155SJason.Xu@Sun.COM static s32
739*11155SJason.Xu@Sun.COM __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, bool locked)
7405779Sxy150489 {
7415779Sxy150489 	u32 kmrnctrlsta;
7428571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
7435779Sxy150489 
7445779Sxy150489 	DEBUGFUNC("e1000_write_kmrn_reg_generic");
7455779Sxy150489 
746*11155SJason.Xu@Sun.COM 	if (!locked) {
747*11155SJason.Xu@Sun.COM 		if (!(hw->phy.ops.acquire))
748*11155SJason.Xu@Sun.COM 			goto out;
749*11155SJason.Xu@Sun.COM 
750*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.acquire(hw);
751*11155SJason.Xu@Sun.COM 		if (ret_val)
752*11155SJason.Xu@Sun.COM 			goto out;
753*11155SJason.Xu@Sun.COM 	}
7545779Sxy150489 
7555779Sxy150489 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
7565779Sxy150489 	    E1000_KMRNCTRLSTA_OFFSET) | data;
7575779Sxy150489 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
7585779Sxy150489 
7595779Sxy150489 	usec_delay(2);
760*11155SJason.Xu@Sun.COM 
761*11155SJason.Xu@Sun.COM 	if (!locked)
762*11155SJason.Xu@Sun.COM 		hw->phy.ops.release(hw);
763*11155SJason.Xu@Sun.COM 
764*11155SJason.Xu@Sun.COM out:
765*11155SJason.Xu@Sun.COM 	return (ret_val);
766*11155SJason.Xu@Sun.COM }
767*11155SJason.Xu@Sun.COM 
768*11155SJason.Xu@Sun.COM /*
769*11155SJason.Xu@Sun.COM  * e1000_write_kmrn_reg_generic -  Write kumeran register
770*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
771*11155SJason.Xu@Sun.COM  * @offset: register offset to write to
772*11155SJason.Xu@Sun.COM  * @data: data to write at register offset
773*11155SJason.Xu@Sun.COM  *
774*11155SJason.Xu@Sun.COM  * Acquires semaphore then writes the data to the PHY register at the offset
775*11155SJason.Xu@Sun.COM  * using the kumeran interface.  Release the acquired semaphore before exiting.
776*11155SJason.Xu@Sun.COM  */
777*11155SJason.Xu@Sun.COM s32
778*11155SJason.Xu@Sun.COM e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
779*11155SJason.Xu@Sun.COM {
780*11155SJason.Xu@Sun.COM 	return (__e1000_write_kmrn_reg(hw, offset, data, false));
781*11155SJason.Xu@Sun.COM }
782*11155SJason.Xu@Sun.COM 
783*11155SJason.Xu@Sun.COM /*
784*11155SJason.Xu@Sun.COM  * e1000_write_kmrn_reg_locked -  Write kumeran register
785*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
786*11155SJason.Xu@Sun.COM  * @offset: register offset to write to
787*11155SJason.Xu@Sun.COM  * @data: data to write at register offset
788*11155SJason.Xu@Sun.COM  *
789*11155SJason.Xu@Sun.COM  * Write the data to PHY register at the offset using the kumeran interface.
790*11155SJason.Xu@Sun.COM  * Assumes semaphore already acquired.
791*11155SJason.Xu@Sun.COM  */
792*11155SJason.Xu@Sun.COM s32
793*11155SJason.Xu@Sun.COM e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
794*11155SJason.Xu@Sun.COM {
795*11155SJason.Xu@Sun.COM 	return (__e1000_write_kmrn_reg(hw, offset, data, true));
796*11155SJason.Xu@Sun.COM }
797*11155SJason.Xu@Sun.COM 
798*11155SJason.Xu@Sun.COM /*
799*11155SJason.Xu@Sun.COM  * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
800*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
801*11155SJason.Xu@Sun.COM  *
802*11155SJason.Xu@Sun.COM  * Sets up Carrier-sense on Transmit and downshift values.
803*11155SJason.Xu@Sun.COM  */
804*11155SJason.Xu@Sun.COM s32
805*11155SJason.Xu@Sun.COM e1000_copper_link_setup_82577(struct e1000_hw *hw)
806*11155SJason.Xu@Sun.COM {
807*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
808*11155SJason.Xu@Sun.COM 	s32 ret_val;
809*11155SJason.Xu@Sun.COM 	u16 phy_data;
810*11155SJason.Xu@Sun.COM 
811*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_copper_link_setup_82577");
812*11155SJason.Xu@Sun.COM 
813*11155SJason.Xu@Sun.COM 	if (phy->reset_disable) {
814*11155SJason.Xu@Sun.COM 		ret_val = E1000_SUCCESS;
815*11155SJason.Xu@Sun.COM 		goto out;
816*11155SJason.Xu@Sun.COM 	}
817*11155SJason.Xu@Sun.COM 
818*11155SJason.Xu@Sun.COM 	if (phy->type == e1000_phy_82580) {
819*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.reset(hw);
820*11155SJason.Xu@Sun.COM 		if (ret_val) {
821*11155SJason.Xu@Sun.COM 			DEBUGOUT("Error resetting the PHY.\n");
822*11155SJason.Xu@Sun.COM 			goto out;
823*11155SJason.Xu@Sun.COM 		}
824*11155SJason.Xu@Sun.COM 	}
825*11155SJason.Xu@Sun.COM 
826*11155SJason.Xu@Sun.COM 	/* Enable CRS on TX. This must be set for half-duplex operation. */
827*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data);
828*11155SJason.Xu@Sun.COM 	if (ret_val)
829*11155SJason.Xu@Sun.COM 		goto out;
830*11155SJason.Xu@Sun.COM 
831*11155SJason.Xu@Sun.COM 	phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
832*11155SJason.Xu@Sun.COM 
833*11155SJason.Xu@Sun.COM 	/* Enable downshift */
834*11155SJason.Xu@Sun.COM 	phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
835*11155SJason.Xu@Sun.COM 
836*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data);
837*11155SJason.Xu@Sun.COM 	if (ret_val)
838*11155SJason.Xu@Sun.COM 		goto out;
839*11155SJason.Xu@Sun.COM 
840*11155SJason.Xu@Sun.COM 	/* Set number of link attempts before downshift */
841*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data);
842*11155SJason.Xu@Sun.COM 	if (ret_val)
843*11155SJason.Xu@Sun.COM 		goto out;
844*11155SJason.Xu@Sun.COM 	phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK;
845*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data);
8465779Sxy150489 
8475779Sxy150489 out:
8485779Sxy150489 	return (ret_val);
8495779Sxy150489 }
8505779Sxy150489 
8515779Sxy150489 /*
8525779Sxy150489  * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
8535779Sxy150489  * @hw: pointer to the HW structure
8545779Sxy150489  *
8555779Sxy150489  * Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
8565779Sxy150489  * and downshift values are set also.
8575779Sxy150489  */
8585779Sxy150489 s32
8595779Sxy150489 e1000_copper_link_setup_m88(struct e1000_hw *hw)
8605779Sxy150489 {
8615779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
8625779Sxy150489 	s32 ret_val;
8635779Sxy150489 	u16 phy_data;
8645779Sxy150489 
8655779Sxy150489 	DEBUGFUNC("e1000_copper_link_setup_m88");
8665779Sxy150489 
8675779Sxy150489 	if (phy->reset_disable) {
8685779Sxy150489 		ret_val = E1000_SUCCESS;
8695779Sxy150489 		goto out;
8705779Sxy150489 	}
8715779Sxy150489 
8725779Sxy150489 	/* Enable CRS on TX. This must be set for half-duplex operation. */
8738571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
8745779Sxy150489 	if (ret_val)
8755779Sxy150489 		goto out;
8765779Sxy150489 
8778571SChenlu.Chen@Sun.COM 	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
8785779Sxy150489 
8795779Sxy150489 	/*
8805779Sxy150489 	 * Options:
8815779Sxy150489 	 *   MDI/MDI-X = 0 (default)
8825779Sxy150489 	 *   0 - Auto for all speeds
8835779Sxy150489 	 *   1 - MDI mode
8845779Sxy150489 	 *   2 - MDI-X mode
8855779Sxy150489 	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
8865779Sxy150489 	 */
8875779Sxy150489 	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
8885779Sxy150489 
8895779Sxy150489 	switch (phy->mdix) {
8905779Sxy150489 		case 1:
8915779Sxy150489 			phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
8925779Sxy150489 			break;
8935779Sxy150489 		case 2:
8945779Sxy150489 			phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
8955779Sxy150489 			break;
8965779Sxy150489 		case 3:
8975779Sxy150489 			phy_data |= M88E1000_PSCR_AUTO_X_1000T;
8985779Sxy150489 			break;
8995779Sxy150489 		case 0:
9005779Sxy150489 		default:
9015779Sxy150489 			phy_data |= M88E1000_PSCR_AUTO_X_MODE;
9025779Sxy150489 			break;
9035779Sxy150489 	}
9045779Sxy150489 
9055779Sxy150489 	/*
9065779Sxy150489 	 * Options:
9075779Sxy150489 	 *   disable_polarity_correction = 0 (default)
9085779Sxy150489 	 *	Automatic Correction for Reversed Cable Polarity
9095779Sxy150489 	 *   0 - Disabled
9105779Sxy150489 	 *   1 - Enabled
9115779Sxy150489 	 */
9125779Sxy150489 	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
9135779Sxy150489 	if (phy->disable_polarity_correction == 1)
9145779Sxy150489 		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
9155779Sxy150489 
9168571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
9175779Sxy150489 	if (ret_val)
9185779Sxy150489 		goto out;
9195779Sxy150489 
9208571SChenlu.Chen@Sun.COM 	if (phy->revision < E1000_REVISION_4) {
9215779Sxy150489 		/*
9225779Sxy150489 		 * Force TX_CLK in the Extended PHY Specific Control Register
9235779Sxy150489 		 * to 25MHz clock.
9245779Sxy150489 		 */
9258571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
9268571SChenlu.Chen@Sun.COM 		    &phy_data);
9275779Sxy150489 		if (ret_val)
9285779Sxy150489 			goto out;
9295779Sxy150489 
9305779Sxy150489 		phy_data |= M88E1000_EPSCR_TX_CLK_25;
9315779Sxy150489 
9325779Sxy150489 		if ((phy->revision == E1000_REVISION_2) &&
9335779Sxy150489 		    (phy->id == M88E1111_I_PHY_ID)) {
9345779Sxy150489 			/* 82573L PHY - set the downshift counter to 5x. */
9355779Sxy150489 			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
9365779Sxy150489 			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
9375779Sxy150489 		} else {
9385779Sxy150489 			/* Configure Master and Slave downshift values */
9395779Sxy150489 			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
9405779Sxy150489 			    M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
9415779Sxy150489 			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
9425779Sxy150489 			    M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
9435779Sxy150489 		}
9448571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
9458571SChenlu.Chen@Sun.COM 		    phy_data);
9465779Sxy150489 		if (ret_val)
9475779Sxy150489 			goto out;
9485779Sxy150489 	}
9495779Sxy150489 
9505779Sxy150489 	/* Commit the changes. */
9518571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.commit(hw);
9525779Sxy150489 	if (ret_val) {
9535779Sxy150489 		DEBUGOUT("Error committing the PHY changes\n");
9545779Sxy150489 		goto out;
9555779Sxy150489 	}
9565779Sxy150489 
9575779Sxy150489 out:
9585779Sxy150489 	return (ret_val);
9595779Sxy150489 }
9605779Sxy150489 
9615779Sxy150489 /*
9625779Sxy150489  * e1000_copper_link_setup_igp - Setup igp PHY's for copper link
9635779Sxy150489  * @hw: pointer to the HW structure
9645779Sxy150489  *
9655779Sxy150489  * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
9665779Sxy150489  * igp PHY's.
9675779Sxy150489  */
9685779Sxy150489 s32
9695779Sxy150489 e1000_copper_link_setup_igp(struct e1000_hw *hw)
9705779Sxy150489 {
9715779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
9725779Sxy150489 	s32 ret_val;
9735779Sxy150489 	u16 data;
9745779Sxy150489 
9755779Sxy150489 	DEBUGFUNC("e1000_copper_link_setup_igp");
9765779Sxy150489 
9775779Sxy150489 	if (phy->reset_disable) {
9785779Sxy150489 		ret_val = E1000_SUCCESS;
9795779Sxy150489 		goto out;
9805779Sxy150489 	}
9815779Sxy150489 
9828571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.reset(hw);
9835779Sxy150489 	if (ret_val) {
9845779Sxy150489 		DEBUGOUT("Error resetting the PHY.\n");
9855779Sxy150489 		goto out;
9865779Sxy150489 	}
9875779Sxy150489 
9888571SChenlu.Chen@Sun.COM 	/*
9898571SChenlu.Chen@Sun.COM 	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
9908571SChenlu.Chen@Sun.COM 	 * timeout issues when LFS is enabled.
9918571SChenlu.Chen@Sun.COM 	 */
9928571SChenlu.Chen@Sun.COM 	msec_delay(100);
9935779Sxy150489 
9945779Sxy150489 	/*
9955779Sxy150489 	 * The NVM settings will configure LPLU in D3 for
9965779Sxy150489 	 * non-IGP1 PHYs.
9975779Sxy150489 	 */
9985779Sxy150489 	if (phy->type == e1000_phy_igp) {
9995779Sxy150489 		/* disable lplu d3 during driver init */
10008571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
10015779Sxy150489 		if (ret_val) {
10025779Sxy150489 			DEBUGOUT("Error Disabling LPLU D3\n");
10035779Sxy150489 			goto out;
10045779Sxy150489 		}
10055779Sxy150489 	}
10065779Sxy150489 
10075779Sxy150489 	/* disable lplu d0 during driver init */
10088571SChenlu.Chen@Sun.COM 	if (hw->phy.ops.set_d0_lplu_state) {
10098571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
10108571SChenlu.Chen@Sun.COM 		if (ret_val) {
10118571SChenlu.Chen@Sun.COM 			DEBUGOUT("Error Disabling LPLU D0\n");
10128571SChenlu.Chen@Sun.COM 			goto out;
10138571SChenlu.Chen@Sun.COM 		}
10145779Sxy150489 	}
10155779Sxy150489 	/* Configure mdi-mdix settings */
10168571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
10175779Sxy150489 	if (ret_val)
10185779Sxy150489 		goto out;
10195779Sxy150489 
10205779Sxy150489 	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
10215779Sxy150489 
10225779Sxy150489 	switch (phy->mdix) {
10235779Sxy150489 	case 1:
10245779Sxy150489 		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
10255779Sxy150489 		break;
10265779Sxy150489 	case 2:
10275779Sxy150489 		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
10285779Sxy150489 		break;
10295779Sxy150489 	case 0:
10305779Sxy150489 	default:
10315779Sxy150489 		data |= IGP01E1000_PSCR_AUTO_MDIX;
10325779Sxy150489 		break;
10335779Sxy150489 	}
10348571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
10355779Sxy150489 	if (ret_val)
10365779Sxy150489 		goto out;
10375779Sxy150489 
10385779Sxy150489 	/* set auto-master slave resolution settings */
10395779Sxy150489 	if (hw->mac.autoneg) {
10405779Sxy150489 		/*
10415779Sxy150489 		 * when autonegotiation advertisement is only 1000Mbps then we
10425779Sxy150489 		 * should disable SmartSpeed and enable Auto MasterSlave
10435779Sxy150489 		 * resolution as hardware default.
10445779Sxy150489 		 */
10455779Sxy150489 		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
10465779Sxy150489 			/* Disable SmartSpeed */
10478571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw,
10485779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG, &data);
10495779Sxy150489 			if (ret_val)
10505779Sxy150489 				goto out;
10515779Sxy150489 
10525779Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10538571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
10545779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG, data);
10555779Sxy150489 			if (ret_val)
10565779Sxy150489 				goto out;
10575779Sxy150489 
10585779Sxy150489 			/* Set auto Master/Slave resolution process */
10598571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
10605779Sxy150489 			if (ret_val)
10615779Sxy150489 				goto out;
10625779Sxy150489 
10635779Sxy150489 			data &= ~CR_1000T_MS_ENABLE;
10648571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
10655779Sxy150489 			if (ret_val)
10665779Sxy150489 				goto out;
10675779Sxy150489 		}
10685779Sxy150489 
10698571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
10705779Sxy150489 		if (ret_val)
10715779Sxy150489 			goto out;
10725779Sxy150489 
10735779Sxy150489 		/* load defaults for future use */
10745779Sxy150489 		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
10755779Sxy150489 		    ((data & CR_1000T_MS_VALUE) ?
10765779Sxy150489 		    e1000_ms_force_master :
10775779Sxy150489 		    e1000_ms_force_slave) :
10785779Sxy150489 		    e1000_ms_auto;
10795779Sxy150489 
10805779Sxy150489 		switch (phy->ms_type) {
10815779Sxy150489 		case e1000_ms_force_master:
10825779Sxy150489 			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
10835779Sxy150489 			break;
10845779Sxy150489 		case e1000_ms_force_slave:
10855779Sxy150489 			data |= CR_1000T_MS_ENABLE;
10865779Sxy150489 			data &= ~(CR_1000T_MS_VALUE);
10875779Sxy150489 			break;
10885779Sxy150489 		case e1000_ms_auto:
10895779Sxy150489 			data &= ~CR_1000T_MS_ENABLE;
10905779Sxy150489 		default:
10915779Sxy150489 			break;
10925779Sxy150489 		}
10938571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
10945779Sxy150489 		if (ret_val)
10955779Sxy150489 			goto out;
10965779Sxy150489 	}
10975779Sxy150489 
10985779Sxy150489 out:
10995779Sxy150489 	return (ret_val);
11005779Sxy150489 }
11015779Sxy150489 
11025779Sxy150489 /*
11035779Sxy150489  * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
11045779Sxy150489  * @hw: pointer to the HW structure
11055779Sxy150489  *
11065779Sxy150489  * Performs initial bounds checking on autoneg advertisement parameter, then
11075779Sxy150489  * configure to advertise the full capability.  Setup the PHY to autoneg
11085779Sxy150489  * and restart the negotiation process between the link partner.  If
11095779Sxy150489  * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
11105779Sxy150489  */
1111*11155SJason.Xu@Sun.COM static s32
11125779Sxy150489 e1000_copper_link_autoneg(struct e1000_hw *hw)
11135779Sxy150489 {
11145779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
11155779Sxy150489 	s32 ret_val;
11165779Sxy150489 	u16 phy_ctrl;
11175779Sxy150489 
11185779Sxy150489 	DEBUGFUNC("e1000_copper_link_autoneg");
11195779Sxy150489 
11205779Sxy150489 	/*
11215779Sxy150489 	 * Perform some bounds checking on the autoneg advertisement
11225779Sxy150489 	 * parameter.
11235779Sxy150489 	 */
11245779Sxy150489 	phy->autoneg_advertised &= phy->autoneg_mask;
11255779Sxy150489 
11265779Sxy150489 	/*
11275779Sxy150489 	 * If autoneg_advertised is zero, we assume it was not defaulted
11285779Sxy150489 	 * by the calling code so we set to advertise full capability.
11295779Sxy150489 	 */
11305779Sxy150489 	if (phy->autoneg_advertised == 0)
11315779Sxy150489 		phy->autoneg_advertised = phy->autoneg_mask;
11325779Sxy150489 
11335779Sxy150489 	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
11345779Sxy150489 	ret_val = e1000_phy_setup_autoneg(hw);
11355779Sxy150489 	if (ret_val) {
11365779Sxy150489 		DEBUGOUT("Error Setting up Auto-Negotiation\n");
11375779Sxy150489 		goto out;
11385779Sxy150489 	}
11395779Sxy150489 	DEBUGOUT("Restarting Auto-Neg\n");
11405779Sxy150489 
11415779Sxy150489 	/*
11425779Sxy150489 	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
11435779Sxy150489 	 * the Auto Neg Restart bit in the PHY control register.
11445779Sxy150489 	 */
11458571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
11465779Sxy150489 	if (ret_val)
11475779Sxy150489 		goto out;
11485779Sxy150489 
11495779Sxy150489 	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
11508571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
11515779Sxy150489 	if (ret_val)
11525779Sxy150489 		goto out;
11535779Sxy150489 
11545779Sxy150489 	/*
11555779Sxy150489 	 * Does the user want to wait for Auto-Neg to complete here, or
11565779Sxy150489 	 * check at a later time (for example, callback routine).
11575779Sxy150489 	 */
11585779Sxy150489 	if (phy->autoneg_wait_to_complete) {
11598571SChenlu.Chen@Sun.COM 		ret_val = hw->mac.ops.wait_autoneg(hw);
11605779Sxy150489 		if (ret_val) {
11615779Sxy150489 			DEBUGOUT("Error while waiting for "
11625779Sxy150489 			    "autoneg to complete\n");
11635779Sxy150489 			goto out;
11645779Sxy150489 		}
11655779Sxy150489 	}
11665779Sxy150489 
11678571SChenlu.Chen@Sun.COM 	hw->mac.get_link_status = true;
11685779Sxy150489 
11695779Sxy150489 out:
11705779Sxy150489 	return (ret_val);
11715779Sxy150489 }
11725779Sxy150489 
11735779Sxy150489 /*
11745779Sxy150489  * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
11755779Sxy150489  * @hw: pointer to the HW structure
11765779Sxy150489  *
11775779Sxy150489  * Reads the MII auto-neg advertisement register and/or the 1000T control
11785779Sxy150489  * register and if the PHY is already setup for auto-negotiation, then
11795779Sxy150489  * return successful.  Otherwise, setup advertisement and flow control to
11805779Sxy150489  * the appropriate values for the wanted auto-negotiation.
11815779Sxy150489  */
11825779Sxy150489 s32
11835779Sxy150489 e1000_phy_setup_autoneg(struct e1000_hw *hw)
11845779Sxy150489 {
11855779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
11865779Sxy150489 	s32 ret_val;
11875779Sxy150489 	u16 mii_autoneg_adv_reg;
11885779Sxy150489 	u16 mii_1000t_ctrl_reg = 0;
11895779Sxy150489 
11905779Sxy150489 	DEBUGFUNC("e1000_phy_setup_autoneg");
11915779Sxy150489 
11925779Sxy150489 	phy->autoneg_advertised &= phy->autoneg_mask;
11935779Sxy150489 
11945779Sxy150489 	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
11958571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
11965779Sxy150489 	if (ret_val)
11975779Sxy150489 		goto out;
11985779Sxy150489 
11995779Sxy150489 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
12005779Sxy150489 		/* Read the MII 1000Base-T Control Register (Address 9). */
12018571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
12028571SChenlu.Chen@Sun.COM 		    &mii_1000t_ctrl_reg);
12035779Sxy150489 		if (ret_val)
12045779Sxy150489 			goto out;
12055779Sxy150489 	}
12065779Sxy150489 
12075779Sxy150489 	/*
12085779Sxy150489 	 * Need to parse both autoneg_advertised and fc and set up
12095779Sxy150489 	 * the appropriate PHY registers.  First we will parse for
12105779Sxy150489 	 * autoneg_advertised software override.  Since we can advertise
12115779Sxy150489 	 * a plethora of combinations, we need to check each bit
12125779Sxy150489 	 * individually.
12135779Sxy150489 	 */
12145779Sxy150489 
12155779Sxy150489 	/*
12165779Sxy150489 	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
12175779Sxy150489 	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
12185779Sxy150489 	 * the  1000Base-T Control Register (Address 9).
12195779Sxy150489 	 */
12205779Sxy150489 	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
12215779Sxy150489 	    NWAY_AR_100TX_HD_CAPS |
12225779Sxy150489 	    NWAY_AR_10T_FD_CAPS   |
12235779Sxy150489 	    NWAY_AR_10T_HD_CAPS);
12245779Sxy150489 	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
12255779Sxy150489 
12265779Sxy150489 	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
12275779Sxy150489 
12285779Sxy150489 	/* Do we want to advertise 10 Mb Half Duplex? */
12295779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
12305779Sxy150489 		DEBUGOUT("Advertise 10mb Half duplex\n");
12315779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
12325779Sxy150489 	}
12335779Sxy150489 
12345779Sxy150489 	/* Do we want to advertise 10 Mb Full Duplex? */
12355779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
12365779Sxy150489 		DEBUGOUT("Advertise 10mb Full duplex\n");
12375779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
12385779Sxy150489 	}
12395779Sxy150489 
12405779Sxy150489 	/* Do we want to advertise 100 Mb Half Duplex? */
12415779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
12425779Sxy150489 		DEBUGOUT("Advertise 100mb Half duplex\n");
12435779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
12445779Sxy150489 	}
12455779Sxy150489 
12465779Sxy150489 	/* Do we want to advertise 100 Mb Full Duplex? */
12475779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
12485779Sxy150489 		DEBUGOUT("Advertise 100mb Full duplex\n");
12495779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
12505779Sxy150489 	}
12515779Sxy150489 
12525779Sxy150489 	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
12538571SChenlu.Chen@Sun.COM 	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
12545779Sxy150489 		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
12555779Sxy150489 
12565779Sxy150489 	/* Do we want to advertise 1000 Mb Full Duplex? */
12575779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
12585779Sxy150489 		DEBUGOUT("Advertise 1000mb Full duplex\n");
12595779Sxy150489 		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
12605779Sxy150489 	}
12615779Sxy150489 
12625779Sxy150489 	/*
12635779Sxy150489 	 * Check for a software override of the flow control settings, and
12645779Sxy150489 	 * setup the PHY advertisement registers accordingly.  If
12655779Sxy150489 	 * auto-negotiation is enabled, then software will have to set the
12665779Sxy150489 	 * "PAUSE" bits to the correct value in the Auto-Negotiation
12675779Sxy150489 	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
12685779Sxy150489 	 * negotiation.
12695779Sxy150489 	 *
12705779Sxy150489 	 * The possible values of the "fc" parameter are:
12715779Sxy150489 	 * 0:	Flow control is completely disabled
12725779Sxy150489 	 * 1:	Rx flow control is enabled (we can receive pause frames
12735779Sxy150489 	 *	but not send pause frames).
12745779Sxy150489 	 * 2:	Tx flow control is enabled (we can send pause frames
12755779Sxy150489 	 *	but we do not support receiving pause frames).
12765779Sxy150489 	 * 3:	Both Rx and Tx flow control (symmetric) are enabled.
12775779Sxy150489 	 * other: No software override.  The flow control configuration
12785779Sxy150489 	 *	in the EEPROM is used.
12795779Sxy150489 	 */
12808571SChenlu.Chen@Sun.COM 	switch (hw->fc.current_mode) {
12815779Sxy150489 	case e1000_fc_none:
12825779Sxy150489 		/*
12835779Sxy150489 		 * Flow control (Rx & Tx) is completely disabled by a
12845779Sxy150489 		 * software over-ride.
12855779Sxy150489 		 */
12865779Sxy150489 		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
12875779Sxy150489 		break;
12885779Sxy150489 	case e1000_fc_rx_pause:
12895779Sxy150489 		/*
12905779Sxy150489 		 * Rx Flow control is enabled, and Tx Flow control is
12915779Sxy150489 		 * disabled, by a software over-ride.
12925779Sxy150489 		 *
12935779Sxy150489 		 * Since there really isn't a way to advertise that we are
12945779Sxy150489 		 * capable of Rx Pause ONLY, we will advertise that we
12955779Sxy150489 		 * support both symmetric and asymmetric Rx PAUSE.  Later
12965779Sxy150489 		 * (in e1000_config_fc_after_link_up) we will disable the
12975779Sxy150489 		 * hw's ability to send PAUSE frames.
12985779Sxy150489 		 */
12995779Sxy150489 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
13005779Sxy150489 		break;
13015779Sxy150489 	case e1000_fc_tx_pause:
13025779Sxy150489 		/*
13035779Sxy150489 		 * Tx Flow control is enabled, and Rx Flow control is
13045779Sxy150489 		 * disabled, by a software over-ride.
13055779Sxy150489 		 */
13065779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
13075779Sxy150489 		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
13085779Sxy150489 		break;
13095779Sxy150489 	case e1000_fc_full:
13105779Sxy150489 		/*
13115779Sxy150489 		 * Flow control (both Rx and Tx) is enabled by a software
13125779Sxy150489 		 * over-ride.
13135779Sxy150489 		 */
13145779Sxy150489 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
13155779Sxy150489 		break;
13165779Sxy150489 	default:
13175779Sxy150489 		DEBUGOUT("Flow control param set incorrectly\n");
13185779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
13195779Sxy150489 		goto out;
13205779Sxy150489 	}
13215779Sxy150489 
13228571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
13235779Sxy150489 	if (ret_val)
13245779Sxy150489 		goto out;
13255779Sxy150489 
13265779Sxy150489 	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
13275779Sxy150489 
13285779Sxy150489 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
13298571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
13305779Sxy150489 		    PHY_1000T_CTRL, mii_1000t_ctrl_reg);
13315779Sxy150489 		if (ret_val)
13325779Sxy150489 			goto out;
13335779Sxy150489 	}
13345779Sxy150489 
13355779Sxy150489 out:
13365779Sxy150489 	return (ret_val);
13375779Sxy150489 }
13385779Sxy150489 
13395779Sxy150489 /*
13405779Sxy150489  * e1000_setup_copper_link_generic - Configure copper link settings
13415779Sxy150489  * @hw: pointer to the HW structure
13425779Sxy150489  *
13435779Sxy150489  * Calls the appropriate function to configure the link for auto-neg or forced
13445779Sxy150489  * speed and duplex.  Then we check for link, once link is established calls
13455779Sxy150489  * to configure collision distance and flow control are called.  If link is
13465779Sxy150489  * not established, we return -E1000_ERR_PHY (-2).
13475779Sxy150489  */
13485779Sxy150489 s32
13495779Sxy150489 e1000_setup_copper_link_generic(struct e1000_hw *hw)
13505779Sxy150489 {
13515779Sxy150489 	s32 ret_val;
13525779Sxy150489 	bool link;
13535779Sxy150489 
13545779Sxy150489 	DEBUGFUNC("e1000_setup_copper_link_generic");
13555779Sxy150489 
13565779Sxy150489 	if (hw->mac.autoneg) {
13575779Sxy150489 		/*
13585779Sxy150489 		 * Setup autoneg and flow control advertisement and perform
13595779Sxy150489 		 * autonegotiation.
13605779Sxy150489 		 */
13615779Sxy150489 		ret_val = e1000_copper_link_autoneg(hw);
13625779Sxy150489 		if (ret_val)
13635779Sxy150489 			goto out;
13645779Sxy150489 	} else {
13655779Sxy150489 		/*
13665779Sxy150489 		 * PHY will be set to 10H, 10F, 100H or 100F
13675779Sxy150489 		 * depending on user settings.
13685779Sxy150489 		 */
13695779Sxy150489 		DEBUGOUT("Forcing Speed and Duplex\n");
13708571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.force_speed_duplex(hw);
13715779Sxy150489 		if (ret_val) {
13725779Sxy150489 			DEBUGOUT("Error Forcing Speed and Duplex\n");
13735779Sxy150489 			goto out;
13745779Sxy150489 		}
13755779Sxy150489 	}
13765779Sxy150489 
13775779Sxy150489 	/*
13785779Sxy150489 	 * Check link status. Wait up to 100 microseconds for link to become
13795779Sxy150489 	 * valid.
13805779Sxy150489 	 */
13815779Sxy150489 	ret_val = e1000_phy_has_link_generic(hw,
13825779Sxy150489 	    COPPER_LINK_UP_LIMIT,
13835779Sxy150489 	    10,
13845779Sxy150489 	    &link);
13855779Sxy150489 	if (ret_val)
13865779Sxy150489 		goto out;
13875779Sxy150489 
13885779Sxy150489 	if (link) {
13895779Sxy150489 		DEBUGOUT("Valid link established!!!\n");
13905779Sxy150489 		e1000_config_collision_dist_generic(hw);
13915779Sxy150489 		ret_val = e1000_config_fc_after_link_up_generic(hw);
13925779Sxy150489 	} else {
13935779Sxy150489 		DEBUGOUT("Unable to establish link!!!\n");
13945779Sxy150489 	}
13955779Sxy150489 
13965779Sxy150489 out:
13975779Sxy150489 	return (ret_val);
13985779Sxy150489 }
13995779Sxy150489 
14005779Sxy150489 /*
14015779Sxy150489  * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
14025779Sxy150489  * @hw: pointer to the HW structure
14035779Sxy150489  *
14045779Sxy150489  * Calls the PHY setup function to force speed and duplex.  Clears the
14055779Sxy150489  * auto-crossover to force MDI manually.  Waits for link and returns
14065779Sxy150489  * successful if link up is successful, else -E1000_ERR_PHY (-2).
14075779Sxy150489  */
14085779Sxy150489 s32
14095779Sxy150489 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
14105779Sxy150489 {
14115779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
14125779Sxy150489 	s32 ret_val;
14135779Sxy150489 	u16 phy_data;
14145779Sxy150489 	bool link;
14155779Sxy150489 
14165779Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
14175779Sxy150489 
14188571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
14195779Sxy150489 	if (ret_val)
14205779Sxy150489 		goto out;
14215779Sxy150489 
14225779Sxy150489 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
14235779Sxy150489 
14248571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
14255779Sxy150489 	if (ret_val)
14265779Sxy150489 		goto out;
14275779Sxy150489 
14285779Sxy150489 	/*
14295779Sxy150489 	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
14305779Sxy150489 	 * forced whenever speed and duplex are forced.
14315779Sxy150489 	 */
14328571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
14335779Sxy150489 	if (ret_val)
14345779Sxy150489 		goto out;
14355779Sxy150489 
14365779Sxy150489 	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
14375779Sxy150489 	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
14385779Sxy150489 
14398571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
14405779Sxy150489 	if (ret_val)
14415779Sxy150489 		goto out;
14425779Sxy150489 
14435779Sxy150489 	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
14445779Sxy150489 
14455779Sxy150489 	usec_delay(1);
14465779Sxy150489 
14475779Sxy150489 	if (phy->autoneg_wait_to_complete) {
14485779Sxy150489 		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
14495779Sxy150489 
14505779Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
14515779Sxy150489 		    PHY_FORCE_LIMIT,
14525779Sxy150489 		    100000,
14535779Sxy150489 		    &link);
14545779Sxy150489 		if (ret_val)
14555779Sxy150489 			goto out;
14565779Sxy150489 
14578571SChenlu.Chen@Sun.COM 		if (!link)
14585779Sxy150489 			DEBUGOUT("Link taking longer than expected.\n");
14595779Sxy150489 
14605779Sxy150489 		/* Try once more */
14615779Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
14625779Sxy150489 		    PHY_FORCE_LIMIT,
14635779Sxy150489 		    100000,
14645779Sxy150489 		    &link);
14655779Sxy150489 		if (ret_val)
14665779Sxy150489 			goto out;
14675779Sxy150489 	}
14685779Sxy150489 
14695779Sxy150489 out:
14705779Sxy150489 	return (ret_val);
14715779Sxy150489 }
14725779Sxy150489 
14735779Sxy150489 /*
14745779Sxy150489  * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
14755779Sxy150489  * @hw: pointer to the HW structure
14765779Sxy150489  *
14775779Sxy150489  * Calls the PHY setup function to force speed and duplex.  Clears the
14785779Sxy150489  * auto-crossover to force MDI manually.  Resets the PHY to commit the
14795779Sxy150489  * changes.  If time expires while waiting for link up, we reset the DSP.
14805779Sxy150489  * After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
14815779Sxy150489  * successful completion, else return corresponding error code.
14825779Sxy150489  */
14835779Sxy150489 s32
14845779Sxy150489 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
14855779Sxy150489 {
14865779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
14875779Sxy150489 	s32 ret_val;
14885779Sxy150489 	u16 phy_data;
14895779Sxy150489 	bool link;
14905779Sxy150489 
14915779Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
14925779Sxy150489 
14935779Sxy150489 	/*
14945779Sxy150489 	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
14955779Sxy150489 	 * forced whenever speed and duplex are forced.
14965779Sxy150489 	 */
14978571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
14985779Sxy150489 	if (ret_val)
14995779Sxy150489 		goto out;
15005779Sxy150489 
15015779Sxy150489 	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
15028571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
15035779Sxy150489 	if (ret_val)
15045779Sxy150489 		goto out;
15055779Sxy150489 
15065779Sxy150489 	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
15075779Sxy150489 
15088571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
15095779Sxy150489 	if (ret_val)
15105779Sxy150489 		goto out;
15115779Sxy150489 
15125779Sxy150489 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
15135779Sxy150489 
15148571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
15155779Sxy150489 	if (ret_val)
15165779Sxy150489 		goto out;
15175779Sxy150489 
15188571SChenlu.Chen@Sun.COM 	/* Reset the phy to commit changes. */
15198571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.commit(hw);
15208571SChenlu.Chen@Sun.COM 	if (ret_val)
15218571SChenlu.Chen@Sun.COM 		goto out;
15225779Sxy150489 
15235779Sxy150489 	if (phy->autoneg_wait_to_complete) {
15245779Sxy150489 		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
15255779Sxy150489 
15268571SChenlu.Chen@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
15278571SChenlu.Chen@Sun.COM 		    100000, &link);
15285779Sxy150489 		if (ret_val)
15295779Sxy150489 			goto out;
15305779Sxy150489 
15315779Sxy150489 		if (!link) {
15325779Sxy150489 			/*
15335779Sxy150489 			 * We didn't get link.
15345779Sxy150489 			 * Reset the DSP and cross our fingers.
15355779Sxy150489 			 */
15368571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
15375779Sxy150489 			    M88E1000_PHY_PAGE_SELECT,
15385779Sxy150489 			    0x001d);
15395779Sxy150489 			if (ret_val)
15405779Sxy150489 				goto out;
15415779Sxy150489 			ret_val = e1000_phy_reset_dsp_generic(hw);
15425779Sxy150489 			if (ret_val)
15435779Sxy150489 				goto out;
15445779Sxy150489 		}
15455779Sxy150489 
15465779Sxy150489 		/* Try once more */
15478571SChenlu.Chen@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
15488571SChenlu.Chen@Sun.COM 		    100000, &link);
15495779Sxy150489 		if (ret_val)
15505779Sxy150489 			goto out;
15515779Sxy150489 	}
15525779Sxy150489 
15538571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
15545779Sxy150489 	if (ret_val)
15555779Sxy150489 		goto out;
15565779Sxy150489 
15575779Sxy150489 	/*
15585779Sxy150489 	 * Resetting the phy means we need to re-force TX_CLK in the
15595779Sxy150489 	 * Extended PHY Specific Control Register to 25MHz clock from
15605779Sxy150489 	 * the reset value of 2.5MHz.
15615779Sxy150489 	 */
15625779Sxy150489 	phy_data |= M88E1000_EPSCR_TX_CLK_25;
15638571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
15645779Sxy150489 	if (ret_val)
15655779Sxy150489 		goto out;
15665779Sxy150489 
15675779Sxy150489 	/*
15685779Sxy150489 	 * In addition, we must re-enable CRS on Tx for both half and full
15695779Sxy150489 	 * duplex.
15705779Sxy150489 	 */
15718571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
15725779Sxy150489 	if (ret_val)
15735779Sxy150489 		goto out;
15745779Sxy150489 
15755779Sxy150489 	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
15768571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
15775779Sxy150489 
15785779Sxy150489 out:
15795779Sxy150489 	return (ret_val);
15805779Sxy150489 }
15815779Sxy150489 
15825779Sxy150489 /*
158310319SJason.Xu@Sun.COM  * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
158410319SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
158510319SJason.Xu@Sun.COM  *
158610319SJason.Xu@Sun.COM  * Forces the speed and duplex settings of the PHY.
158710319SJason.Xu@Sun.COM  * This is a function pointer entry point only called by
158810319SJason.Xu@Sun.COM  * PHY setup routines.
158910319SJason.Xu@Sun.COM  */
159010319SJason.Xu@Sun.COM s32
159110319SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
159210319SJason.Xu@Sun.COM {
159310319SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
159410319SJason.Xu@Sun.COM 	s32 ret_val;
159510319SJason.Xu@Sun.COM 	u16 data;
159610319SJason.Xu@Sun.COM 	bool link;
159710319SJason.Xu@Sun.COM 
159810319SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
159910319SJason.Xu@Sun.COM 
160010319SJason.Xu@Sun.COM 	if (phy->type != e1000_phy_ife) {
160110319SJason.Xu@Sun.COM 		ret_val = e1000_phy_force_speed_duplex_igp(hw);
160210319SJason.Xu@Sun.COM 		goto out;
160310319SJason.Xu@Sun.COM 	}
160410319SJason.Xu@Sun.COM 
160510319SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
160610319SJason.Xu@Sun.COM 	if (ret_val)
160710319SJason.Xu@Sun.COM 		goto out;
160810319SJason.Xu@Sun.COM 
160910319SJason.Xu@Sun.COM 	e1000_phy_force_speed_duplex_setup(hw, &data);
161010319SJason.Xu@Sun.COM 
161110319SJason.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
161210319SJason.Xu@Sun.COM 	if (ret_val)
161310319SJason.Xu@Sun.COM 		goto out;
161410319SJason.Xu@Sun.COM 
161510319SJason.Xu@Sun.COM 	/* Disable MDI-X support for 10/100 */
161610319SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
161710319SJason.Xu@Sun.COM 	if (ret_val)
161810319SJason.Xu@Sun.COM 		goto out;
161910319SJason.Xu@Sun.COM 
162010319SJason.Xu@Sun.COM 	data &= ~IFE_PMC_AUTO_MDIX;
162110319SJason.Xu@Sun.COM 	data &= ~IFE_PMC_FORCE_MDIX;
162210319SJason.Xu@Sun.COM 
162310319SJason.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
162410319SJason.Xu@Sun.COM 	if (ret_val)
162510319SJason.Xu@Sun.COM 		goto out;
162610319SJason.Xu@Sun.COM 
162710319SJason.Xu@Sun.COM 	DEBUGOUT1("IFE PMC: %X\n", data);
162810319SJason.Xu@Sun.COM 
162910319SJason.Xu@Sun.COM 	usec_delay(1);
163010319SJason.Xu@Sun.COM 
163110319SJason.Xu@Sun.COM 	if (phy->autoneg_wait_to_complete) {
163210319SJason.Xu@Sun.COM 		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
163310319SJason.Xu@Sun.COM 
163410319SJason.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
163510319SJason.Xu@Sun.COM 		    PHY_FORCE_LIMIT, 100000, &link);
163610319SJason.Xu@Sun.COM 		if (ret_val)
163710319SJason.Xu@Sun.COM 			goto out;
163810319SJason.Xu@Sun.COM 
163910319SJason.Xu@Sun.COM 		if (!link)
164010319SJason.Xu@Sun.COM 			DEBUGOUT("Link taking longer than expected.\n");
164110319SJason.Xu@Sun.COM 
164210319SJason.Xu@Sun.COM 		/* Try once more */
164310319SJason.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
164410319SJason.Xu@Sun.COM 		    PHY_FORCE_LIMIT, 100000, &link);
164510319SJason.Xu@Sun.COM 		if (ret_val)
164610319SJason.Xu@Sun.COM 			goto out;
164710319SJason.Xu@Sun.COM 	}
164810319SJason.Xu@Sun.COM 
164910319SJason.Xu@Sun.COM out:
165010319SJason.Xu@Sun.COM 	return (ret_val);
165110319SJason.Xu@Sun.COM }
165210319SJason.Xu@Sun.COM /*
16535779Sxy150489  * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
16545779Sxy150489  * @hw: pointer to the HW structure
16555779Sxy150489  * @phy_ctrl: pointer to current value of PHY_CONTROL
16565779Sxy150489  *
16575779Sxy150489  * Forces speed and duplex on the PHY by doing the following: disable flow
16585779Sxy150489  * control, force speed/duplex on the MAC, disable auto speed detection,
16595779Sxy150489  * disable auto-negotiation, configure duplex, configure speed, configure
16605779Sxy150489  * the collision distance, write configuration to CTRL register.  The
16615779Sxy150489  * caller must write to the PHY_CONTROL register for these settings to
16625779Sxy150489  * take affect.
16635779Sxy150489  */
16645779Sxy150489 void
16655779Sxy150489 e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
16665779Sxy150489 {
16675779Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
16685779Sxy150489 	u32 ctrl;
16695779Sxy150489 
16705779Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
16715779Sxy150489 
16725779Sxy150489 	/* Turn off flow control when forcing speed/duplex */
16738571SChenlu.Chen@Sun.COM 	hw->fc.current_mode = e1000_fc_none;
16745779Sxy150489 
16755779Sxy150489 	/* Force speed/duplex on the mac */
16765779Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
16775779Sxy150489 	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
16785779Sxy150489 	ctrl &= ~E1000_CTRL_SPD_SEL;
16795779Sxy150489 
16805779Sxy150489 	/* Disable Auto Speed Detection */
16815779Sxy150489 	ctrl &= ~E1000_CTRL_ASDE;
16825779Sxy150489 
16835779Sxy150489 	/* Disable autoneg on the phy */
16845779Sxy150489 	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
16855779Sxy150489 
16865779Sxy150489 	/* Forcing Full or Half Duplex? */
16875779Sxy150489 	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
16885779Sxy150489 		ctrl &= ~E1000_CTRL_FD;
16895779Sxy150489 		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
16905779Sxy150489 		DEBUGOUT("Half Duplex\n");
16915779Sxy150489 	} else {
16925779Sxy150489 		ctrl |= E1000_CTRL_FD;
16935779Sxy150489 		*phy_ctrl |= MII_CR_FULL_DUPLEX;
16945779Sxy150489 		DEBUGOUT("Full Duplex\n");
16955779Sxy150489 	}
16965779Sxy150489 
16975779Sxy150489 	/* Forcing 10mb or 100mb? */
16985779Sxy150489 	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
16995779Sxy150489 		ctrl |= E1000_CTRL_SPD_100;
17005779Sxy150489 		*phy_ctrl |= MII_CR_SPEED_100;
17015779Sxy150489 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
17025779Sxy150489 		DEBUGOUT("Forcing 100mb\n");
17035779Sxy150489 	} else {
17045779Sxy150489 		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
17055779Sxy150489 		/* LINTED */
17065779Sxy150489 		*phy_ctrl |= MII_CR_SPEED_10;
17075779Sxy150489 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
17085779Sxy150489 		DEBUGOUT("Forcing 10mb\n");
17095779Sxy150489 	}
17105779Sxy150489 
17115779Sxy150489 	e1000_config_collision_dist_generic(hw);
17125779Sxy150489 
17135779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
17145779Sxy150489 }
17155779Sxy150489 
17165779Sxy150489 /*
17175779Sxy150489  * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
17185779Sxy150489  * @hw: pointer to the HW structure
17195779Sxy150489  * @active: boolean used to enable/disable lplu
17205779Sxy150489  *
17215779Sxy150489  * Success returns 0, Failure returns 1
17225779Sxy150489  *
17235779Sxy150489  * The low power link up (lplu) state is set to the power management level D3
17245779Sxy150489  * and SmartSpeed is disabled when active is true, else clear lplu for D3
17255779Sxy150489  * and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
17265779Sxy150489  * is used during Dx states where the power conservation is most important.
17275779Sxy150489  * During driver activity, SmartSpeed should be enabled so performance is
17285779Sxy150489  * maintained.
17295779Sxy150489  */
17305779Sxy150489 s32
17315779Sxy150489 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
17325779Sxy150489 {
17335779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
17348571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
17355779Sxy150489 	u16 data;
17365779Sxy150489 
17375779Sxy150489 	DEBUGFUNC("e1000_set_d3_lplu_state_generic");
17385779Sxy150489 
17398571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
17408571SChenlu.Chen@Sun.COM 		goto out;
17418571SChenlu.Chen@Sun.COM 
17428571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
17435779Sxy150489 	if (ret_val)
17445779Sxy150489 		goto out;
17455779Sxy150489 
17465779Sxy150489 	if (!active) {
17475779Sxy150489 		data &= ~IGP02E1000_PM_D3_LPLU;
17488571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
17495779Sxy150489 		    IGP02E1000_PHY_POWER_MGMT,
17505779Sxy150489 		    data);
17515779Sxy150489 		if (ret_val)
17525779Sxy150489 			goto out;
17535779Sxy150489 		/*
17545779Sxy150489 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
17555779Sxy150489 		 * during Dx states where the power conservation is most
17565779Sxy150489 		 * important.  During driver activity we should enable
17575779Sxy150489 		 * SmartSpeed, so performance is maintained.
17585779Sxy150489 		 */
17595779Sxy150489 		if (phy->smart_speed == e1000_smart_speed_on) {
17608571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw,
17615779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
17625779Sxy150489 			    &data);
17635779Sxy150489 			if (ret_val)
17645779Sxy150489 				goto out;
17655779Sxy150489 
17665779Sxy150489 			data |= IGP01E1000_PSCFR_SMART_SPEED;
17678571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
17685779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
17695779Sxy150489 			    data);
17705779Sxy150489 			if (ret_val)
17715779Sxy150489 				goto out;
17725779Sxy150489 		} else if (phy->smart_speed == e1000_smart_speed_off) {
17738571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw,
17745779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
17755779Sxy150489 			    &data);
17765779Sxy150489 			if (ret_val)
17775779Sxy150489 				goto out;
17785779Sxy150489 
17795779Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
17808571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
17815779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
17825779Sxy150489 			    data);
17835779Sxy150489 			if (ret_val)
17845779Sxy150489 				goto out;
17855779Sxy150489 		}
17865779Sxy150489 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
17875779Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
17885779Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
17895779Sxy150489 		data |= IGP02E1000_PM_D3_LPLU;
17908571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
17915779Sxy150489 		    IGP02E1000_PHY_POWER_MGMT,
17925779Sxy150489 		    data);
17935779Sxy150489 		if (ret_val)
17945779Sxy150489 			goto out;
17955779Sxy150489 
17965779Sxy150489 		/* When LPLU is enabled, we should disable SmartSpeed */
17978571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw,
17985779Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
17995779Sxy150489 		    &data);
18005779Sxy150489 		if (ret_val)
18015779Sxy150489 			goto out;
18025779Sxy150489 
18035779Sxy150489 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
18048571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
18055779Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
18065779Sxy150489 		    data);
18075779Sxy150489 	}
18085779Sxy150489 
18095779Sxy150489 out:
18105779Sxy150489 	return (ret_val);
18115779Sxy150489 }
18125779Sxy150489 
18135779Sxy150489 /*
18148571SChenlu.Chen@Sun.COM  * e1000_check_downshift_generic - Checks whether a downshift in speed occurred
18155779Sxy150489  * @hw: pointer to the HW structure
18165779Sxy150489  *
18175779Sxy150489  * Success returns 0, Failure returns 1
18185779Sxy150489  *
18195779Sxy150489  * A downshift is detected by querying the PHY link health.
18205779Sxy150489  */
18215779Sxy150489 s32
18225779Sxy150489 e1000_check_downshift_generic(struct e1000_hw *hw)
18235779Sxy150489 {
18245779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
18255779Sxy150489 	s32 ret_val;
18265779Sxy150489 	u16 phy_data, offset, mask;
18275779Sxy150489 
18285779Sxy150489 	DEBUGFUNC("e1000_check_downshift_generic");
18295779Sxy150489 
18305779Sxy150489 	switch (phy->type) {
18315779Sxy150489 	case e1000_phy_m88:
18325779Sxy150489 	case e1000_phy_gg82563:
18335779Sxy150489 		offset	= M88E1000_PHY_SPEC_STATUS;
18345779Sxy150489 		mask	= M88E1000_PSSR_DOWNSHIFT;
18355779Sxy150489 		break;
18365779Sxy150489 	case e1000_phy_igp_2:
18375779Sxy150489 	case e1000_phy_igp:
18385779Sxy150489 	case e1000_phy_igp_3:
18395779Sxy150489 		offset	= IGP01E1000_PHY_LINK_HEALTH;
18405779Sxy150489 		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
18415779Sxy150489 		break;
18425779Sxy150489 	default:
18435779Sxy150489 		/* speed downshift not supported */
18448571SChenlu.Chen@Sun.COM 		phy->speed_downgraded = false;
18455779Sxy150489 		ret_val = E1000_SUCCESS;
18465779Sxy150489 		goto out;
18475779Sxy150489 	}
18485779Sxy150489 
18498571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
18505779Sxy150489 
18515779Sxy150489 	if (!ret_val)
18528571SChenlu.Chen@Sun.COM 		phy->speed_downgraded = (phy_data & mask) ? true : false;
18535779Sxy150489 
18545779Sxy150489 out:
18555779Sxy150489 	return (ret_val);
18565779Sxy150489 }
18575779Sxy150489 
18585779Sxy150489 /*
18595779Sxy150489  * e1000_check_polarity_m88 - Checks the polarity.
18605779Sxy150489  * @hw: pointer to the HW structure
18615779Sxy150489  *
18625779Sxy150489  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
18635779Sxy150489  *
18645779Sxy150489  * Polarity is determined based on the PHY specific status register.
18655779Sxy150489  */
18665779Sxy150489 s32
18675779Sxy150489 e1000_check_polarity_m88(struct e1000_hw *hw)
18685779Sxy150489 {
18695779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
18705779Sxy150489 	s32 ret_val;
18715779Sxy150489 	u16 data;
18725779Sxy150489 
18735779Sxy150489 	DEBUGFUNC("e1000_check_polarity_m88");
18745779Sxy150489 
18758571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
18765779Sxy150489 
18775779Sxy150489 	if (!ret_val)
18785779Sxy150489 		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
18795779Sxy150489 		    ? e1000_rev_polarity_reversed
18805779Sxy150489 		    : e1000_rev_polarity_normal;
18815779Sxy150489 
18825779Sxy150489 	return (ret_val);
18835779Sxy150489 }
18845779Sxy150489 
18855779Sxy150489 /*
18865779Sxy150489  * e1000_check_polarity_igp - Checks the polarity.
18875779Sxy150489  * @hw: pointer to the HW structure
18885779Sxy150489  *
18895779Sxy150489  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
18905779Sxy150489  *
18915779Sxy150489  * Polarity is determined based on the PHY port status register, and the
18925779Sxy150489  * current speed (since there is no polarity at 100Mbps).
18935779Sxy150489  */
18945779Sxy150489 s32
18955779Sxy150489 e1000_check_polarity_igp(struct e1000_hw *hw)
18965779Sxy150489 {
18975779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
18985779Sxy150489 	s32 ret_val;
18995779Sxy150489 	u16 data, offset, mask;
19005779Sxy150489 
19015779Sxy150489 	DEBUGFUNC("e1000_check_polarity_igp");
19025779Sxy150489 
19035779Sxy150489 	/*
19045779Sxy150489 	 * Polarity is determined based on the speed of
19055779Sxy150489 	 * our connection.
19065779Sxy150489 	 */
19078571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
19085779Sxy150489 	if (ret_val)
19095779Sxy150489 		goto out;
19105779Sxy150489 
19115779Sxy150489 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
19125779Sxy150489 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
19135779Sxy150489 		offset	= IGP01E1000_PHY_PCS_INIT_REG;
19145779Sxy150489 		mask	= IGP01E1000_PHY_POLARITY_MASK;
19155779Sxy150489 	} else {
19165779Sxy150489 		/*
19175779Sxy150489 		 * This really only applies to 10Mbps since
19185779Sxy150489 		 * there is no polarity for 100Mbps (always 0).
19195779Sxy150489 		 */
19205779Sxy150489 		offset	= IGP01E1000_PHY_PORT_STATUS;
19215779Sxy150489 		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
19225779Sxy150489 	}
19235779Sxy150489 
19248571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, offset, &data);
19255779Sxy150489 
19265779Sxy150489 	if (!ret_val)
19275779Sxy150489 		phy->cable_polarity = (data & mask)
19285779Sxy150489 		    ? e1000_rev_polarity_reversed
19295779Sxy150489 		    : e1000_rev_polarity_normal;
19305779Sxy150489 
19315779Sxy150489 out:
19325779Sxy150489 	return (ret_val);
19335779Sxy150489 }
19345779Sxy150489 
19355779Sxy150489 /*
193610319SJason.Xu@Sun.COM  * e1000_check_polarity_ife - Check cable polarity for IFE PHY
193710319SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
193810319SJason.Xu@Sun.COM  *
193910319SJason.Xu@Sun.COM  * Polarity is determined on the polarity reversal feature being enabled.
194010319SJason.Xu@Sun.COM  */
194110319SJason.Xu@Sun.COM s32
194210319SJason.Xu@Sun.COM e1000_check_polarity_ife(struct e1000_hw *hw)
194310319SJason.Xu@Sun.COM {
194410319SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
194510319SJason.Xu@Sun.COM 	s32 ret_val;
194610319SJason.Xu@Sun.COM 	u16 phy_data, offset, mask;
194710319SJason.Xu@Sun.COM 
194810319SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_check_polarity_ife");
194910319SJason.Xu@Sun.COM 
195010319SJason.Xu@Sun.COM 	/*
195110319SJason.Xu@Sun.COM 	 * Polarity is determined based on the reversal feature being enabled.
195210319SJason.Xu@Sun.COM 	 */
195310319SJason.Xu@Sun.COM 	if (phy->polarity_correction) {
195410319SJason.Xu@Sun.COM 		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
195510319SJason.Xu@Sun.COM 		mask = IFE_PESC_POLARITY_REVERSED;
195610319SJason.Xu@Sun.COM 	} else {
195710319SJason.Xu@Sun.COM 		offset = IFE_PHY_SPECIAL_CONTROL;
195810319SJason.Xu@Sun.COM 		mask = IFE_PSC_FORCE_POLARITY;
195910319SJason.Xu@Sun.COM 	}
196010319SJason.Xu@Sun.COM 
196110319SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
196210319SJason.Xu@Sun.COM 
196310319SJason.Xu@Sun.COM 	if (!ret_val)
196410319SJason.Xu@Sun.COM 		phy->cable_polarity = (phy_data & mask)
196510319SJason.Xu@Sun.COM 		    ? e1000_rev_polarity_reversed
196610319SJason.Xu@Sun.COM 		    : e1000_rev_polarity_normal;
196710319SJason.Xu@Sun.COM 
196810319SJason.Xu@Sun.COM 	return (ret_val);
196910319SJason.Xu@Sun.COM }
197010319SJason.Xu@Sun.COM /*
19718571SChenlu.Chen@Sun.COM  * e1000_wait_autoneg_generic - Wait for auto-neg completion
19725779Sxy150489  * @hw: pointer to the HW structure
19735779Sxy150489  *
19745779Sxy150489  * Waits for auto-negotiation to complete or for the auto-negotiation time
19755779Sxy150489  * limit to expire, which ever happens first.
19765779Sxy150489  */
19775779Sxy150489 s32
19785779Sxy150489 e1000_wait_autoneg_generic(struct e1000_hw *hw)
19795779Sxy150489 {
19805779Sxy150489 	s32 ret_val = E1000_SUCCESS;
19815779Sxy150489 	u16 i, phy_status;
19825779Sxy150489 
19835779Sxy150489 	DEBUGFUNC("e1000_wait_autoneg_generic");
19845779Sxy150489 
19858571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
19868571SChenlu.Chen@Sun.COM 		return (E1000_SUCCESS);
19878571SChenlu.Chen@Sun.COM 
19885779Sxy150489 	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
19895779Sxy150489 	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
19908571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
19915779Sxy150489 		if (ret_val)
19925779Sxy150489 			break;
19938571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
19945779Sxy150489 		if (ret_val)
19955779Sxy150489 			break;
19965779Sxy150489 		if (phy_status & MII_SR_AUTONEG_COMPLETE)
19975779Sxy150489 			break;
19985779Sxy150489 		msec_delay(100);
19995779Sxy150489 	}
20005779Sxy150489 
20015779Sxy150489 	/*
20025779Sxy150489 	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
20035779Sxy150489 	 * has completed.
20045779Sxy150489 	 */
20055779Sxy150489 	return (ret_val);
20065779Sxy150489 }
20075779Sxy150489 
20085779Sxy150489 /*
20095779Sxy150489  * e1000_phy_has_link_generic - Polls PHY for link
20105779Sxy150489  * @hw: pointer to the HW structure
20115779Sxy150489  * @iterations: number of times to poll for link
20125779Sxy150489  * @usec_interval: delay between polling attempts
20135779Sxy150489  * @success: pointer to whether polling was successful or not
20145779Sxy150489  *
20155779Sxy150489  * Polls the PHY status register for link, 'iterations' number of times.
20165779Sxy150489  */
20175779Sxy150489 s32
20185779Sxy150489 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
20195779Sxy150489     u32 usec_interval, bool *success)
20205779Sxy150489 {
20215779Sxy150489 	s32 ret_val = E1000_SUCCESS;
20225779Sxy150489 	u16 i, phy_status;
20235779Sxy150489 
20245779Sxy150489 	DEBUGFUNC("e1000_phy_has_link_generic");
20255779Sxy150489 
20268571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
20278571SChenlu.Chen@Sun.COM 		return (E1000_SUCCESS);
20288571SChenlu.Chen@Sun.COM 
20295779Sxy150489 	for (i = 0; i < iterations; i++) {
20305779Sxy150489 		/*
20315779Sxy150489 		 * Some PHYs require the PHY_STATUS register to be read
20325779Sxy150489 		 * twice due to the link bit being sticky.  No harm doing
20335779Sxy150489 		 * it across the board.
20345779Sxy150489 		 */
20358571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
203610319SJason.Xu@Sun.COM 		if (ret_val) {
203710319SJason.Xu@Sun.COM 			/*
203810319SJason.Xu@Sun.COM 			 * If the first read fails, another entity may have
203910319SJason.Xu@Sun.COM 			 * ownership of the resources, wait and try again to
204010319SJason.Xu@Sun.COM 			 * see if they have relinquished the resources yet.
204110319SJason.Xu@Sun.COM 			 */
204210319SJason.Xu@Sun.COM 			usec_delay(usec_interval);
204310319SJason.Xu@Sun.COM 		}
2044*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
20455779Sxy150489 		if (ret_val)
20465779Sxy150489 			break;
20475779Sxy150489 		if (phy_status & MII_SR_LINK_STATUS)
20485779Sxy150489 			break;
20495779Sxy150489 		if (usec_interval >= 1000)
20505779Sxy150489 			msec_delay_irq(usec_interval/1000);
20515779Sxy150489 		else
20525779Sxy150489 			usec_delay(usec_interval);
20535779Sxy150489 	}
20545779Sxy150489 
20558571SChenlu.Chen@Sun.COM 	*success = (i < iterations) ? true : false;
20565779Sxy150489 
20575779Sxy150489 	return (ret_val);
20585779Sxy150489 }
20595779Sxy150489 
20605779Sxy150489 /*
20615779Sxy150489  * e1000_get_cable_length_m88 - Determine cable length for m88 PHY
20625779Sxy150489  * @hw: pointer to the HW structure
20635779Sxy150489  *
20645779Sxy150489  * Reads the PHY specific status register to retrieve the cable length
20655779Sxy150489  * information.  The cable length is determined by averaging the minimum and
20665779Sxy150489  * maximum values to get the "average" cable length.  The m88 PHY has four
20675779Sxy150489  * possible cable length values, which are:
20685779Sxy150489  *	Register Value		Cable Length
20695779Sxy150489  *	0			< 50 meters
20705779Sxy150489  *	1			50 - 80 meters
20715779Sxy150489  *	2			80 - 110 meters
20725779Sxy150489  *	3			110 - 140 meters
20735779Sxy150489  *	4			> 140 meters
20745779Sxy150489  */
20755779Sxy150489 s32
20765779Sxy150489 e1000_get_cable_length_m88(struct e1000_hw *hw)
20775779Sxy150489 {
20785779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
20795779Sxy150489 	s32 ret_val;
20805779Sxy150489 	u16 phy_data, index;
20815779Sxy150489 
20825779Sxy150489 	DEBUGFUNC("e1000_get_cable_length_m88");
20835779Sxy150489 
20848571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
20855779Sxy150489 	if (ret_val)
20865779Sxy150489 		goto out;
20875779Sxy150489 
20885779Sxy150489 	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
20895779Sxy150489 	    M88E1000_PSSR_CABLE_LENGTH_SHIFT;
2090*11155SJason.Xu@Sun.COM 	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
2091*11155SJason.Xu@Sun.COM 		ret_val = -E1000_ERR_PHY;
209210319SJason.Xu@Sun.COM 		goto out;
209310319SJason.Xu@Sun.COM 	}
20945779Sxy150489 
209510319SJason.Xu@Sun.COM 	phy->min_cable_length = e1000_m88_cable_length_table[index];
2096*11155SJason.Xu@Sun.COM 	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
209710319SJason.Xu@Sun.COM 
209810319SJason.Xu@Sun.COM 	phy->cable_length = (phy->min_cable_length +
209910319SJason.Xu@Sun.COM 	    phy->max_cable_length) / 2;
21005779Sxy150489 
21015779Sxy150489 out:
21025779Sxy150489 	return (ret_val);
21035779Sxy150489 }
21045779Sxy150489 
21055779Sxy150489 /*
21065779Sxy150489  * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
21075779Sxy150489  * @hw: pointer to the HW structure
21085779Sxy150489  *
21095779Sxy150489  * The automatic gain control (agc) normalizes the amplitude of the
21105779Sxy150489  * received signal, adjusting for the attenuation produced by the
21118571SChenlu.Chen@Sun.COM  * cable.  By reading the AGC registers, which represent the
21128571SChenlu.Chen@Sun.COM  * combination of coarse and fine gain value, the value can be put
21135779Sxy150489  * into a lookup table to obtain the approximate cable length
21145779Sxy150489  * for each channel.
21155779Sxy150489  */
21165779Sxy150489 s32
21175779Sxy150489 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
21185779Sxy150489 {
21195779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
21205779Sxy150489 	s32 ret_val = E1000_SUCCESS;
21215779Sxy150489 	u16 phy_data, i, agc_value = 0;
21225779Sxy150489 	u16 cur_agc_index, max_agc_index = 0;
21235779Sxy150489 	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
21245779Sxy150489 	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
21255779Sxy150489 		{IGP02E1000_PHY_AGC_A,
21265779Sxy150489 		IGP02E1000_PHY_AGC_B,
21275779Sxy150489 		IGP02E1000_PHY_AGC_C,
21285779Sxy150489 		IGP02E1000_PHY_AGC_D};
21295779Sxy150489 
21305779Sxy150489 	DEBUGFUNC("e1000_get_cable_length_igp_2");
21315779Sxy150489 
21325779Sxy150489 	/* Read the AGC registers for all channels */
21335779Sxy150489 	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
21348571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
21355779Sxy150489 		if (ret_val)
21365779Sxy150489 			goto out;
21375779Sxy150489 
21385779Sxy150489 		/*
21395779Sxy150489 		 * Getting bits 15:9, which represent the combination of
21408571SChenlu.Chen@Sun.COM 		 * coarse and fine gain values.  The result is a number
21415779Sxy150489 		 * that can be put into the lookup table to obtain the
21425779Sxy150489 		 * approximate cable length.
21435779Sxy150489 		 */
21445779Sxy150489 		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
21455779Sxy150489 		    IGP02E1000_AGC_LENGTH_MASK;
21465779Sxy150489 
21475779Sxy150489 		/* Array index bound check. */
21485779Sxy150489 		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
21495779Sxy150489 		    (cur_agc_index == 0)) {
21505779Sxy150489 			ret_val = -E1000_ERR_PHY;
21515779Sxy150489 			goto out;
21525779Sxy150489 		}
21535779Sxy150489 
21545779Sxy150489 		/* Remove min & max AGC values from calculation. */
21555779Sxy150489 		if (e1000_igp_2_cable_length_table[min_agc_index] >
21565779Sxy150489 		    e1000_igp_2_cable_length_table[cur_agc_index])
21575779Sxy150489 			min_agc_index = cur_agc_index;
21585779Sxy150489 		if (e1000_igp_2_cable_length_table[max_agc_index] <
21595779Sxy150489 		    e1000_igp_2_cable_length_table[cur_agc_index])
21605779Sxy150489 			max_agc_index = cur_agc_index;
21615779Sxy150489 
21625779Sxy150489 		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
21635779Sxy150489 	}
21645779Sxy150489 
21655779Sxy150489 	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
21665779Sxy150489 	    e1000_igp_2_cable_length_table[max_agc_index]);
21675779Sxy150489 	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
21685779Sxy150489 
21695779Sxy150489 	/* Calculate cable length with the error range of +/- 10 meters. */
21705779Sxy150489 	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
21715779Sxy150489 	    (agc_value - IGP02E1000_AGC_RANGE) : 0;
21725779Sxy150489 	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
21735779Sxy150489 
21745779Sxy150489 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
21755779Sxy150489 
21765779Sxy150489 out:
21775779Sxy150489 	return (ret_val);
21785779Sxy150489 }
21795779Sxy150489 
21805779Sxy150489 /*
21815779Sxy150489  * e1000_get_phy_info_m88 - Retrieve PHY information
21825779Sxy150489  * @hw: pointer to the HW structure
21835779Sxy150489  *
21845779Sxy150489  * Valid for only copper links.  Read the PHY status register (sticky read)
21855779Sxy150489  * to verify that link is up.  Read the PHY special control register to
21865779Sxy150489  * determine the polarity and 10base-T extended distance.  Read the PHY
21875779Sxy150489  * special status register to determine MDI/MDIx and current speed.  If
21885779Sxy150489  * speed is 1000, then determine cable length, local and remote receiver.
21895779Sxy150489  */
21905779Sxy150489 s32
21915779Sxy150489 e1000_get_phy_info_m88(struct e1000_hw *hw)
21925779Sxy150489 {
21935779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
21945779Sxy150489 	s32  ret_val;
21955779Sxy150489 	u16 phy_data;
21965779Sxy150489 	bool link;
21975779Sxy150489 
21985779Sxy150489 	DEBUGFUNC("e1000_get_phy_info_m88");
21995779Sxy150489 
2200*11155SJason.Xu@Sun.COM 	if (phy->media_type != e1000_media_type_copper) {
22015779Sxy150489 		DEBUGOUT("Phy info is only valid for copper media\n");
22025779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
22035779Sxy150489 		goto out;
22045779Sxy150489 	}
22055779Sxy150489 
22065779Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
22075779Sxy150489 	if (ret_val)
22085779Sxy150489 		goto out;
22095779Sxy150489 
22105779Sxy150489 	if (!link) {
22115779Sxy150489 		DEBUGOUT("Phy info is only valid if link is up\n");
22125779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
22135779Sxy150489 		goto out;
22145779Sxy150489 	}
22155779Sxy150489 
22168571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
22175779Sxy150489 	if (ret_val)
22185779Sxy150489 		goto out;
22195779Sxy150489 
22205779Sxy150489 	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
22218571SChenlu.Chen@Sun.COM 	    ? true : false;
22225779Sxy150489 
22235779Sxy150489 	ret_val = e1000_check_polarity_m88(hw);
22245779Sxy150489 	if (ret_val)
22255779Sxy150489 		goto out;
22265779Sxy150489 
22278571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
22285779Sxy150489 	if (ret_val)
22295779Sxy150489 		goto out;
22305779Sxy150489 
22318571SChenlu.Chen@Sun.COM 	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
22325779Sxy150489 
22335779Sxy150489 	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
22348571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
22355779Sxy150489 		if (ret_val)
22365779Sxy150489 			goto out;
22375779Sxy150489 
22388571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
22395779Sxy150489 		if (ret_val)
22405779Sxy150489 			goto out;
22415779Sxy150489 
22425779Sxy150489 		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
22435779Sxy150489 		    ? e1000_1000t_rx_status_ok
22445779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
22455779Sxy150489 
22465779Sxy150489 		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
22475779Sxy150489 		    ? e1000_1000t_rx_status_ok
22485779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
22495779Sxy150489 	} else {
22505779Sxy150489 		/* Set values to "undefined" */
22515779Sxy150489 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
22525779Sxy150489 		phy->local_rx = e1000_1000t_rx_status_undefined;
22535779Sxy150489 		phy->remote_rx = e1000_1000t_rx_status_undefined;
22545779Sxy150489 	}
22555779Sxy150489 
22565779Sxy150489 out:
22575779Sxy150489 	return (ret_val);
22585779Sxy150489 }
22595779Sxy150489 
22605779Sxy150489 /*
22615779Sxy150489  * e1000_get_phy_info_igp - Retrieve igp PHY information
22625779Sxy150489  * @hw: pointer to the HW structure
22635779Sxy150489  *
22645779Sxy150489  * Read PHY status to determine if link is up.  If link is up, then
22655779Sxy150489  * set/determine 10base-T extended distance and polarity correction.  Read
22665779Sxy150489  * PHY port status to determine MDI/MDIx and speed.  Based on the speed,
22675779Sxy150489  * determine on the cable length, local and remote receiver.
22685779Sxy150489  */
22695779Sxy150489 s32
22705779Sxy150489 e1000_get_phy_info_igp(struct e1000_hw *hw)
22715779Sxy150489 {
22725779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
22735779Sxy150489 	s32 ret_val;
22745779Sxy150489 	u16 data;
22755779Sxy150489 	bool link;
22765779Sxy150489 
22775779Sxy150489 	DEBUGFUNC("e1000_get_phy_info_igp");
22785779Sxy150489 
22795779Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
22805779Sxy150489 	if (ret_val)
22815779Sxy150489 		goto out;
22825779Sxy150489 
22835779Sxy150489 	if (!link) {
22845779Sxy150489 		DEBUGOUT("Phy info is only valid if link is up\n");
22855779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
22865779Sxy150489 		goto out;
22875779Sxy150489 	}
22885779Sxy150489 
22898571SChenlu.Chen@Sun.COM 	phy->polarity_correction = true;
22905779Sxy150489 
22915779Sxy150489 	ret_val = e1000_check_polarity_igp(hw);
22925779Sxy150489 	if (ret_val)
22935779Sxy150489 		goto out;
22945779Sxy150489 
22958571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
22965779Sxy150489 	if (ret_val)
22975779Sxy150489 		goto out;
22985779Sxy150489 
22998571SChenlu.Chen@Sun.COM 	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
23005779Sxy150489 
23015779Sxy150489 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
23025779Sxy150489 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
2303*11155SJason.Xu@Sun.COM 		ret_val = phy->ops.get_cable_length(hw);
23045779Sxy150489 		if (ret_val)
23055779Sxy150489 			goto out;
23065779Sxy150489 
23078571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
23085779Sxy150489 		if (ret_val)
23095779Sxy150489 			goto out;
23105779Sxy150489 
23115779Sxy150489 		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
23125779Sxy150489 		    ? e1000_1000t_rx_status_ok
23135779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
23145779Sxy150489 
23155779Sxy150489 		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
23165779Sxy150489 		    ? e1000_1000t_rx_status_ok
23175779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
23185779Sxy150489 	} else {
23195779Sxy150489 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
23205779Sxy150489 		phy->local_rx = e1000_1000t_rx_status_undefined;
23215779Sxy150489 		phy->remote_rx = e1000_1000t_rx_status_undefined;
23225779Sxy150489 	}
23235779Sxy150489 
23245779Sxy150489 out:
23255779Sxy150489 	return (ret_val);
23265779Sxy150489 }
23275779Sxy150489 
23285779Sxy150489 /*
23295779Sxy150489  * e1000_phy_sw_reset_generic - PHY software reset
23305779Sxy150489  * @hw: pointer to the HW structure
23315779Sxy150489  *
23325779Sxy150489  * Does a software reset of the PHY by reading the PHY control register and
23335779Sxy150489  * setting/write the control register reset bit to the PHY.
23345779Sxy150489  */
23355779Sxy150489 s32
23365779Sxy150489 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
23375779Sxy150489 {
23388571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
23395779Sxy150489 	u16 phy_ctrl;
23405779Sxy150489 
23415779Sxy150489 	DEBUGFUNC("e1000_phy_sw_reset_generic");
23425779Sxy150489 
23438571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
23448571SChenlu.Chen@Sun.COM 		goto out;
23458571SChenlu.Chen@Sun.COM 
23468571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
23475779Sxy150489 	if (ret_val)
23485779Sxy150489 		goto out;
23495779Sxy150489 
23505779Sxy150489 	phy_ctrl |= MII_CR_RESET;
23518571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
23525779Sxy150489 	if (ret_val)
23535779Sxy150489 		goto out;
23545779Sxy150489 
23555779Sxy150489 	usec_delay(1);
23565779Sxy150489 
23575779Sxy150489 out:
23585779Sxy150489 	return (ret_val);
23595779Sxy150489 }
23605779Sxy150489 
23615779Sxy150489 /*
23625779Sxy150489  * e1000_phy_hw_reset_generic - PHY hardware reset
23635779Sxy150489  * @hw: pointer to the HW structure
23645779Sxy150489  *
23655779Sxy150489  * Verify the reset block is not blocking us from resetting.  Acquire
23665779Sxy150489  * semaphore (if necessary) and read/set/write the device control reset
23675779Sxy150489  * bit in the PHY.  Wait the appropriate delay time for the device to
23688571SChenlu.Chen@Sun.COM  * reset and release the semaphore (if necessary).
23695779Sxy150489  */
23705779Sxy150489 s32
23715779Sxy150489 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
23725779Sxy150489 {
23735779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
23748571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
23755779Sxy150489 	u32 ctrl;
23765779Sxy150489 
23775779Sxy150489 	DEBUGFUNC("e1000_phy_hw_reset_generic");
23785779Sxy150489 
23798571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.check_reset_block(hw);
23805779Sxy150489 	if (ret_val) {
23815779Sxy150489 		ret_val = E1000_SUCCESS;
23825779Sxy150489 		goto out;
23835779Sxy150489 	}
23845779Sxy150489 
23858571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.acquire(hw);
23865779Sxy150489 	if (ret_val)
23875779Sxy150489 		goto out;
23885779Sxy150489 
23895779Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
23905779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
23915779Sxy150489 	E1000_WRITE_FLUSH(hw);
23925779Sxy150489 
23935779Sxy150489 	usec_delay(phy->reset_delay_us);
23945779Sxy150489 
23955779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
23965779Sxy150489 	E1000_WRITE_FLUSH(hw);
23975779Sxy150489 
23985779Sxy150489 	usec_delay(150);
23995779Sxy150489 
24008571SChenlu.Chen@Sun.COM 	phy->ops.release(hw);
24015779Sxy150489 
24028571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.get_cfg_done(hw);
24035779Sxy150489 
24045779Sxy150489 out:
24055779Sxy150489 	return (ret_val);
24065779Sxy150489 }
24075779Sxy150489 
24085779Sxy150489 /*
24095779Sxy150489  * e1000_get_cfg_done_generic - Generic configuration done
24105779Sxy150489  * @hw: pointer to the HW structure
24115779Sxy150489  *
24125779Sxy150489  * Generic function to wait 10 milli-seconds for configuration to complete
24135779Sxy150489  * and return success.
24145779Sxy150489  */
24155779Sxy150489 s32
24165779Sxy150489 e1000_get_cfg_done_generic(struct e1000_hw *hw)
24175779Sxy150489 {
24185779Sxy150489 	DEBUGFUNC("e1000_get_cfg_done_generic");
24198571SChenlu.Chen@Sun.COM 	UNREFERENCED_1PARAMETER(hw);
24205779Sxy150489 
24215779Sxy150489 	msec_delay_irq(10);
24225779Sxy150489 
24235779Sxy150489 	return (E1000_SUCCESS);
24245779Sxy150489 }
24255779Sxy150489 
24265779Sxy150489 /*
24275779Sxy150489  * e1000_phy_init_script_igp3 - Inits the IGP3 PHY
24285779Sxy150489  * @hw: pointer to the HW structure
24295779Sxy150489  *
24305779Sxy150489  * Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
24315779Sxy150489  */
24325779Sxy150489 s32
24335779Sxy150489 e1000_phy_init_script_igp3(struct e1000_hw *hw)
24345779Sxy150489 {
24355779Sxy150489 	DEBUGOUT("Running IGP 3 PHY init script\n");
24365779Sxy150489 
24375779Sxy150489 	/* PHY init IGP 3 */
24385779Sxy150489 	/* Enable rise/fall, 10-mode work in class-A */
24398571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
24405779Sxy150489 	/* Remove all caps from Replica path filter */
24418571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
24425779Sxy150489 	/* Bias trimming for ADC, AFE and Driver (Default) */
24438571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
24445779Sxy150489 	/* Increase Hybrid poly bias */
24458571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
24468571SChenlu.Chen@Sun.COM 	/* Add 4% to Tx amplitude in Gig mode */
24478571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
24485779Sxy150489 	/* Disable trimming (TTT) */
24498571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
24505779Sxy150489 	/* Poly DC correction to 94.6% + 2% for all channels */
24518571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
24525779Sxy150489 	/* ABS DC correction to 95.9% */
24538571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
24545779Sxy150489 	/* BG temp curve trim */
24558571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
24565779Sxy150489 	/* Increasing ADC OPAMP stage 1 currents to max */
24578571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
24585779Sxy150489 	/* Force 1000 ( required for enabling PHY regs configuration) */
24598571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
24605779Sxy150489 	/* Set upd_freq to 6 */
24618571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
24625779Sxy150489 	/* Disable NPDFE */
24638571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
24645779Sxy150489 	/* Disable adaptive fixed FFE (Default) */
24658571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
24665779Sxy150489 	/* Enable FFE hysteresis */
24678571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
24685779Sxy150489 	/* Fixed FFE for short cable lengths */
24698571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
24705779Sxy150489 	/* Fixed FFE for medium cable lengths */
24718571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
24725779Sxy150489 	/* Fixed FFE for long cable lengths */
24738571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
24745779Sxy150489 	/* Enable Adaptive Clip Threshold */
24758571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
24765779Sxy150489 	/* AHT reset limit to 1 */
24778571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
24785779Sxy150489 	/* Set AHT master delay to 127 msec */
24798571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
24805779Sxy150489 	/* Set scan bits for AHT */
24818571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
24825779Sxy150489 	/* Set AHT Preset bits */
24838571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
24845779Sxy150489 	/* Change integ_factor of channel A to 3 */
24858571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
24865779Sxy150489 	/* Change prop_factor of channels BCD to 8 */
24878571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
24885779Sxy150489 	/* Change cg_icount + enable integbp for channels BCD */
24898571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
24905779Sxy150489 	/*
24915779Sxy150489 	 * Change cg_icount + enable integbp + change prop_factor_master
24925779Sxy150489 	 * to 8 for channel A
24935779Sxy150489 	 */
24948571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
24955779Sxy150489 	/* Disable AHT in Slave mode on channel A */
24968571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
24975779Sxy150489 	/*
24985779Sxy150489 	 * Enable LPLU and disable AN to 1000 in non-D0a states,
24995779Sxy150489 	 * Enable SPD+B2B
25005779Sxy150489 	 */
25018571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
25025779Sxy150489 	/* Enable restart AN on an1000_dis change */
25038571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
25045779Sxy150489 	/* Enable wh_fifo read clock in 10/100 modes */
25058571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
25065779Sxy150489 	/* Restart AN, Speed selection is 1000 */
25078571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
25085779Sxy150489 
25095779Sxy150489 	return (E1000_SUCCESS);
25105779Sxy150489 }
25115779Sxy150489 
25125779Sxy150489 /*
25135779Sxy150489  * e1000_get_phy_type_from_id - Get PHY type from id
25145779Sxy150489  * @phy_id: phy_id read from the phy
25155779Sxy150489  *
25165779Sxy150489  * Returns the phy type from the id.
25175779Sxy150489  */
25188571SChenlu.Chen@Sun.COM enum e1000_phy_type
25195779Sxy150489 e1000_get_phy_type_from_id(u32 phy_id)
25205779Sxy150489 {
25218571SChenlu.Chen@Sun.COM 	enum e1000_phy_type phy_type = e1000_phy_unknown;
25225779Sxy150489 
25235779Sxy150489 	switch (phy_id)	{
25245779Sxy150489 	case M88E1000_I_PHY_ID:
25255779Sxy150489 	case M88E1000_E_PHY_ID:
25265779Sxy150489 	case M88E1111_I_PHY_ID:
25275779Sxy150489 	case M88E1011_I_PHY_ID:
25285779Sxy150489 		phy_type = e1000_phy_m88;
25295779Sxy150489 		break;
25305779Sxy150489 	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
25315779Sxy150489 		phy_type = e1000_phy_igp_2;
25325779Sxy150489 		break;
25335779Sxy150489 	case GG82563_E_PHY_ID:
25345779Sxy150489 		phy_type = e1000_phy_gg82563;
25355779Sxy150489 		break;
25365779Sxy150489 	case IGP03E1000_E_PHY_ID:
25375779Sxy150489 		phy_type = e1000_phy_igp_3;
25385779Sxy150489 		break;
25395779Sxy150489 	case IFE_E_PHY_ID:
25405779Sxy150489 	case IFE_PLUS_E_PHY_ID:
25415779Sxy150489 	case IFE_C_E_PHY_ID:
25425779Sxy150489 		phy_type = e1000_phy_ife;
25435779Sxy150489 		break;
2544*11155SJason.Xu@Sun.COM 	case I82580_I_PHY_ID:
2545*11155SJason.Xu@Sun.COM 		phy_type = e1000_phy_82580;
2546*11155SJason.Xu@Sun.COM 		break;
25475779Sxy150489 	default:
25485779Sxy150489 		phy_type = e1000_phy_unknown;
25495779Sxy150489 		break;
25505779Sxy150489 	}
25515779Sxy150489 	return (phy_type);
25525779Sxy150489 }
25535779Sxy150489 
25545779Sxy150489 /*
255510319SJason.Xu@Sun.COM  * e1000_determine_phy_address - Determines PHY address.
255610319SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
255710319SJason.Xu@Sun.COM  *
255810319SJason.Xu@Sun.COM  * This uses a trial and error method to loop through possible PHY
255910319SJason.Xu@Sun.COM  * addresses. It tests each by reading the PHY ID registers and
256010319SJason.Xu@Sun.COM  * checking for a match.
256110319SJason.Xu@Sun.COM  */
256210319SJason.Xu@Sun.COM s32
256310319SJason.Xu@Sun.COM e1000_determine_phy_address(struct e1000_hw *hw)
256410319SJason.Xu@Sun.COM {
256510319SJason.Xu@Sun.COM 	s32 ret_val = -E1000_ERR_PHY_TYPE;
256610319SJason.Xu@Sun.COM 	u32 phy_addr = 0;
256710319SJason.Xu@Sun.COM 	u32 i;
256810319SJason.Xu@Sun.COM 	enum e1000_phy_type phy_type = e1000_phy_unknown;
256910319SJason.Xu@Sun.COM 
257010319SJason.Xu@Sun.COM 	hw->phy.id = phy_type;
257110319SJason.Xu@Sun.COM 
257210319SJason.Xu@Sun.COM 	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
257310319SJason.Xu@Sun.COM 		hw->phy.addr = phy_addr;
257410319SJason.Xu@Sun.COM 		i = 0;
257510319SJason.Xu@Sun.COM 
257610319SJason.Xu@Sun.COM 		do {
2577*11155SJason.Xu@Sun.COM 			(void) e1000_get_phy_id(hw);
257810319SJason.Xu@Sun.COM 			phy_type = e1000_get_phy_type_from_id(hw->phy.id);
257910319SJason.Xu@Sun.COM 
258010319SJason.Xu@Sun.COM 			/*
258110319SJason.Xu@Sun.COM 			 * If phy_type is valid, break - we found our
258210319SJason.Xu@Sun.COM 			 * PHY address
258310319SJason.Xu@Sun.COM 			 */
258410319SJason.Xu@Sun.COM 			if (phy_type  != e1000_phy_unknown) {
258510319SJason.Xu@Sun.COM 				ret_val = E1000_SUCCESS;
258610319SJason.Xu@Sun.COM 				goto out;
258710319SJason.Xu@Sun.COM 			}
258810319SJason.Xu@Sun.COM 			msec_delay(1);
258910319SJason.Xu@Sun.COM 			i++;
259010319SJason.Xu@Sun.COM 		} while (i < 10);
259110319SJason.Xu@Sun.COM 	}
259210319SJason.Xu@Sun.COM 
259310319SJason.Xu@Sun.COM out:
259410319SJason.Xu@Sun.COM 	return (ret_val);
259510319SJason.Xu@Sun.COM }
259610319SJason.Xu@Sun.COM /*
25975779Sxy150489  * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
25985779Sxy150489  * @hw: pointer to the HW structure
25995779Sxy150489  *
26005779Sxy150489  * In the case of a PHY power down to save power, or to turn off link during a
26015779Sxy150489  * driver unload, or wake on lan is not enabled, restore the link to previous
26025779Sxy150489  * settings.
26035779Sxy150489  */
26045779Sxy150489 void
26055779Sxy150489 e1000_power_up_phy_copper(struct e1000_hw *hw)
26065779Sxy150489 {
26075779Sxy150489 	u16 mii_reg = 0;
26085779Sxy150489 
26095779Sxy150489 	/* The PHY will retain its settings across a power down/up cycle */
26108571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
26115779Sxy150489 	mii_reg &= ~MII_CR_POWER_DOWN;
26128571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
26135779Sxy150489 }
26145779Sxy150489 
26155779Sxy150489 /*
26165779Sxy150489  * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
26175779Sxy150489  * @hw: pointer to the HW structure
26185779Sxy150489  *
26195779Sxy150489  * In the case of a PHY power down to save power, or to turn off link during a
26205779Sxy150489  * driver unload, or wake on lan is not enabled, restore the link to previous
26215779Sxy150489  * settings.
26225779Sxy150489  */
26235779Sxy150489 void
26245779Sxy150489 e1000_power_down_phy_copper(struct e1000_hw *hw)
26255779Sxy150489 {
26265779Sxy150489 	u16 mii_reg = 0;
26275779Sxy150489 
26285779Sxy150489 	/* The PHY will retain its settings across a power down/up cycle */
26298571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
26305779Sxy150489 	mii_reg |= MII_CR_POWER_DOWN;
26318571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
26325779Sxy150489 	msec_delay(1);
26335779Sxy150489 }
2634*11155SJason.Xu@Sun.COM 
2635*11155SJason.Xu@Sun.COM /*
2636*11155SJason.Xu@Sun.COM  * e1000_check_polarity_82577 - Checks the polarity.
2637*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
2638*11155SJason.Xu@Sun.COM  *
2639*11155SJason.Xu@Sun.COM  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
2640*11155SJason.Xu@Sun.COM  *
2641*11155SJason.Xu@Sun.COM  * Polarity is determined based on the PHY specific status register.
2642*11155SJason.Xu@Sun.COM  */
2643*11155SJason.Xu@Sun.COM s32
2644*11155SJason.Xu@Sun.COM e1000_check_polarity_82577(struct e1000_hw *hw)
2645*11155SJason.Xu@Sun.COM {
2646*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
2647*11155SJason.Xu@Sun.COM 	s32 ret_val;
2648*11155SJason.Xu@Sun.COM 	u16 data;
2649*11155SJason.Xu@Sun.COM 
2650*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_check_polarity_82577");
2651*11155SJason.Xu@Sun.COM 
2652*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
2653*11155SJason.Xu@Sun.COM 
2654*11155SJason.Xu@Sun.COM 	if (!ret_val)
2655*11155SJason.Xu@Sun.COM 		phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
2656*11155SJason.Xu@Sun.COM 		    ? e1000_rev_polarity_reversed
2657*11155SJason.Xu@Sun.COM 		    : e1000_rev_polarity_normal;
2658*11155SJason.Xu@Sun.COM 
2659*11155SJason.Xu@Sun.COM 	return (ret_val);
2660*11155SJason.Xu@Sun.COM }
2661*11155SJason.Xu@Sun.COM 
2662*11155SJason.Xu@Sun.COM /*
2663*11155SJason.Xu@Sun.COM  * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
2664*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
2665*11155SJason.Xu@Sun.COM  *
2666*11155SJason.Xu@Sun.COM  * Calls the PHY setup function to force speed and duplex.  Clears the
2667*11155SJason.Xu@Sun.COM  * auto-crossover to force MDI manually.  Waits for link and returns
2668*11155SJason.Xu@Sun.COM  * successful if link up is successful, else -E1000_ERR_PHY (-2).
2669*11155SJason.Xu@Sun.COM  */
2670*11155SJason.Xu@Sun.COM s32
2671*11155SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
2672*11155SJason.Xu@Sun.COM {
2673*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
2674*11155SJason.Xu@Sun.COM 	s32 ret_val;
2675*11155SJason.Xu@Sun.COM 	u16 phy_data;
2676*11155SJason.Xu@Sun.COM 	bool link;
2677*11155SJason.Xu@Sun.COM 
2678*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_phy_force_speed_duplex_82577");
2679*11155SJason.Xu@Sun.COM 
2680*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
2681*11155SJason.Xu@Sun.COM 	if (ret_val)
2682*11155SJason.Xu@Sun.COM 		goto out;
2683*11155SJason.Xu@Sun.COM 
2684*11155SJason.Xu@Sun.COM 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
2685*11155SJason.Xu@Sun.COM 
2686*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
2687*11155SJason.Xu@Sun.COM 	if (ret_val)
2688*11155SJason.Xu@Sun.COM 		goto out;
2689*11155SJason.Xu@Sun.COM 
2690*11155SJason.Xu@Sun.COM 	/*
2691*11155SJason.Xu@Sun.COM 	 * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
2692*11155SJason.Xu@Sun.COM 	 * forced whenever speed and duplex are forced.
2693*11155SJason.Xu@Sun.COM 	 */
2694*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data);
2695*11155SJason.Xu@Sun.COM 	if (ret_val)
2696*11155SJason.Xu@Sun.COM 		goto out;
2697*11155SJason.Xu@Sun.COM 
2698*11155SJason.Xu@Sun.COM 	phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
2699*11155SJason.Xu@Sun.COM 	phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
2700*11155SJason.Xu@Sun.COM 
2701*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data);
2702*11155SJason.Xu@Sun.COM 	if (ret_val)
2703*11155SJason.Xu@Sun.COM 		goto out;
2704*11155SJason.Xu@Sun.COM 
2705*11155SJason.Xu@Sun.COM 	DEBUGOUT1("I82577_PHY_CTRL_2: %X\n", phy_data);
2706*11155SJason.Xu@Sun.COM 
2707*11155SJason.Xu@Sun.COM 	usec_delay(1);
2708*11155SJason.Xu@Sun.COM 
2709*11155SJason.Xu@Sun.COM 	if (phy->autoneg_wait_to_complete) {
2710*11155SJason.Xu@Sun.COM 		DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n");
2711*11155SJason.Xu@Sun.COM 
2712*11155SJason.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
2713*11155SJason.Xu@Sun.COM 		    PHY_FORCE_LIMIT,
2714*11155SJason.Xu@Sun.COM 		    100000,
2715*11155SJason.Xu@Sun.COM 		    &link);
2716*11155SJason.Xu@Sun.COM 		if (ret_val)
2717*11155SJason.Xu@Sun.COM 			goto out;
2718*11155SJason.Xu@Sun.COM 
2719*11155SJason.Xu@Sun.COM 		if (!link)
2720*11155SJason.Xu@Sun.COM 			DEBUGOUT("Link taking longer than expected.\n");
2721*11155SJason.Xu@Sun.COM 
2722*11155SJason.Xu@Sun.COM 		/* Try once more */
2723*11155SJason.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
2724*11155SJason.Xu@Sun.COM 		    PHY_FORCE_LIMIT,
2725*11155SJason.Xu@Sun.COM 		    100000,
2726*11155SJason.Xu@Sun.COM 		    &link);
2727*11155SJason.Xu@Sun.COM 		if (ret_val)
2728*11155SJason.Xu@Sun.COM 			goto out;
2729*11155SJason.Xu@Sun.COM 	}
2730*11155SJason.Xu@Sun.COM 
2731*11155SJason.Xu@Sun.COM out:
2732*11155SJason.Xu@Sun.COM 	return (ret_val);
2733*11155SJason.Xu@Sun.COM }
2734*11155SJason.Xu@Sun.COM 
2735*11155SJason.Xu@Sun.COM /*
2736*11155SJason.Xu@Sun.COM  * e1000_get_phy_info_82577 - Retrieve I82577 PHY information
2737*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
2738*11155SJason.Xu@Sun.COM  *
2739*11155SJason.Xu@Sun.COM  * Read PHY status to determine if link is up.  If link is up, then
2740*11155SJason.Xu@Sun.COM  * set/determine 10base-T extended distance and polarity correction.  Read
2741*11155SJason.Xu@Sun.COM  * PHY port status to determine MDI/MDIx and speed.  Based on the speed,
2742*11155SJason.Xu@Sun.COM  * determine on the cable length, local and remote receiver.
2743*11155SJason.Xu@Sun.COM  */
2744*11155SJason.Xu@Sun.COM s32
2745*11155SJason.Xu@Sun.COM e1000_get_phy_info_82577(struct e1000_hw *hw)
2746*11155SJason.Xu@Sun.COM {
2747*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
2748*11155SJason.Xu@Sun.COM 	s32 ret_val;
2749*11155SJason.Xu@Sun.COM 	u16 data;
2750*11155SJason.Xu@Sun.COM 	bool link;
2751*11155SJason.Xu@Sun.COM 
2752*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_get_phy_info_82577");
2753*11155SJason.Xu@Sun.COM 
2754*11155SJason.Xu@Sun.COM 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
2755*11155SJason.Xu@Sun.COM 	if (ret_val)
2756*11155SJason.Xu@Sun.COM 		goto out;
2757*11155SJason.Xu@Sun.COM 
2758*11155SJason.Xu@Sun.COM 	if (!link) {
2759*11155SJason.Xu@Sun.COM 		DEBUGOUT("Phy info is only valid if link is up\n");
2760*11155SJason.Xu@Sun.COM 		ret_val = -E1000_ERR_CONFIG;
2761*11155SJason.Xu@Sun.COM 		goto out;
2762*11155SJason.Xu@Sun.COM 	}
2763*11155SJason.Xu@Sun.COM 
2764*11155SJason.Xu@Sun.COM 	phy->polarity_correction = true;
2765*11155SJason.Xu@Sun.COM 
2766*11155SJason.Xu@Sun.COM 	ret_val = e1000_check_polarity_82577(hw);
2767*11155SJason.Xu@Sun.COM 	if (ret_val)
2768*11155SJason.Xu@Sun.COM 		goto out;
2769*11155SJason.Xu@Sun.COM 
2770*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
2771*11155SJason.Xu@Sun.COM 	if (ret_val)
2772*11155SJason.Xu@Sun.COM 		goto out;
2773*11155SJason.Xu@Sun.COM 
2774*11155SJason.Xu@Sun.COM 	phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
2775*11155SJason.Xu@Sun.COM 
2776*11155SJason.Xu@Sun.COM 	if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
2777*11155SJason.Xu@Sun.COM 	    I82577_PHY_STATUS2_SPEED_1000MBPS) {
2778*11155SJason.Xu@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
2779*11155SJason.Xu@Sun.COM 		if (ret_val)
2780*11155SJason.Xu@Sun.COM 			goto out;
2781*11155SJason.Xu@Sun.COM 
2782*11155SJason.Xu@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
2783*11155SJason.Xu@Sun.COM 		if (ret_val)
2784*11155SJason.Xu@Sun.COM 			goto out;
2785*11155SJason.Xu@Sun.COM 
2786*11155SJason.Xu@Sun.COM 		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
2787*11155SJason.Xu@Sun.COM 		    ? e1000_1000t_rx_status_ok
2788*11155SJason.Xu@Sun.COM 		    : e1000_1000t_rx_status_not_ok;
2789*11155SJason.Xu@Sun.COM 
2790*11155SJason.Xu@Sun.COM 		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
2791*11155SJason.Xu@Sun.COM 		    ? e1000_1000t_rx_status_ok
2792*11155SJason.Xu@Sun.COM 		    : e1000_1000t_rx_status_not_ok;
2793*11155SJason.Xu@Sun.COM 	} else {
2794*11155SJason.Xu@Sun.COM 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
2795*11155SJason.Xu@Sun.COM 		phy->local_rx = e1000_1000t_rx_status_undefined;
2796*11155SJason.Xu@Sun.COM 		phy->remote_rx = e1000_1000t_rx_status_undefined;
2797*11155SJason.Xu@Sun.COM 	}
2798*11155SJason.Xu@Sun.COM 
2799*11155SJason.Xu@Sun.COM out:
2800*11155SJason.Xu@Sun.COM 	return (ret_val);
2801*11155SJason.Xu@Sun.COM }
2802*11155SJason.Xu@Sun.COM 
2803*11155SJason.Xu@Sun.COM /*
2804*11155SJason.Xu@Sun.COM  * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
2805*11155SJason.Xu@Sun.COM  * @hw: pointer to the HW structure
2806*11155SJason.Xu@Sun.COM  *
2807*11155SJason.Xu@Sun.COM  * Reads the diagnostic status register and verifies result is valid before
2808*11155SJason.Xu@Sun.COM  * placing it in the phy_cable_length field.
2809*11155SJason.Xu@Sun.COM  */
2810*11155SJason.Xu@Sun.COM s32
2811*11155SJason.Xu@Sun.COM e1000_get_cable_length_82577(struct e1000_hw *hw)
2812*11155SJason.Xu@Sun.COM {
2813*11155SJason.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
2814*11155SJason.Xu@Sun.COM 	s32 ret_val;
2815*11155SJason.Xu@Sun.COM 	u16 phy_data, length;
2816*11155SJason.Xu@Sun.COM 
2817*11155SJason.Xu@Sun.COM 	DEBUGFUNC("e1000_get_cable_length_82577");
2818*11155SJason.Xu@Sun.COM 
2819*11155SJason.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
2820*11155SJason.Xu@Sun.COM 	if (ret_val)
2821*11155SJason.Xu@Sun.COM 		goto out;
2822*11155SJason.Xu@Sun.COM 
2823*11155SJason.Xu@Sun.COM 	length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
2824*11155SJason.Xu@Sun.COM 	    I82577_DSTATUS_CABLE_LENGTH_SHIFT;
2825*11155SJason.Xu@Sun.COM 
2826*11155SJason.Xu@Sun.COM 	if (length == E1000_CABLE_LENGTH_UNDEFINED)
2827*11155SJason.Xu@Sun.COM 		ret_val = -E1000_ERR_PHY;
2828*11155SJason.Xu@Sun.COM 
2829*11155SJason.Xu@Sun.COM 	phy->cable_length = length;
2830*11155SJason.Xu@Sun.COM 
2831*11155SJason.Xu@Sun.COM out:
2832*11155SJason.Xu@Sun.COM 
2833*11155SJason.Xu@Sun.COM 	return (ret_val);
2834*11155SJason.Xu@Sun.COM }
2835