xref: /onnv-gate/usr/src/uts/common/io/igb/igb_phy.c (revision 8571:60e408ef19cc)
15779Sxy150489 /*
25779Sxy150489  * CDDL HEADER START
35779Sxy150489  *
4*8571SChenlu.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 /*
25*8571SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
265779Sxy150489  * Use is subject to license terms of the CDDL.
275779Sxy150489  */
285779Sxy150489 
29*8571SChenlu.Chen@Sun.COM /* IntelVersion: 1.112 v2008-10-7 */
305779Sxy150489 
315779Sxy150489 #include "igb_api.h"
325779Sxy150489 
33*8571SChenlu.Chen@Sun.COM static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
345779Sxy150489 
355779Sxy150489 /* Cable length tables */
365779Sxy150489 static const u16 e1000_m88_cable_length_table[] =
375779Sxy150489 	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
385779Sxy150489 
395779Sxy150489 #define	M88E1000_CABLE_LENGTH_TABLE_SIZE \
405779Sxy150489 	(sizeof (e1000_m88_cable_length_table) / \
415779Sxy150489 	sizeof (e1000_m88_cable_length_table[0]))
425779Sxy150489 
435779Sxy150489 static const u16 e1000_igp_2_cable_length_table[] =
445779Sxy150489 	{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
455779Sxy150489 	0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
465779Sxy150489 	6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
475779Sxy150489 	21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
485779Sxy150489 	40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
495779Sxy150489 	60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
505779Sxy150489 	83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
515779Sxy150489 	104, 109, 114, 118, 121, 124};
525779Sxy150489 
535779Sxy150489 #define	IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
545779Sxy150489 	(sizeof (e1000_igp_2_cable_length_table) / \
555779Sxy150489 	sizeof (e1000_igp_2_cable_length_table[0]))
565779Sxy150489 
575779Sxy150489 /*
58*8571SChenlu.Chen@Sun.COM  * e1000_init_phy_ops_generic - Initialize PHY function pointers
59*8571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
60*8571SChenlu.Chen@Sun.COM  *
61*8571SChenlu.Chen@Sun.COM  * Setups up the function pointers to no-op functions
62*8571SChenlu.Chen@Sun.COM  */
63*8571SChenlu.Chen@Sun.COM void
64*8571SChenlu.Chen@Sun.COM e1000_init_phy_ops_generic(struct e1000_hw *hw)
65*8571SChenlu.Chen@Sun.COM {
66*8571SChenlu.Chen@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
67*8571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_init_phy_ops_generic");
68*8571SChenlu.Chen@Sun.COM 
69*8571SChenlu.Chen@Sun.COM 	/* Initialize function pointers */
70*8571SChenlu.Chen@Sun.COM 	phy->ops.init_params = e1000_null_ops_generic;
71*8571SChenlu.Chen@Sun.COM 	phy->ops.acquire = e1000_null_ops_generic;
72*8571SChenlu.Chen@Sun.COM 	phy->ops.check_polarity = e1000_null_ops_generic;
73*8571SChenlu.Chen@Sun.COM 	phy->ops.check_reset_block = e1000_null_ops_generic;
74*8571SChenlu.Chen@Sun.COM 	phy->ops.commit = e1000_null_ops_generic;
75*8571SChenlu.Chen@Sun.COM 	phy->ops.force_speed_duplex = e1000_null_ops_generic;
76*8571SChenlu.Chen@Sun.COM 	phy->ops.get_cfg_done = e1000_null_ops_generic;
77*8571SChenlu.Chen@Sun.COM 	phy->ops.get_cable_length = e1000_null_ops_generic;
78*8571SChenlu.Chen@Sun.COM 	phy->ops.get_info = e1000_null_ops_generic;
79*8571SChenlu.Chen@Sun.COM 	phy->ops.read_reg = e1000_null_read_reg;
80*8571SChenlu.Chen@Sun.COM 	phy->ops.release = e1000_null_phy_generic;
81*8571SChenlu.Chen@Sun.COM 	phy->ops.reset = e1000_null_ops_generic;
82*8571SChenlu.Chen@Sun.COM 	phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
83*8571SChenlu.Chen@Sun.COM 	phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
84*8571SChenlu.Chen@Sun.COM 	phy->ops.write_reg = e1000_null_write_reg;
85*8571SChenlu.Chen@Sun.COM 	phy->ops.power_up = e1000_null_phy_generic;
86*8571SChenlu.Chen@Sun.COM 	phy->ops.power_down = e1000_null_phy_generic;
87*8571SChenlu.Chen@Sun.COM }
88*8571SChenlu.Chen@Sun.COM 
89*8571SChenlu.Chen@Sun.COM /*
90*8571SChenlu.Chen@Sun.COM  * e1000_null_read_reg - No-op function, return 0
91*8571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
92*8571SChenlu.Chen@Sun.COM  */
93*8571SChenlu.Chen@Sun.COM s32
94*8571SChenlu.Chen@Sun.COM e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data)
95*8571SChenlu.Chen@Sun.COM {
96*8571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_read_reg");
97*8571SChenlu.Chen@Sun.COM 	UNREFERENCED_3PARAMETER(hw, offset, data);
98*8571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
99*8571SChenlu.Chen@Sun.COM }
100*8571SChenlu.Chen@Sun.COM 
101*8571SChenlu.Chen@Sun.COM /*
102*8571SChenlu.Chen@Sun.COM  * e1000_null_phy_generic - No-op function, return void
103*8571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
104*8571SChenlu.Chen@Sun.COM  */
105*8571SChenlu.Chen@Sun.COM void
106*8571SChenlu.Chen@Sun.COM e1000_null_phy_generic(struct e1000_hw *hw)
107*8571SChenlu.Chen@Sun.COM {
108*8571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_phy_generic");
109*8571SChenlu.Chen@Sun.COM 	UNREFERENCED_1PARAMETER(hw);
110*8571SChenlu.Chen@Sun.COM }
111*8571SChenlu.Chen@Sun.COM 
112*8571SChenlu.Chen@Sun.COM /*
113*8571SChenlu.Chen@Sun.COM  * e1000_null_lplu_state - No-op function, return 0
114*8571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
115*8571SChenlu.Chen@Sun.COM  */
116*8571SChenlu.Chen@Sun.COM s32
117*8571SChenlu.Chen@Sun.COM e1000_null_lplu_state(struct e1000_hw *hw, bool active)
118*8571SChenlu.Chen@Sun.COM {
119*8571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_lplu_state");
120*8571SChenlu.Chen@Sun.COM 	UNREFERENCED_2PARAMETER(hw, active);
121*8571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
122*8571SChenlu.Chen@Sun.COM }
123*8571SChenlu.Chen@Sun.COM 
124*8571SChenlu.Chen@Sun.COM /*
125*8571SChenlu.Chen@Sun.COM  * e1000_null_write_reg - No-op function, return 0
126*8571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
127*8571SChenlu.Chen@Sun.COM  */
128*8571SChenlu.Chen@Sun.COM s32
129*8571SChenlu.Chen@Sun.COM e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
130*8571SChenlu.Chen@Sun.COM {
131*8571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_write_reg");
132*8571SChenlu.Chen@Sun.COM 	UNREFERENCED_3PARAMETER(hw, offset, data);
133*8571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
134*8571SChenlu.Chen@Sun.COM }
135*8571SChenlu.Chen@Sun.COM 
136*8571SChenlu.Chen@Sun.COM /*
1375779Sxy150489  * e1000_check_reset_block_generic - Check if PHY reset is blocked
1385779Sxy150489  * @hw: pointer to the HW structure
1395779Sxy150489  *
1405779Sxy150489  * Read the PHY management control register and check whether a PHY reset
1415779Sxy150489  * is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
1425779Sxy150489  * return E1000_BLK_PHY_RESET (12).
1435779Sxy150489  */
1445779Sxy150489 s32
1455779Sxy150489 e1000_check_reset_block_generic(struct e1000_hw *hw)
1465779Sxy150489 {
1475779Sxy150489 	u32 manc;
1485779Sxy150489 
1495779Sxy150489 	DEBUGFUNC("e1000_check_reset_block");
1505779Sxy150489 
1515779Sxy150489 	manc = E1000_READ_REG(hw, E1000_MANC);
1525779Sxy150489 
1535779Sxy150489 	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
1545779Sxy150489 	    E1000_BLK_PHY_RESET : E1000_SUCCESS;
1555779Sxy150489 }
1565779Sxy150489 
1575779Sxy150489 /*
1585779Sxy150489  * e1000_get_phy_id - Retrieve the PHY ID and revision
1595779Sxy150489  * @hw: pointer to the HW structure
1605779Sxy150489  *
1615779Sxy150489  * Reads the PHY registers and stores the PHY ID and possibly the PHY
1625779Sxy150489  * revision in the hardware structure.
1635779Sxy150489  */
1645779Sxy150489 s32
1655779Sxy150489 e1000_get_phy_id(struct e1000_hw *hw)
1665779Sxy150489 {
1675779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
1685779Sxy150489 	s32 ret_val = E1000_SUCCESS;
1695779Sxy150489 	u16 phy_id;
1705779Sxy150489 
1715779Sxy150489 	DEBUGFUNC("e1000_get_phy_id");
1725779Sxy150489 
173*8571SChenlu.Chen@Sun.COM 	if (!(phy->ops.read_reg))
174*8571SChenlu.Chen@Sun.COM 		goto out;
175*8571SChenlu.Chen@Sun.COM 
176*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
1775779Sxy150489 	if (ret_val)
1785779Sxy150489 		goto out;
1795779Sxy150489 
1805779Sxy150489 	phy->id = (u32)(phy_id << 16);
1815779Sxy150489 	usec_delay(20);
182*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
1835779Sxy150489 	if (ret_val)
1845779Sxy150489 		goto out;
1855779Sxy150489 
1865779Sxy150489 	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
1875779Sxy150489 	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
1885779Sxy150489 
1895779Sxy150489 out:
1905779Sxy150489 	return (ret_val);
1915779Sxy150489 }
1925779Sxy150489 
1935779Sxy150489 /*
1945779Sxy150489  * e1000_phy_reset_dsp_generic - Reset PHY DSP
1955779Sxy150489  * @hw: pointer to the HW structure
1965779Sxy150489  *
1975779Sxy150489  * Reset the digital signal processor.
1985779Sxy150489  */
1995779Sxy150489 s32
2005779Sxy150489 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
2015779Sxy150489 {
202*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
2035779Sxy150489 
2045779Sxy150489 	DEBUGFUNC("e1000_phy_reset_dsp_generic");
2055779Sxy150489 
206*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.write_reg))
207*8571SChenlu.Chen@Sun.COM 		goto out;
208*8571SChenlu.Chen@Sun.COM 
209*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
2105779Sxy150489 	if (ret_val)
2115779Sxy150489 		goto out;
2125779Sxy150489 
213*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
2145779Sxy150489 
2155779Sxy150489 out:
2165779Sxy150489 	return (ret_val);
2175779Sxy150489 }
2185779Sxy150489 
2195779Sxy150489 /*
2205779Sxy150489  * e1000_read_phy_reg_mdic - Read MDI control register
2215779Sxy150489  * @hw: pointer to the HW structure
2225779Sxy150489  * @offset: register offset to be read
2235779Sxy150489  * @data: pointer to the read data
2245779Sxy150489  *
225*8571SChenlu.Chen@Sun.COM  * Reads the MDI control register in the PHY at offset and stores the
2265779Sxy150489  * information read to data.
2275779Sxy150489  */
2285779Sxy150489 s32
2295779Sxy150489 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
2305779Sxy150489 {
2315779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
2325779Sxy150489 	u32 i, mdic = 0;
2335779Sxy150489 	s32 ret_val = E1000_SUCCESS;
2345779Sxy150489 
2355779Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_mdic");
2365779Sxy150489 
2375779Sxy150489 	/*
2385779Sxy150489 	 * Set up Op-code, Phy Address, and register offset in the MDI
2395779Sxy150489 	 * Control register.  The MAC will take care of interfacing with the
2405779Sxy150489 	 * PHY to retrieve the desired data.
2415779Sxy150489 	 */
2425779Sxy150489 	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
2435779Sxy150489 	    (phy->addr << E1000_MDIC_PHY_SHIFT) |
2445779Sxy150489 	    (E1000_MDIC_OP_READ));
2455779Sxy150489 
2465779Sxy150489 	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
2475779Sxy150489 
2485779Sxy150489 	/*
2495779Sxy150489 	 * Poll the ready bit to see if the MDI read completed
2505779Sxy150489 	 * Increasing the time out as testing showed failures with
2515779Sxy150489 	 * the lower time out
2525779Sxy150489 	 */
2535779Sxy150489 	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
2545779Sxy150489 		usec_delay(50);
2555779Sxy150489 		mdic = E1000_READ_REG(hw, E1000_MDIC);
2565779Sxy150489 		if (mdic & E1000_MDIC_READY)
2575779Sxy150489 			break;
2585779Sxy150489 	}
2595779Sxy150489 	if (!(mdic & E1000_MDIC_READY)) {
2605779Sxy150489 		DEBUGOUT("MDI Read did not complete\n");
2615779Sxy150489 		ret_val = -E1000_ERR_PHY;
2625779Sxy150489 		goto out;
2635779Sxy150489 	}
2645779Sxy150489 	if (mdic & E1000_MDIC_ERROR) {
2655779Sxy150489 		DEBUGOUT("MDI Error\n");
2665779Sxy150489 		ret_val = -E1000_ERR_PHY;
2675779Sxy150489 		goto out;
2685779Sxy150489 	}
2695779Sxy150489 	*data = (u16) mdic;
2705779Sxy150489 
2715779Sxy150489 out:
2725779Sxy150489 	return (ret_val);
2735779Sxy150489 }
2745779Sxy150489 
2755779Sxy150489 /*
2765779Sxy150489  * e1000_write_phy_reg_mdic - Write MDI control register
2775779Sxy150489  * @hw: pointer to the HW structure
2785779Sxy150489  * @offset: register offset to write to
2795779Sxy150489  * @data: data to write to register at offset
2805779Sxy150489  *
2815779Sxy150489  * Writes data to MDI control register in the PHY at offset.
2825779Sxy150489  */
2835779Sxy150489 s32
2845779Sxy150489 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
2855779Sxy150489 {
2865779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
2875779Sxy150489 	u32 i, mdic = 0;
2885779Sxy150489 	s32 ret_val = E1000_SUCCESS;
2895779Sxy150489 
2905779Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_mdic");
2915779Sxy150489 
2925779Sxy150489 	/*
2935779Sxy150489 	 * Set up Op-code, Phy Address, and register offset in the MDI
2945779Sxy150489 	 * Control register.  The MAC will take care of interfacing with the
2955779Sxy150489 	 * PHY to retrieve the desired data.
2965779Sxy150489 	 */
2975779Sxy150489 	mdic = (((u32)data) |
2985779Sxy150489 	    (offset << E1000_MDIC_REG_SHIFT) |
2995779Sxy150489 	    (phy->addr << E1000_MDIC_PHY_SHIFT) |
3005779Sxy150489 	    (E1000_MDIC_OP_WRITE));
3015779Sxy150489 
3025779Sxy150489 	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
3035779Sxy150489 
3045779Sxy150489 	/*
3055779Sxy150489 	 * Poll the ready bit to see if the MDI read completed
3065779Sxy150489 	 * Increasing the time out as testing showed failures with
3075779Sxy150489 	 * the lower time out
3085779Sxy150489 	 */
3095779Sxy150489 	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
3105779Sxy150489 		usec_delay(50);
3115779Sxy150489 		mdic = E1000_READ_REG(hw, E1000_MDIC);
3125779Sxy150489 		if (mdic & E1000_MDIC_READY)
3135779Sxy150489 			break;
3145779Sxy150489 	}
3155779Sxy150489 	if (!(mdic & E1000_MDIC_READY)) {
3165779Sxy150489 		DEBUGOUT("MDI Write did not complete\n");
3175779Sxy150489 		ret_val = -E1000_ERR_PHY;
3185779Sxy150489 		goto out;
3195779Sxy150489 	}
3205779Sxy150489 	if (mdic & E1000_MDIC_ERROR) {
3215779Sxy150489 		DEBUGOUT("MDI Error\n");
3225779Sxy150489 		ret_val = -E1000_ERR_PHY;
3235779Sxy150489 		goto out;
3245779Sxy150489 	}
3255779Sxy150489 
3265779Sxy150489 out:
3275779Sxy150489 	return (ret_val);
3285779Sxy150489 }
3295779Sxy150489 
3305779Sxy150489 /*
3315779Sxy150489  * e1000_read_phy_reg_m88 - Read m88 PHY register
3325779Sxy150489  * @hw: pointer to the HW structure
3335779Sxy150489  * @offset: register offset to be read
3345779Sxy150489  * @data: pointer to the read data
3355779Sxy150489  *
3365779Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
3375779Sxy150489  * and storing the retrieved information in data.  Release any acquired
3385779Sxy150489  * semaphores before exiting.
3395779Sxy150489  */
3405779Sxy150489 s32
3415779Sxy150489 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
3425779Sxy150489 {
343*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
3445779Sxy150489 
3455779Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_m88");
3465779Sxy150489 
347*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
348*8571SChenlu.Chen@Sun.COM 		goto out;
349*8571SChenlu.Chen@Sun.COM 
350*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
3515779Sxy150489 	if (ret_val)
3525779Sxy150489 		goto out;
3535779Sxy150489 
3545779Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw,
3555779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
3565779Sxy150489 
357*8571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
3585779Sxy150489 
3595779Sxy150489 out:
3605779Sxy150489 	return (ret_val);
3615779Sxy150489 }
3625779Sxy150489 
3635779Sxy150489 /*
3645779Sxy150489  * e1000_write_phy_reg_m88 - Write m88 PHY register
3655779Sxy150489  * @hw: pointer to the HW structure
3665779Sxy150489  * @offset: register offset to write to
3675779Sxy150489  * @data: data to write at register offset
3685779Sxy150489  *
3695779Sxy150489  * Acquires semaphore, if necessary, then writes the data to PHY register
3705779Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
3715779Sxy150489  */
3725779Sxy150489 s32
3735779Sxy150489 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
3745779Sxy150489 {
375*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
3765779Sxy150489 
3775779Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_m88");
3785779Sxy150489 
379*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
380*8571SChenlu.Chen@Sun.COM 		goto out;
381*8571SChenlu.Chen@Sun.COM 
382*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
3835779Sxy150489 	if (ret_val)
3845779Sxy150489 		goto out;
3855779Sxy150489 
3865779Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
3875779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
3885779Sxy150489 
389*8571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
3905779Sxy150489 
3915779Sxy150489 out:
3925779Sxy150489 	return (ret_val);
3935779Sxy150489 }
3945779Sxy150489 
3955779Sxy150489 /*
3965779Sxy150489  * e1000_read_phy_reg_igp - Read igp PHY register
3975779Sxy150489  * @hw: pointer to the HW structure
3985779Sxy150489  * @offset: register offset to be read
3995779Sxy150489  * @data: pointer to the read data
4005779Sxy150489  *
4015779Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
4025779Sxy150489  * and storing the retrieved information in data.  Release any acquired
4035779Sxy150489  * semaphores before exiting.
4045779Sxy150489  */
4055779Sxy150489 s32
4065779Sxy150489 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
4075779Sxy150489 {
408*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
4095779Sxy150489 
4105779Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_igp");
4115779Sxy150489 
412*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
413*8571SChenlu.Chen@Sun.COM 		goto out;
414*8571SChenlu.Chen@Sun.COM 
415*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
4165779Sxy150489 	if (ret_val)
4175779Sxy150489 		goto out;
4185779Sxy150489 
4195779Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
4205779Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw,
4215779Sxy150489 		    IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
4225779Sxy150489 		if (ret_val) {
423*8571SChenlu.Chen@Sun.COM 			hw->phy.ops.release(hw);
4245779Sxy150489 			goto out;
4255779Sxy150489 		}
4265779Sxy150489 	}
4275779Sxy150489 
4285779Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw,
4295779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
4305779Sxy150489 
431*8571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
4325779Sxy150489 
4335779Sxy150489 out:
4345779Sxy150489 	return (ret_val);
4355779Sxy150489 }
4365779Sxy150489 
4375779Sxy150489 /*
4385779Sxy150489  * e1000_write_phy_reg_igp - Write igp PHY register
4395779Sxy150489  * @hw: pointer to the HW structure
4405779Sxy150489  * @offset: register offset to write to
4415779Sxy150489  * @data: data to write at register offset
4425779Sxy150489  *
4435779Sxy150489  * Acquires semaphore, if necessary, then writes the data to PHY register
4445779Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
4455779Sxy150489  */
4465779Sxy150489 s32
4475779Sxy150489 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
4485779Sxy150489 {
449*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
4505779Sxy150489 
4515779Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_igp");
4525779Sxy150489 
453*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
454*8571SChenlu.Chen@Sun.COM 		goto out;
455*8571SChenlu.Chen@Sun.COM 
456*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
4575779Sxy150489 	if (ret_val)
4585779Sxy150489 		goto out;
4595779Sxy150489 
4605779Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
4615779Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw,
4625779Sxy150489 		    IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
4635779Sxy150489 		if (ret_val) {
464*8571SChenlu.Chen@Sun.COM 			hw->phy.ops.release(hw);
4655779Sxy150489 			goto out;
4665779Sxy150489 		}
4675779Sxy150489 	}
4685779Sxy150489 
4695779Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
4705779Sxy150489 	    MAX_PHY_REG_ADDRESS & offset, data);
4715779Sxy150489 
472*8571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
4735779Sxy150489 
4745779Sxy150489 out:
4755779Sxy150489 	return (ret_val);
4765779Sxy150489 }
4775779Sxy150489 
4785779Sxy150489 /*
4795779Sxy150489  * e1000_read_kmrn_reg_generic - Read kumeran register
4805779Sxy150489  * @hw: pointer to the HW structure
4815779Sxy150489  * @offset: register offset to be read
4825779Sxy150489  * @data: pointer to the read data
4835779Sxy150489  *
4845779Sxy150489  * Acquires semaphore, if necessary.  Then reads the PHY register at offset
4855779Sxy150489  * using the kumeran interface.  The information retrieved is stored in data.
4865779Sxy150489  * Release any acquired semaphores before exiting.
4875779Sxy150489  */
4885779Sxy150489 s32
4895779Sxy150489 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
4905779Sxy150489 {
4915779Sxy150489 	u32 kmrnctrlsta;
492*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
4935779Sxy150489 
4945779Sxy150489 	DEBUGFUNC("e1000_read_kmrn_reg_generic");
4955779Sxy150489 
496*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
497*8571SChenlu.Chen@Sun.COM 		goto out;
498*8571SChenlu.Chen@Sun.COM 
499*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
5005779Sxy150489 	if (ret_val)
5015779Sxy150489 		goto out;
5025779Sxy150489 
5035779Sxy150489 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
5045779Sxy150489 	    E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
5055779Sxy150489 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
5065779Sxy150489 
5075779Sxy150489 	usec_delay(2);
5085779Sxy150489 
5095779Sxy150489 	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
5105779Sxy150489 	*data = (u16)kmrnctrlsta;
5115779Sxy150489 
512*8571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
5135779Sxy150489 
5145779Sxy150489 out:
5155779Sxy150489 	return (ret_val);
5165779Sxy150489 }
5175779Sxy150489 
5185779Sxy150489 /*
5195779Sxy150489  * e1000_write_kmrn_reg_generic - Write kumeran register
5205779Sxy150489  * @hw: pointer to the HW structure
5215779Sxy150489  * @offset: register offset to write to
5225779Sxy150489  * @data: data to write at register offset
5235779Sxy150489  *
5245779Sxy150489  * Acquires semaphore, if necessary.  Then write the data to PHY register
5255779Sxy150489  * at the offset using the kumeran interface.  Release any acquired semaphores
5265779Sxy150489  * before exiting.
5275779Sxy150489  */
5285779Sxy150489 s32
5295779Sxy150489 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
5305779Sxy150489 {
5315779Sxy150489 	u32 kmrnctrlsta;
532*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
5335779Sxy150489 
5345779Sxy150489 	DEBUGFUNC("e1000_write_kmrn_reg_generic");
5355779Sxy150489 
536*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.acquire))
537*8571SChenlu.Chen@Sun.COM 		goto out;
538*8571SChenlu.Chen@Sun.COM 
539*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
5405779Sxy150489 	if (ret_val)
5415779Sxy150489 		goto out;
5425779Sxy150489 
5435779Sxy150489 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
5445779Sxy150489 	    E1000_KMRNCTRLSTA_OFFSET) | data;
5455779Sxy150489 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
5465779Sxy150489 
5475779Sxy150489 	usec_delay(2);
548*8571SChenlu.Chen@Sun.COM 	hw->phy.ops.release(hw);
5495779Sxy150489 
5505779Sxy150489 out:
5515779Sxy150489 	return (ret_val);
5525779Sxy150489 }
5535779Sxy150489 
5545779Sxy150489 /*
5555779Sxy150489  * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
5565779Sxy150489  * @hw: pointer to the HW structure
5575779Sxy150489  *
5585779Sxy150489  * Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
5595779Sxy150489  * and downshift values are set also.
5605779Sxy150489  */
5615779Sxy150489 s32
5625779Sxy150489 e1000_copper_link_setup_m88(struct e1000_hw *hw)
5635779Sxy150489 {
5645779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
5655779Sxy150489 	s32 ret_val;
5665779Sxy150489 	u16 phy_data;
5675779Sxy150489 
5685779Sxy150489 	DEBUGFUNC("e1000_copper_link_setup_m88");
5695779Sxy150489 
5705779Sxy150489 	if (phy->reset_disable) {
5715779Sxy150489 		ret_val = E1000_SUCCESS;
5725779Sxy150489 		goto out;
5735779Sxy150489 	}
5745779Sxy150489 
5755779Sxy150489 	/* Enable CRS on TX. This must be set for half-duplex operation. */
576*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
5775779Sxy150489 	if (ret_val)
5785779Sxy150489 		goto out;
5795779Sxy150489 
580*8571SChenlu.Chen@Sun.COM 	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
5815779Sxy150489 
5825779Sxy150489 	/*
5835779Sxy150489 	 * Options:
5845779Sxy150489 	 *   MDI/MDI-X = 0 (default)
5855779Sxy150489 	 *   0 - Auto for all speeds
5865779Sxy150489 	 *   1 - MDI mode
5875779Sxy150489 	 *   2 - MDI-X mode
5885779Sxy150489 	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
5895779Sxy150489 	 */
5905779Sxy150489 	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
5915779Sxy150489 
5925779Sxy150489 	switch (phy->mdix) {
5935779Sxy150489 		case 1:
5945779Sxy150489 			phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
5955779Sxy150489 			break;
5965779Sxy150489 		case 2:
5975779Sxy150489 			phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
5985779Sxy150489 			break;
5995779Sxy150489 		case 3:
6005779Sxy150489 			phy_data |= M88E1000_PSCR_AUTO_X_1000T;
6015779Sxy150489 			break;
6025779Sxy150489 		case 0:
6035779Sxy150489 		default:
6045779Sxy150489 			phy_data |= M88E1000_PSCR_AUTO_X_MODE;
6055779Sxy150489 			break;
6065779Sxy150489 	}
6075779Sxy150489 
6085779Sxy150489 	/*
6095779Sxy150489 	 * Options:
6105779Sxy150489 	 *   disable_polarity_correction = 0 (default)
6115779Sxy150489 	 *	Automatic Correction for Reversed Cable Polarity
6125779Sxy150489 	 *   0 - Disabled
6135779Sxy150489 	 *   1 - Enabled
6145779Sxy150489 	 */
6155779Sxy150489 	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
6165779Sxy150489 	if (phy->disable_polarity_correction == 1)
6175779Sxy150489 		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
6185779Sxy150489 
619*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
6205779Sxy150489 	if (ret_val)
6215779Sxy150489 		goto out;
6225779Sxy150489 
623*8571SChenlu.Chen@Sun.COM 	if (phy->revision < E1000_REVISION_4) {
6245779Sxy150489 		/*
6255779Sxy150489 		 * Force TX_CLK in the Extended PHY Specific Control Register
6265779Sxy150489 		 * to 25MHz clock.
6275779Sxy150489 		 */
628*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
629*8571SChenlu.Chen@Sun.COM 		    &phy_data);
6305779Sxy150489 		if (ret_val)
6315779Sxy150489 			goto out;
6325779Sxy150489 
6335779Sxy150489 		phy_data |= M88E1000_EPSCR_TX_CLK_25;
6345779Sxy150489 
6355779Sxy150489 		if ((phy->revision == E1000_REVISION_2) &&
6365779Sxy150489 		    (phy->id == M88E1111_I_PHY_ID)) {
6375779Sxy150489 			/* 82573L PHY - set the downshift counter to 5x. */
6385779Sxy150489 			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
6395779Sxy150489 			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
6405779Sxy150489 		} else {
6415779Sxy150489 			/* Configure Master and Slave downshift values */
6425779Sxy150489 			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
6435779Sxy150489 			    M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
6445779Sxy150489 			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
6455779Sxy150489 			    M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
6465779Sxy150489 		}
647*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
648*8571SChenlu.Chen@Sun.COM 		    phy_data);
6495779Sxy150489 		if (ret_val)
6505779Sxy150489 			goto out;
6515779Sxy150489 	}
6525779Sxy150489 
6535779Sxy150489 	/* Commit the changes. */
654*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.commit(hw);
6555779Sxy150489 	if (ret_val) {
6565779Sxy150489 		DEBUGOUT("Error committing the PHY changes\n");
6575779Sxy150489 		goto out;
6585779Sxy150489 	}
6595779Sxy150489 
6605779Sxy150489 out:
6615779Sxy150489 	return (ret_val);
6625779Sxy150489 }
6635779Sxy150489 
6645779Sxy150489 /*
6655779Sxy150489  * e1000_copper_link_setup_igp - Setup igp PHY's for copper link
6665779Sxy150489  * @hw: pointer to the HW structure
6675779Sxy150489  *
6685779Sxy150489  * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
6695779Sxy150489  * igp PHY's.
6705779Sxy150489  */
6715779Sxy150489 s32
6725779Sxy150489 e1000_copper_link_setup_igp(struct e1000_hw *hw)
6735779Sxy150489 {
6745779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
6755779Sxy150489 	s32 ret_val;
6765779Sxy150489 	u16 data;
6775779Sxy150489 
6785779Sxy150489 	DEBUGFUNC("e1000_copper_link_setup_igp");
6795779Sxy150489 
6805779Sxy150489 	if (phy->reset_disable) {
6815779Sxy150489 		ret_val = E1000_SUCCESS;
6825779Sxy150489 		goto out;
6835779Sxy150489 	}
6845779Sxy150489 
685*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.reset(hw);
6865779Sxy150489 	if (ret_val) {
6875779Sxy150489 		DEBUGOUT("Error resetting the PHY.\n");
6885779Sxy150489 		goto out;
6895779Sxy150489 	}
6905779Sxy150489 
691*8571SChenlu.Chen@Sun.COM 	/*
692*8571SChenlu.Chen@Sun.COM 	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
693*8571SChenlu.Chen@Sun.COM 	 * timeout issues when LFS is enabled.
694*8571SChenlu.Chen@Sun.COM 	 */
695*8571SChenlu.Chen@Sun.COM 	msec_delay(100);
6965779Sxy150489 
6975779Sxy150489 	/*
6985779Sxy150489 	 * The NVM settings will configure LPLU in D3 for
6995779Sxy150489 	 * non-IGP1 PHYs.
7005779Sxy150489 	 */
7015779Sxy150489 	if (phy->type == e1000_phy_igp) {
7025779Sxy150489 		/* disable lplu d3 during driver init */
703*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
7045779Sxy150489 		if (ret_val) {
7055779Sxy150489 			DEBUGOUT("Error Disabling LPLU D3\n");
7065779Sxy150489 			goto out;
7075779Sxy150489 		}
7085779Sxy150489 	}
7095779Sxy150489 
7105779Sxy150489 	/* disable lplu d0 during driver init */
711*8571SChenlu.Chen@Sun.COM 	if (hw->phy.ops.set_d0_lplu_state) {
712*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
713*8571SChenlu.Chen@Sun.COM 		if (ret_val) {
714*8571SChenlu.Chen@Sun.COM 			DEBUGOUT("Error Disabling LPLU D0\n");
715*8571SChenlu.Chen@Sun.COM 			goto out;
716*8571SChenlu.Chen@Sun.COM 		}
7175779Sxy150489 	}
7185779Sxy150489 	/* Configure mdi-mdix settings */
719*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
7205779Sxy150489 	if (ret_val)
7215779Sxy150489 		goto out;
7225779Sxy150489 
7235779Sxy150489 	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
7245779Sxy150489 
7255779Sxy150489 	switch (phy->mdix) {
7265779Sxy150489 	case 1:
7275779Sxy150489 		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
7285779Sxy150489 		break;
7295779Sxy150489 	case 2:
7305779Sxy150489 		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
7315779Sxy150489 		break;
7325779Sxy150489 	case 0:
7335779Sxy150489 	default:
7345779Sxy150489 		data |= IGP01E1000_PSCR_AUTO_MDIX;
7355779Sxy150489 		break;
7365779Sxy150489 	}
737*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
7385779Sxy150489 	if (ret_val)
7395779Sxy150489 		goto out;
7405779Sxy150489 
7415779Sxy150489 	/* set auto-master slave resolution settings */
7425779Sxy150489 	if (hw->mac.autoneg) {
7435779Sxy150489 		/*
7445779Sxy150489 		 * when autonegotiation advertisement is only 1000Mbps then we
7455779Sxy150489 		 * should disable SmartSpeed and enable Auto MasterSlave
7465779Sxy150489 		 * resolution as hardware default.
7475779Sxy150489 		 */
7485779Sxy150489 		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
7495779Sxy150489 			/* Disable SmartSpeed */
750*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw,
7515779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG, &data);
7525779Sxy150489 			if (ret_val)
7535779Sxy150489 				goto out;
7545779Sxy150489 
7555779Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
756*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
7575779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG, data);
7585779Sxy150489 			if (ret_val)
7595779Sxy150489 				goto out;
7605779Sxy150489 
7615779Sxy150489 			/* Set auto Master/Slave resolution process */
762*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
7635779Sxy150489 			if (ret_val)
7645779Sxy150489 				goto out;
7655779Sxy150489 
7665779Sxy150489 			data &= ~CR_1000T_MS_ENABLE;
767*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
7685779Sxy150489 			if (ret_val)
7695779Sxy150489 				goto out;
7705779Sxy150489 		}
7715779Sxy150489 
772*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
7735779Sxy150489 		if (ret_val)
7745779Sxy150489 			goto out;
7755779Sxy150489 
7765779Sxy150489 		/* load defaults for future use */
7775779Sxy150489 		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
7785779Sxy150489 		    ((data & CR_1000T_MS_VALUE) ?
7795779Sxy150489 		    e1000_ms_force_master :
7805779Sxy150489 		    e1000_ms_force_slave) :
7815779Sxy150489 		    e1000_ms_auto;
7825779Sxy150489 
7835779Sxy150489 		switch (phy->ms_type) {
7845779Sxy150489 		case e1000_ms_force_master:
7855779Sxy150489 			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
7865779Sxy150489 			break;
7875779Sxy150489 		case e1000_ms_force_slave:
7885779Sxy150489 			data |= CR_1000T_MS_ENABLE;
7895779Sxy150489 			data &= ~(CR_1000T_MS_VALUE);
7905779Sxy150489 			break;
7915779Sxy150489 		case e1000_ms_auto:
7925779Sxy150489 			data &= ~CR_1000T_MS_ENABLE;
7935779Sxy150489 		default:
7945779Sxy150489 			break;
7955779Sxy150489 		}
796*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
7975779Sxy150489 		if (ret_val)
7985779Sxy150489 			goto out;
7995779Sxy150489 	}
8005779Sxy150489 
8015779Sxy150489 out:
8025779Sxy150489 	return (ret_val);
8035779Sxy150489 }
8045779Sxy150489 
8055779Sxy150489 /*
8065779Sxy150489  * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
8075779Sxy150489  * @hw: pointer to the HW structure
8085779Sxy150489  *
8095779Sxy150489  * Performs initial bounds checking on autoneg advertisement parameter, then
8105779Sxy150489  * configure to advertise the full capability.  Setup the PHY to autoneg
8115779Sxy150489  * and restart the negotiation process between the link partner.  If
8125779Sxy150489  * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
8135779Sxy150489  */
8145779Sxy150489 s32
8155779Sxy150489 e1000_copper_link_autoneg(struct e1000_hw *hw)
8165779Sxy150489 {
8175779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
8185779Sxy150489 	s32 ret_val;
8195779Sxy150489 	u16 phy_ctrl;
8205779Sxy150489 
8215779Sxy150489 	DEBUGFUNC("e1000_copper_link_autoneg");
8225779Sxy150489 
8235779Sxy150489 	/*
8245779Sxy150489 	 * Perform some bounds checking on the autoneg advertisement
8255779Sxy150489 	 * parameter.
8265779Sxy150489 	 */
8275779Sxy150489 	phy->autoneg_advertised &= phy->autoneg_mask;
8285779Sxy150489 
8295779Sxy150489 	/*
8305779Sxy150489 	 * If autoneg_advertised is zero, we assume it was not defaulted
8315779Sxy150489 	 * by the calling code so we set to advertise full capability.
8325779Sxy150489 	 */
8335779Sxy150489 	if (phy->autoneg_advertised == 0)
8345779Sxy150489 		phy->autoneg_advertised = phy->autoneg_mask;
8355779Sxy150489 
8365779Sxy150489 	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
8375779Sxy150489 	ret_val = e1000_phy_setup_autoneg(hw);
8385779Sxy150489 	if (ret_val) {
8395779Sxy150489 		DEBUGOUT("Error Setting up Auto-Negotiation\n");
8405779Sxy150489 		goto out;
8415779Sxy150489 	}
8425779Sxy150489 	DEBUGOUT("Restarting Auto-Neg\n");
8435779Sxy150489 
8445779Sxy150489 	/*
8455779Sxy150489 	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
8465779Sxy150489 	 * the Auto Neg Restart bit in the PHY control register.
8475779Sxy150489 	 */
848*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
8495779Sxy150489 	if (ret_val)
8505779Sxy150489 		goto out;
8515779Sxy150489 
8525779Sxy150489 	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
853*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
8545779Sxy150489 	if (ret_val)
8555779Sxy150489 		goto out;
8565779Sxy150489 
8575779Sxy150489 	/*
8585779Sxy150489 	 * Does the user want to wait for Auto-Neg to complete here, or
8595779Sxy150489 	 * check at a later time (for example, callback routine).
8605779Sxy150489 	 */
8615779Sxy150489 	if (phy->autoneg_wait_to_complete) {
862*8571SChenlu.Chen@Sun.COM 		ret_val = hw->mac.ops.wait_autoneg(hw);
8635779Sxy150489 		if (ret_val) {
8645779Sxy150489 			DEBUGOUT("Error while waiting for "
8655779Sxy150489 			    "autoneg to complete\n");
8665779Sxy150489 			goto out;
8675779Sxy150489 		}
8685779Sxy150489 	}
8695779Sxy150489 
870*8571SChenlu.Chen@Sun.COM 	hw->mac.get_link_status = true;
8715779Sxy150489 
8725779Sxy150489 out:
8735779Sxy150489 	return (ret_val);
8745779Sxy150489 }
8755779Sxy150489 
8765779Sxy150489 /*
8775779Sxy150489  * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
8785779Sxy150489  * @hw: pointer to the HW structure
8795779Sxy150489  *
8805779Sxy150489  * Reads the MII auto-neg advertisement register and/or the 1000T control
8815779Sxy150489  * register and if the PHY is already setup for auto-negotiation, then
8825779Sxy150489  * return successful.  Otherwise, setup advertisement and flow control to
8835779Sxy150489  * the appropriate values for the wanted auto-negotiation.
8845779Sxy150489  */
8855779Sxy150489 s32
8865779Sxy150489 e1000_phy_setup_autoneg(struct e1000_hw *hw)
8875779Sxy150489 {
8885779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
8895779Sxy150489 	s32 ret_val;
8905779Sxy150489 	u16 mii_autoneg_adv_reg;
8915779Sxy150489 	u16 mii_1000t_ctrl_reg = 0;
8925779Sxy150489 
8935779Sxy150489 	DEBUGFUNC("e1000_phy_setup_autoneg");
8945779Sxy150489 
8955779Sxy150489 	phy->autoneg_advertised &= phy->autoneg_mask;
8965779Sxy150489 
8975779Sxy150489 	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
898*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
8995779Sxy150489 	if (ret_val)
9005779Sxy150489 		goto out;
9015779Sxy150489 
9025779Sxy150489 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
9035779Sxy150489 		/* Read the MII 1000Base-T Control Register (Address 9). */
904*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
905*8571SChenlu.Chen@Sun.COM 		    &mii_1000t_ctrl_reg);
9065779Sxy150489 		if (ret_val)
9075779Sxy150489 			goto out;
9085779Sxy150489 	}
9095779Sxy150489 
9105779Sxy150489 	/*
9115779Sxy150489 	 * Need to parse both autoneg_advertised and fc and set up
9125779Sxy150489 	 * the appropriate PHY registers.  First we will parse for
9135779Sxy150489 	 * autoneg_advertised software override.  Since we can advertise
9145779Sxy150489 	 * a plethora of combinations, we need to check each bit
9155779Sxy150489 	 * individually.
9165779Sxy150489 	 */
9175779Sxy150489 
9185779Sxy150489 	/*
9195779Sxy150489 	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
9205779Sxy150489 	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
9215779Sxy150489 	 * the  1000Base-T Control Register (Address 9).
9225779Sxy150489 	 */
9235779Sxy150489 	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
9245779Sxy150489 	    NWAY_AR_100TX_HD_CAPS |
9255779Sxy150489 	    NWAY_AR_10T_FD_CAPS   |
9265779Sxy150489 	    NWAY_AR_10T_HD_CAPS);
9275779Sxy150489 	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
9285779Sxy150489 
9295779Sxy150489 	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
9305779Sxy150489 
9315779Sxy150489 	/* Do we want to advertise 10 Mb Half Duplex? */
9325779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
9335779Sxy150489 		DEBUGOUT("Advertise 10mb Half duplex\n");
9345779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
9355779Sxy150489 	}
9365779Sxy150489 
9375779Sxy150489 	/* Do we want to advertise 10 Mb Full Duplex? */
9385779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
9395779Sxy150489 		DEBUGOUT("Advertise 10mb Full duplex\n");
9405779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
9415779Sxy150489 	}
9425779Sxy150489 
9435779Sxy150489 	/* Do we want to advertise 100 Mb Half Duplex? */
9445779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
9455779Sxy150489 		DEBUGOUT("Advertise 100mb Half duplex\n");
9465779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
9475779Sxy150489 	}
9485779Sxy150489 
9495779Sxy150489 	/* Do we want to advertise 100 Mb Full Duplex? */
9505779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
9515779Sxy150489 		DEBUGOUT("Advertise 100mb Full duplex\n");
9525779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
9535779Sxy150489 	}
9545779Sxy150489 
9555779Sxy150489 	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
956*8571SChenlu.Chen@Sun.COM 	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
9575779Sxy150489 		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
9585779Sxy150489 
9595779Sxy150489 	/* Do we want to advertise 1000 Mb Full Duplex? */
9605779Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
9615779Sxy150489 		DEBUGOUT("Advertise 1000mb Full duplex\n");
9625779Sxy150489 		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
9635779Sxy150489 	}
9645779Sxy150489 
9655779Sxy150489 	/*
9665779Sxy150489 	 * Check for a software override of the flow control settings, and
9675779Sxy150489 	 * setup the PHY advertisement registers accordingly.  If
9685779Sxy150489 	 * auto-negotiation is enabled, then software will have to set the
9695779Sxy150489 	 * "PAUSE" bits to the correct value in the Auto-Negotiation
9705779Sxy150489 	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
9715779Sxy150489 	 * negotiation.
9725779Sxy150489 	 *
9735779Sxy150489 	 * The possible values of the "fc" parameter are:
9745779Sxy150489 	 * 0:	Flow control is completely disabled
9755779Sxy150489 	 * 1:	Rx flow control is enabled (we can receive pause frames
9765779Sxy150489 	 *	but not send pause frames).
9775779Sxy150489 	 * 2:	Tx flow control is enabled (we can send pause frames
9785779Sxy150489 	 *	but we do not support receiving pause frames).
9795779Sxy150489 	 * 3:	Both Rx and Tx flow control (symmetric) are enabled.
9805779Sxy150489 	 * other: No software override.  The flow control configuration
9815779Sxy150489 	 *	in the EEPROM is used.
9825779Sxy150489 	 */
983*8571SChenlu.Chen@Sun.COM 	switch (hw->fc.current_mode) {
9845779Sxy150489 	case e1000_fc_none:
9855779Sxy150489 		/*
9865779Sxy150489 		 * Flow control (Rx & Tx) is completely disabled by a
9875779Sxy150489 		 * software over-ride.
9885779Sxy150489 		 */
9895779Sxy150489 		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
9905779Sxy150489 		break;
9915779Sxy150489 	case e1000_fc_rx_pause:
9925779Sxy150489 		/*
9935779Sxy150489 		 * Rx Flow control is enabled, and Tx Flow control is
9945779Sxy150489 		 * disabled, by a software over-ride.
9955779Sxy150489 		 *
9965779Sxy150489 		 * Since there really isn't a way to advertise that we are
9975779Sxy150489 		 * capable of Rx Pause ONLY, we will advertise that we
9985779Sxy150489 		 * support both symmetric and asymmetric Rx PAUSE.  Later
9995779Sxy150489 		 * (in e1000_config_fc_after_link_up) we will disable the
10005779Sxy150489 		 * hw's ability to send PAUSE frames.
10015779Sxy150489 		 */
10025779Sxy150489 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
10035779Sxy150489 		break;
10045779Sxy150489 	case e1000_fc_tx_pause:
10055779Sxy150489 		/*
10065779Sxy150489 		 * Tx Flow control is enabled, and Rx Flow control is
10075779Sxy150489 		 * disabled, by a software over-ride.
10085779Sxy150489 		 */
10095779Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
10105779Sxy150489 		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
10115779Sxy150489 		break;
10125779Sxy150489 	case e1000_fc_full:
10135779Sxy150489 		/*
10145779Sxy150489 		 * Flow control (both Rx and Tx) is enabled by a software
10155779Sxy150489 		 * over-ride.
10165779Sxy150489 		 */
10175779Sxy150489 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
10185779Sxy150489 		break;
10195779Sxy150489 	default:
10205779Sxy150489 		DEBUGOUT("Flow control param set incorrectly\n");
10215779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
10225779Sxy150489 		goto out;
10235779Sxy150489 	}
10245779Sxy150489 
1025*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
10265779Sxy150489 	if (ret_val)
10275779Sxy150489 		goto out;
10285779Sxy150489 
10295779Sxy150489 	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
10305779Sxy150489 
10315779Sxy150489 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
1032*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
10335779Sxy150489 		    PHY_1000T_CTRL, mii_1000t_ctrl_reg);
10345779Sxy150489 		if (ret_val)
10355779Sxy150489 			goto out;
10365779Sxy150489 	}
10375779Sxy150489 
10385779Sxy150489 out:
10395779Sxy150489 	return (ret_val);
10405779Sxy150489 }
10415779Sxy150489 
10425779Sxy150489 /*
10435779Sxy150489  * e1000_setup_copper_link_generic - Configure copper link settings
10445779Sxy150489  * @hw: pointer to the HW structure
10455779Sxy150489  *
10465779Sxy150489  * Calls the appropriate function to configure the link for auto-neg or forced
10475779Sxy150489  * speed and duplex.  Then we check for link, once link is established calls
10485779Sxy150489  * to configure collision distance and flow control are called.  If link is
10495779Sxy150489  * not established, we return -E1000_ERR_PHY (-2).
10505779Sxy150489  */
10515779Sxy150489 s32
10525779Sxy150489 e1000_setup_copper_link_generic(struct e1000_hw *hw)
10535779Sxy150489 {
10545779Sxy150489 	s32 ret_val;
10555779Sxy150489 	bool link;
10565779Sxy150489 
10575779Sxy150489 	DEBUGFUNC("e1000_setup_copper_link_generic");
10585779Sxy150489 
10595779Sxy150489 	if (hw->mac.autoneg) {
10605779Sxy150489 		/*
10615779Sxy150489 		 * Setup autoneg and flow control advertisement and perform
10625779Sxy150489 		 * autonegotiation.
10635779Sxy150489 		 */
10645779Sxy150489 		ret_val = e1000_copper_link_autoneg(hw);
10655779Sxy150489 		if (ret_val)
10665779Sxy150489 			goto out;
10675779Sxy150489 	} else {
10685779Sxy150489 		/*
10695779Sxy150489 		 * PHY will be set to 10H, 10F, 100H or 100F
10705779Sxy150489 		 * depending on user settings.
10715779Sxy150489 		 */
10725779Sxy150489 		DEBUGOUT("Forcing Speed and Duplex\n");
1073*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.force_speed_duplex(hw);
10745779Sxy150489 		if (ret_val) {
10755779Sxy150489 			DEBUGOUT("Error Forcing Speed and Duplex\n");
10765779Sxy150489 			goto out;
10775779Sxy150489 		}
10785779Sxy150489 	}
10795779Sxy150489 
10805779Sxy150489 	/*
10815779Sxy150489 	 * Check link status. Wait up to 100 microseconds for link to become
10825779Sxy150489 	 * valid.
10835779Sxy150489 	 */
10845779Sxy150489 	ret_val = e1000_phy_has_link_generic(hw,
10855779Sxy150489 	    COPPER_LINK_UP_LIMIT,
10865779Sxy150489 	    10,
10875779Sxy150489 	    &link);
10885779Sxy150489 	if (ret_val)
10895779Sxy150489 		goto out;
10905779Sxy150489 
10915779Sxy150489 	if (link) {
10925779Sxy150489 		DEBUGOUT("Valid link established!!!\n");
10935779Sxy150489 		e1000_config_collision_dist_generic(hw);
10945779Sxy150489 		ret_val = e1000_config_fc_after_link_up_generic(hw);
10955779Sxy150489 	} else {
10965779Sxy150489 		DEBUGOUT("Unable to establish link!!!\n");
10975779Sxy150489 	}
10985779Sxy150489 
10995779Sxy150489 out:
11005779Sxy150489 	return (ret_val);
11015779Sxy150489 }
11025779Sxy150489 
11035779Sxy150489 /*
11045779Sxy150489  * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
11055779Sxy150489  * @hw: pointer to the HW structure
11065779Sxy150489  *
11075779Sxy150489  * Calls the PHY setup function to force speed and duplex.  Clears the
11085779Sxy150489  * auto-crossover to force MDI manually.  Waits for link and returns
11095779Sxy150489  * successful if link up is successful, else -E1000_ERR_PHY (-2).
11105779Sxy150489  */
11115779Sxy150489 s32
11125779Sxy150489 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
11135779Sxy150489 {
11145779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
11155779Sxy150489 	s32 ret_val;
11165779Sxy150489 	u16 phy_data;
11175779Sxy150489 	bool link;
11185779Sxy150489 
11195779Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
11205779Sxy150489 
1121*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
11225779Sxy150489 	if (ret_val)
11235779Sxy150489 		goto out;
11245779Sxy150489 
11255779Sxy150489 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
11265779Sxy150489 
1127*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
11285779Sxy150489 	if (ret_val)
11295779Sxy150489 		goto out;
11305779Sxy150489 
11315779Sxy150489 	/*
11325779Sxy150489 	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
11335779Sxy150489 	 * forced whenever speed and duplex are forced.
11345779Sxy150489 	 */
1135*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
11365779Sxy150489 	if (ret_val)
11375779Sxy150489 		goto out;
11385779Sxy150489 
11395779Sxy150489 	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
11405779Sxy150489 	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
11415779Sxy150489 
1142*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
11435779Sxy150489 	if (ret_val)
11445779Sxy150489 		goto out;
11455779Sxy150489 
11465779Sxy150489 	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
11475779Sxy150489 
11485779Sxy150489 	usec_delay(1);
11495779Sxy150489 
11505779Sxy150489 	if (phy->autoneg_wait_to_complete) {
11515779Sxy150489 		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
11525779Sxy150489 
11535779Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
11545779Sxy150489 		    PHY_FORCE_LIMIT,
11555779Sxy150489 		    100000,
11565779Sxy150489 		    &link);
11575779Sxy150489 		if (ret_val)
11585779Sxy150489 			goto out;
11595779Sxy150489 
1160*8571SChenlu.Chen@Sun.COM 		if (!link)
11615779Sxy150489 			DEBUGOUT("Link taking longer than expected.\n");
11625779Sxy150489 
11635779Sxy150489 		/* Try once more */
11645779Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
11655779Sxy150489 		    PHY_FORCE_LIMIT,
11665779Sxy150489 		    100000,
11675779Sxy150489 		    &link);
11685779Sxy150489 		if (ret_val)
11695779Sxy150489 			goto out;
11705779Sxy150489 	}
11715779Sxy150489 
11725779Sxy150489 out:
11735779Sxy150489 	return (ret_val);
11745779Sxy150489 }
11755779Sxy150489 
11765779Sxy150489 /*
11775779Sxy150489  * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
11785779Sxy150489  * @hw: pointer to the HW structure
11795779Sxy150489  *
11805779Sxy150489  * Calls the PHY setup function to force speed and duplex.  Clears the
11815779Sxy150489  * auto-crossover to force MDI manually.  Resets the PHY to commit the
11825779Sxy150489  * changes.  If time expires while waiting for link up, we reset the DSP.
11835779Sxy150489  * After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
11845779Sxy150489  * successful completion, else return corresponding error code.
11855779Sxy150489  */
11865779Sxy150489 s32
11875779Sxy150489 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
11885779Sxy150489 {
11895779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
11905779Sxy150489 	s32 ret_val;
11915779Sxy150489 	u16 phy_data;
11925779Sxy150489 	bool link;
11935779Sxy150489 
11945779Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
11955779Sxy150489 
11965779Sxy150489 	/*
11975779Sxy150489 	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
11985779Sxy150489 	 * forced whenever speed and duplex are forced.
11995779Sxy150489 	 */
1200*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
12015779Sxy150489 	if (ret_val)
12025779Sxy150489 		goto out;
12035779Sxy150489 
12045779Sxy150489 	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
1205*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
12065779Sxy150489 	if (ret_val)
12075779Sxy150489 		goto out;
12085779Sxy150489 
12095779Sxy150489 	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
12105779Sxy150489 
1211*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
12125779Sxy150489 	if (ret_val)
12135779Sxy150489 		goto out;
12145779Sxy150489 
12155779Sxy150489 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
12165779Sxy150489 
1217*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
12185779Sxy150489 	if (ret_val)
12195779Sxy150489 		goto out;
12205779Sxy150489 
1221*8571SChenlu.Chen@Sun.COM 	/* Reset the phy to commit changes. */
1222*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.commit(hw);
1223*8571SChenlu.Chen@Sun.COM 	if (ret_val)
1224*8571SChenlu.Chen@Sun.COM 		goto out;
12255779Sxy150489 
12265779Sxy150489 	if (phy->autoneg_wait_to_complete) {
12275779Sxy150489 		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
12285779Sxy150489 
1229*8571SChenlu.Chen@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
1230*8571SChenlu.Chen@Sun.COM 		    100000, &link);
12315779Sxy150489 		if (ret_val)
12325779Sxy150489 			goto out;
12335779Sxy150489 
12345779Sxy150489 		if (!link) {
12355779Sxy150489 			/*
12365779Sxy150489 			 * We didn't get link.
12375779Sxy150489 			 * Reset the DSP and cross our fingers.
12385779Sxy150489 			 */
1239*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
12405779Sxy150489 			    M88E1000_PHY_PAGE_SELECT,
12415779Sxy150489 			    0x001d);
12425779Sxy150489 			if (ret_val)
12435779Sxy150489 				goto out;
12445779Sxy150489 			ret_val = e1000_phy_reset_dsp_generic(hw);
12455779Sxy150489 			if (ret_val)
12465779Sxy150489 				goto out;
12475779Sxy150489 		}
12485779Sxy150489 
12495779Sxy150489 		/* Try once more */
1250*8571SChenlu.Chen@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
1251*8571SChenlu.Chen@Sun.COM 		    100000, &link);
12525779Sxy150489 		if (ret_val)
12535779Sxy150489 			goto out;
12545779Sxy150489 	}
12555779Sxy150489 
1256*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
12575779Sxy150489 	if (ret_val)
12585779Sxy150489 		goto out;
12595779Sxy150489 
12605779Sxy150489 	/*
12615779Sxy150489 	 * Resetting the phy means we need to re-force TX_CLK in the
12625779Sxy150489 	 * Extended PHY Specific Control Register to 25MHz clock from
12635779Sxy150489 	 * the reset value of 2.5MHz.
12645779Sxy150489 	 */
12655779Sxy150489 	phy_data |= M88E1000_EPSCR_TX_CLK_25;
1266*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
12675779Sxy150489 	if (ret_val)
12685779Sxy150489 		goto out;
12695779Sxy150489 
12705779Sxy150489 	/*
12715779Sxy150489 	 * In addition, we must re-enable CRS on Tx for both half and full
12725779Sxy150489 	 * duplex.
12735779Sxy150489 	 */
1274*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
12755779Sxy150489 	if (ret_val)
12765779Sxy150489 		goto out;
12775779Sxy150489 
12785779Sxy150489 	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
1279*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
12805779Sxy150489 
12815779Sxy150489 out:
12825779Sxy150489 	return (ret_val);
12835779Sxy150489 }
12845779Sxy150489 
12855779Sxy150489 /*
12865779Sxy150489  * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
12875779Sxy150489  * @hw: pointer to the HW structure
12885779Sxy150489  * @phy_ctrl: pointer to current value of PHY_CONTROL
12895779Sxy150489  *
12905779Sxy150489  * Forces speed and duplex on the PHY by doing the following: disable flow
12915779Sxy150489  * control, force speed/duplex on the MAC, disable auto speed detection,
12925779Sxy150489  * disable auto-negotiation, configure duplex, configure speed, configure
12935779Sxy150489  * the collision distance, write configuration to CTRL register.  The
12945779Sxy150489  * caller must write to the PHY_CONTROL register for these settings to
12955779Sxy150489  * take affect.
12965779Sxy150489  */
12975779Sxy150489 void
12985779Sxy150489 e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
12995779Sxy150489 {
13005779Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
13015779Sxy150489 	u32 ctrl;
13025779Sxy150489 
13035779Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
13045779Sxy150489 
13055779Sxy150489 	/* Turn off flow control when forcing speed/duplex */
1306*8571SChenlu.Chen@Sun.COM 	hw->fc.current_mode = e1000_fc_none;
13075779Sxy150489 
13085779Sxy150489 	/* Force speed/duplex on the mac */
13095779Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
13105779Sxy150489 	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
13115779Sxy150489 	ctrl &= ~E1000_CTRL_SPD_SEL;
13125779Sxy150489 
13135779Sxy150489 	/* Disable Auto Speed Detection */
13145779Sxy150489 	ctrl &= ~E1000_CTRL_ASDE;
13155779Sxy150489 
13165779Sxy150489 	/* Disable autoneg on the phy */
13175779Sxy150489 	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
13185779Sxy150489 
13195779Sxy150489 	/* Forcing Full or Half Duplex? */
13205779Sxy150489 	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
13215779Sxy150489 		ctrl &= ~E1000_CTRL_FD;
13225779Sxy150489 		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
13235779Sxy150489 		DEBUGOUT("Half Duplex\n");
13245779Sxy150489 	} else {
13255779Sxy150489 		ctrl |= E1000_CTRL_FD;
13265779Sxy150489 		*phy_ctrl |= MII_CR_FULL_DUPLEX;
13275779Sxy150489 		DEBUGOUT("Full Duplex\n");
13285779Sxy150489 	}
13295779Sxy150489 
13305779Sxy150489 	/* Forcing 10mb or 100mb? */
13315779Sxy150489 	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
13325779Sxy150489 		ctrl |= E1000_CTRL_SPD_100;
13335779Sxy150489 		*phy_ctrl |= MII_CR_SPEED_100;
13345779Sxy150489 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
13355779Sxy150489 		DEBUGOUT("Forcing 100mb\n");
13365779Sxy150489 	} else {
13375779Sxy150489 		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
13385779Sxy150489 		/* LINTED */
13395779Sxy150489 		*phy_ctrl |= MII_CR_SPEED_10;
13405779Sxy150489 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
13415779Sxy150489 		DEBUGOUT("Forcing 10mb\n");
13425779Sxy150489 	}
13435779Sxy150489 
13445779Sxy150489 	e1000_config_collision_dist_generic(hw);
13455779Sxy150489 
13465779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
13475779Sxy150489 }
13485779Sxy150489 
13495779Sxy150489 /*
13505779Sxy150489  * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
13515779Sxy150489  * @hw: pointer to the HW structure
13525779Sxy150489  * @active: boolean used to enable/disable lplu
13535779Sxy150489  *
13545779Sxy150489  * Success returns 0, Failure returns 1
13555779Sxy150489  *
13565779Sxy150489  * The low power link up (lplu) state is set to the power management level D3
13575779Sxy150489  * and SmartSpeed is disabled when active is true, else clear lplu for D3
13585779Sxy150489  * and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
13595779Sxy150489  * is used during Dx states where the power conservation is most important.
13605779Sxy150489  * During driver activity, SmartSpeed should be enabled so performance is
13615779Sxy150489  * maintained.
13625779Sxy150489  */
13635779Sxy150489 s32
13645779Sxy150489 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
13655779Sxy150489 {
13665779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
1367*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
13685779Sxy150489 	u16 data;
13695779Sxy150489 
13705779Sxy150489 	DEBUGFUNC("e1000_set_d3_lplu_state_generic");
13715779Sxy150489 
1372*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
1373*8571SChenlu.Chen@Sun.COM 		goto out;
1374*8571SChenlu.Chen@Sun.COM 
1375*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
13765779Sxy150489 	if (ret_val)
13775779Sxy150489 		goto out;
13785779Sxy150489 
13795779Sxy150489 	if (!active) {
13805779Sxy150489 		data &= ~IGP02E1000_PM_D3_LPLU;
1381*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
13825779Sxy150489 		    IGP02E1000_PHY_POWER_MGMT,
13835779Sxy150489 		    data);
13845779Sxy150489 		if (ret_val)
13855779Sxy150489 			goto out;
13865779Sxy150489 		/*
13875779Sxy150489 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
13885779Sxy150489 		 * during Dx states where the power conservation is most
13895779Sxy150489 		 * important.  During driver activity we should enable
13905779Sxy150489 		 * SmartSpeed, so performance is maintained.
13915779Sxy150489 		 */
13925779Sxy150489 		if (phy->smart_speed == e1000_smart_speed_on) {
1393*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw,
13945779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
13955779Sxy150489 			    &data);
13965779Sxy150489 			if (ret_val)
13975779Sxy150489 				goto out;
13985779Sxy150489 
13995779Sxy150489 			data |= IGP01E1000_PSCFR_SMART_SPEED;
1400*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
14015779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
14025779Sxy150489 			    data);
14035779Sxy150489 			if (ret_val)
14045779Sxy150489 				goto out;
14055779Sxy150489 		} else if (phy->smart_speed == e1000_smart_speed_off) {
1406*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.read_reg(hw,
14075779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
14085779Sxy150489 			    &data);
14095779Sxy150489 			if (ret_val)
14105779Sxy150489 				goto out;
14115779Sxy150489 
14125779Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
1413*8571SChenlu.Chen@Sun.COM 			ret_val = phy->ops.write_reg(hw,
14145779Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
14155779Sxy150489 			    data);
14165779Sxy150489 			if (ret_val)
14175779Sxy150489 				goto out;
14185779Sxy150489 		}
14195779Sxy150489 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
14205779Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
14215779Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
14225779Sxy150489 		data |= IGP02E1000_PM_D3_LPLU;
1423*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
14245779Sxy150489 		    IGP02E1000_PHY_POWER_MGMT,
14255779Sxy150489 		    data);
14265779Sxy150489 		if (ret_val)
14275779Sxy150489 			goto out;
14285779Sxy150489 
14295779Sxy150489 		/* When LPLU is enabled, we should disable SmartSpeed */
1430*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw,
14315779Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
14325779Sxy150489 		    &data);
14335779Sxy150489 		if (ret_val)
14345779Sxy150489 			goto out;
14355779Sxy150489 
14365779Sxy150489 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
1437*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.write_reg(hw,
14385779Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
14395779Sxy150489 		    data);
14405779Sxy150489 	}
14415779Sxy150489 
14425779Sxy150489 out:
14435779Sxy150489 	return (ret_val);
14445779Sxy150489 }
14455779Sxy150489 
14465779Sxy150489 /*
1447*8571SChenlu.Chen@Sun.COM  * e1000_check_downshift_generic - Checks whether a downshift in speed occurred
14485779Sxy150489  * @hw: pointer to the HW structure
14495779Sxy150489  *
14505779Sxy150489  * Success returns 0, Failure returns 1
14515779Sxy150489  *
14525779Sxy150489  * A downshift is detected by querying the PHY link health.
14535779Sxy150489  */
14545779Sxy150489 s32
14555779Sxy150489 e1000_check_downshift_generic(struct e1000_hw *hw)
14565779Sxy150489 {
14575779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
14585779Sxy150489 	s32 ret_val;
14595779Sxy150489 	u16 phy_data, offset, mask;
14605779Sxy150489 
14615779Sxy150489 	DEBUGFUNC("e1000_check_downshift_generic");
14625779Sxy150489 
14635779Sxy150489 	switch (phy->type) {
14645779Sxy150489 	case e1000_phy_m88:
14655779Sxy150489 	case e1000_phy_gg82563:
14665779Sxy150489 		offset	= M88E1000_PHY_SPEC_STATUS;
14675779Sxy150489 		mask	= M88E1000_PSSR_DOWNSHIFT;
14685779Sxy150489 		break;
14695779Sxy150489 	case e1000_phy_igp_2:
14705779Sxy150489 	case e1000_phy_igp:
14715779Sxy150489 	case e1000_phy_igp_3:
14725779Sxy150489 		offset	= IGP01E1000_PHY_LINK_HEALTH;
14735779Sxy150489 		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
14745779Sxy150489 		break;
14755779Sxy150489 	default:
14765779Sxy150489 		/* speed downshift not supported */
1477*8571SChenlu.Chen@Sun.COM 		phy->speed_downgraded = false;
14785779Sxy150489 		ret_val = E1000_SUCCESS;
14795779Sxy150489 		goto out;
14805779Sxy150489 	}
14815779Sxy150489 
1482*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
14835779Sxy150489 
14845779Sxy150489 	if (!ret_val)
1485*8571SChenlu.Chen@Sun.COM 		phy->speed_downgraded = (phy_data & mask) ? true : false;
14865779Sxy150489 
14875779Sxy150489 out:
14885779Sxy150489 	return (ret_val);
14895779Sxy150489 }
14905779Sxy150489 
14915779Sxy150489 /*
14925779Sxy150489  * e1000_check_polarity_m88 - Checks the polarity.
14935779Sxy150489  * @hw: pointer to the HW structure
14945779Sxy150489  *
14955779Sxy150489  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
14965779Sxy150489  *
14975779Sxy150489  * Polarity is determined based on the PHY specific status register.
14985779Sxy150489  */
14995779Sxy150489 s32
15005779Sxy150489 e1000_check_polarity_m88(struct e1000_hw *hw)
15015779Sxy150489 {
15025779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
15035779Sxy150489 	s32 ret_val;
15045779Sxy150489 	u16 data;
15055779Sxy150489 
15065779Sxy150489 	DEBUGFUNC("e1000_check_polarity_m88");
15075779Sxy150489 
1508*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
15095779Sxy150489 
15105779Sxy150489 	if (!ret_val)
15115779Sxy150489 		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
15125779Sxy150489 		    ? e1000_rev_polarity_reversed
15135779Sxy150489 		    : e1000_rev_polarity_normal;
15145779Sxy150489 
15155779Sxy150489 	return (ret_val);
15165779Sxy150489 }
15175779Sxy150489 
15185779Sxy150489 /*
15195779Sxy150489  * e1000_check_polarity_igp - Checks the polarity.
15205779Sxy150489  * @hw: pointer to the HW structure
15215779Sxy150489  *
15225779Sxy150489  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
15235779Sxy150489  *
15245779Sxy150489  * Polarity is determined based on the PHY port status register, and the
15255779Sxy150489  * current speed (since there is no polarity at 100Mbps).
15265779Sxy150489  */
15275779Sxy150489 s32
15285779Sxy150489 e1000_check_polarity_igp(struct e1000_hw *hw)
15295779Sxy150489 {
15305779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
15315779Sxy150489 	s32 ret_val;
15325779Sxy150489 	u16 data, offset, mask;
15335779Sxy150489 
15345779Sxy150489 	DEBUGFUNC("e1000_check_polarity_igp");
15355779Sxy150489 
15365779Sxy150489 	/*
15375779Sxy150489 	 * Polarity is determined based on the speed of
15385779Sxy150489 	 * our connection.
15395779Sxy150489 	 */
1540*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
15415779Sxy150489 	if (ret_val)
15425779Sxy150489 		goto out;
15435779Sxy150489 
15445779Sxy150489 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
15455779Sxy150489 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
15465779Sxy150489 		offset	= IGP01E1000_PHY_PCS_INIT_REG;
15475779Sxy150489 		mask	= IGP01E1000_PHY_POLARITY_MASK;
15485779Sxy150489 	} else {
15495779Sxy150489 		/*
15505779Sxy150489 		 * This really only applies to 10Mbps since
15515779Sxy150489 		 * there is no polarity for 100Mbps (always 0).
15525779Sxy150489 		 */
15535779Sxy150489 		offset	= IGP01E1000_PHY_PORT_STATUS;
15545779Sxy150489 		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
15555779Sxy150489 	}
15565779Sxy150489 
1557*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, offset, &data);
15585779Sxy150489 
15595779Sxy150489 	if (!ret_val)
15605779Sxy150489 		phy->cable_polarity = (data & mask)
15615779Sxy150489 		    ? e1000_rev_polarity_reversed
15625779Sxy150489 		    : e1000_rev_polarity_normal;
15635779Sxy150489 
15645779Sxy150489 out:
15655779Sxy150489 	return (ret_val);
15665779Sxy150489 }
15675779Sxy150489 
15685779Sxy150489 /*
1569*8571SChenlu.Chen@Sun.COM  * e1000_wait_autoneg_generic - Wait for auto-neg completion
15705779Sxy150489  * @hw: pointer to the HW structure
15715779Sxy150489  *
15725779Sxy150489  * Waits for auto-negotiation to complete or for the auto-negotiation time
15735779Sxy150489  * limit to expire, which ever happens first.
15745779Sxy150489  */
15755779Sxy150489 s32
15765779Sxy150489 e1000_wait_autoneg_generic(struct e1000_hw *hw)
15775779Sxy150489 {
15785779Sxy150489 	s32 ret_val = E1000_SUCCESS;
15795779Sxy150489 	u16 i, phy_status;
15805779Sxy150489 
15815779Sxy150489 	DEBUGFUNC("e1000_wait_autoneg_generic");
15825779Sxy150489 
1583*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
1584*8571SChenlu.Chen@Sun.COM 		return (E1000_SUCCESS);
1585*8571SChenlu.Chen@Sun.COM 
15865779Sxy150489 	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
15875779Sxy150489 	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
1588*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
15895779Sxy150489 		if (ret_val)
15905779Sxy150489 			break;
1591*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
15925779Sxy150489 		if (ret_val)
15935779Sxy150489 			break;
15945779Sxy150489 		if (phy_status & MII_SR_AUTONEG_COMPLETE)
15955779Sxy150489 			break;
15965779Sxy150489 		msec_delay(100);
15975779Sxy150489 	}
15985779Sxy150489 
15995779Sxy150489 	/*
16005779Sxy150489 	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
16015779Sxy150489 	 * has completed.
16025779Sxy150489 	 */
16035779Sxy150489 	return (ret_val);
16045779Sxy150489 }
16055779Sxy150489 
16065779Sxy150489 /*
16075779Sxy150489  * e1000_phy_has_link_generic - Polls PHY for link
16085779Sxy150489  * @hw: pointer to the HW structure
16095779Sxy150489  * @iterations: number of times to poll for link
16105779Sxy150489  * @usec_interval: delay between polling attempts
16115779Sxy150489  * @success: pointer to whether polling was successful or not
16125779Sxy150489  *
16135779Sxy150489  * Polls the PHY status register for link, 'iterations' number of times.
16145779Sxy150489  */
16155779Sxy150489 s32
16165779Sxy150489 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
16175779Sxy150489     u32 usec_interval, bool *success)
16185779Sxy150489 {
16195779Sxy150489 	s32 ret_val = E1000_SUCCESS;
16205779Sxy150489 	u16 i, phy_status;
16215779Sxy150489 
16225779Sxy150489 	DEBUGFUNC("e1000_phy_has_link_generic");
16235779Sxy150489 
1624*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
1625*8571SChenlu.Chen@Sun.COM 		return (E1000_SUCCESS);
1626*8571SChenlu.Chen@Sun.COM 
16275779Sxy150489 	for (i = 0; i < iterations; i++) {
16285779Sxy150489 		/*
16295779Sxy150489 		 * Some PHYs require the PHY_STATUS register to be read
16305779Sxy150489 		 * twice due to the link bit being sticky.  No harm doing
16315779Sxy150489 		 * it across the board.
16325779Sxy150489 		 */
1633*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
16345779Sxy150489 		if (ret_val)
16355779Sxy150489 			break;
1636*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
16375779Sxy150489 		if (ret_val)
16385779Sxy150489 			break;
16395779Sxy150489 		if (phy_status & MII_SR_LINK_STATUS)
16405779Sxy150489 			break;
16415779Sxy150489 		if (usec_interval >= 1000)
16425779Sxy150489 			msec_delay_irq(usec_interval/1000);
16435779Sxy150489 		else
16445779Sxy150489 			usec_delay(usec_interval);
16455779Sxy150489 	}
16465779Sxy150489 
1647*8571SChenlu.Chen@Sun.COM 	*success = (i < iterations) ? true : false;
16485779Sxy150489 
16495779Sxy150489 	return (ret_val);
16505779Sxy150489 }
16515779Sxy150489 
16525779Sxy150489 /*
16535779Sxy150489  * e1000_get_cable_length_m88 - Determine cable length for m88 PHY
16545779Sxy150489  * @hw: pointer to the HW structure
16555779Sxy150489  *
16565779Sxy150489  * Reads the PHY specific status register to retrieve the cable length
16575779Sxy150489  * information.  The cable length is determined by averaging the minimum and
16585779Sxy150489  * maximum values to get the "average" cable length.  The m88 PHY has four
16595779Sxy150489  * possible cable length values, which are:
16605779Sxy150489  *	Register Value		Cable Length
16615779Sxy150489  *	0			< 50 meters
16625779Sxy150489  *	1			50 - 80 meters
16635779Sxy150489  *	2			80 - 110 meters
16645779Sxy150489  *	3			110 - 140 meters
16655779Sxy150489  *	4			> 140 meters
16665779Sxy150489  */
16675779Sxy150489 s32
16685779Sxy150489 e1000_get_cable_length_m88(struct e1000_hw *hw)
16695779Sxy150489 {
16705779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
16715779Sxy150489 	s32 ret_val;
16725779Sxy150489 	u16 phy_data, index;
16735779Sxy150489 
16745779Sxy150489 	DEBUGFUNC("e1000_get_cable_length_m88");
16755779Sxy150489 
1676*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
16775779Sxy150489 	if (ret_val)
16785779Sxy150489 		goto out;
16795779Sxy150489 
16805779Sxy150489 	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
16815779Sxy150489 	    M88E1000_PSSR_CABLE_LENGTH_SHIFT;
1682*8571SChenlu.Chen@Sun.COM 	if (index < (M88E1000_CABLE_LENGTH_TABLE_SIZE + 1)) {
1683*8571SChenlu.Chen@Sun.COM 		phy->min_cable_length = e1000_m88_cable_length_table[index];
1684*8571SChenlu.Chen@Sun.COM 		phy->max_cable_length = e1000_m88_cable_length_table[index+1];
16855779Sxy150489 
1686*8571SChenlu.Chen@Sun.COM 		phy->cable_length = (phy->min_cable_length +
1687*8571SChenlu.Chen@Sun.COM 		    phy->max_cable_length) / 2;
1688*8571SChenlu.Chen@Sun.COM 	} else {
1689*8571SChenlu.Chen@Sun.COM 		ret_val = E1000_ERR_PHY;
1690*8571SChenlu.Chen@Sun.COM 	}
16915779Sxy150489 
16925779Sxy150489 out:
16935779Sxy150489 	return (ret_val);
16945779Sxy150489 }
16955779Sxy150489 
16965779Sxy150489 /*
16975779Sxy150489  * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
16985779Sxy150489  * @hw: pointer to the HW structure
16995779Sxy150489  *
17005779Sxy150489  * The automatic gain control (agc) normalizes the amplitude of the
17015779Sxy150489  * received signal, adjusting for the attenuation produced by the
1702*8571SChenlu.Chen@Sun.COM  * cable.  By reading the AGC registers, which represent the
1703*8571SChenlu.Chen@Sun.COM  * combination of coarse and fine gain value, the value can be put
17045779Sxy150489  * into a lookup table to obtain the approximate cable length
17055779Sxy150489  * for each channel.
17065779Sxy150489  */
17075779Sxy150489 s32
17085779Sxy150489 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
17095779Sxy150489 {
17105779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
17115779Sxy150489 	s32 ret_val = E1000_SUCCESS;
17125779Sxy150489 	u16 phy_data, i, agc_value = 0;
17135779Sxy150489 	u16 cur_agc_index, max_agc_index = 0;
17145779Sxy150489 	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
17155779Sxy150489 	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
17165779Sxy150489 		{IGP02E1000_PHY_AGC_A,
17175779Sxy150489 		IGP02E1000_PHY_AGC_B,
17185779Sxy150489 		IGP02E1000_PHY_AGC_C,
17195779Sxy150489 		IGP02E1000_PHY_AGC_D};
17205779Sxy150489 
17215779Sxy150489 	DEBUGFUNC("e1000_get_cable_length_igp_2");
17225779Sxy150489 
17235779Sxy150489 	/* Read the AGC registers for all channels */
17245779Sxy150489 	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
1725*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
17265779Sxy150489 		if (ret_val)
17275779Sxy150489 			goto out;
17285779Sxy150489 
17295779Sxy150489 		/*
17305779Sxy150489 		 * Getting bits 15:9, which represent the combination of
1731*8571SChenlu.Chen@Sun.COM 		 * coarse and fine gain values.  The result is a number
17325779Sxy150489 		 * that can be put into the lookup table to obtain the
17335779Sxy150489 		 * approximate cable length.
17345779Sxy150489 		 */
17355779Sxy150489 		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
17365779Sxy150489 		    IGP02E1000_AGC_LENGTH_MASK;
17375779Sxy150489 
17385779Sxy150489 		/* Array index bound check. */
17395779Sxy150489 		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
17405779Sxy150489 		    (cur_agc_index == 0)) {
17415779Sxy150489 			ret_val = -E1000_ERR_PHY;
17425779Sxy150489 			goto out;
17435779Sxy150489 		}
17445779Sxy150489 
17455779Sxy150489 		/* Remove min & max AGC values from calculation. */
17465779Sxy150489 		if (e1000_igp_2_cable_length_table[min_agc_index] >
17475779Sxy150489 		    e1000_igp_2_cable_length_table[cur_agc_index])
17485779Sxy150489 			min_agc_index = cur_agc_index;
17495779Sxy150489 		if (e1000_igp_2_cable_length_table[max_agc_index] <
17505779Sxy150489 		    e1000_igp_2_cable_length_table[cur_agc_index])
17515779Sxy150489 			max_agc_index = cur_agc_index;
17525779Sxy150489 
17535779Sxy150489 		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
17545779Sxy150489 	}
17555779Sxy150489 
17565779Sxy150489 	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
17575779Sxy150489 	    e1000_igp_2_cable_length_table[max_agc_index]);
17585779Sxy150489 	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
17595779Sxy150489 
17605779Sxy150489 	/* Calculate cable length with the error range of +/- 10 meters. */
17615779Sxy150489 	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
17625779Sxy150489 	    (agc_value - IGP02E1000_AGC_RANGE) : 0;
17635779Sxy150489 	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
17645779Sxy150489 
17655779Sxy150489 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
17665779Sxy150489 
17675779Sxy150489 out:
17685779Sxy150489 	return (ret_val);
17695779Sxy150489 }
17705779Sxy150489 
17715779Sxy150489 /*
17725779Sxy150489  * e1000_get_phy_info_m88 - Retrieve PHY information
17735779Sxy150489  * @hw: pointer to the HW structure
17745779Sxy150489  *
17755779Sxy150489  * Valid for only copper links.  Read the PHY status register (sticky read)
17765779Sxy150489  * to verify that link is up.  Read the PHY special control register to
17775779Sxy150489  * determine the polarity and 10base-T extended distance.  Read the PHY
17785779Sxy150489  * special status register to determine MDI/MDIx and current speed.  If
17795779Sxy150489  * speed is 1000, then determine cable length, local and remote receiver.
17805779Sxy150489  */
17815779Sxy150489 s32
17825779Sxy150489 e1000_get_phy_info_m88(struct e1000_hw *hw)
17835779Sxy150489 {
17845779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
17855779Sxy150489 	s32  ret_val;
17865779Sxy150489 	u16 phy_data;
17875779Sxy150489 	bool link;
17885779Sxy150489 
17895779Sxy150489 	DEBUGFUNC("e1000_get_phy_info_m88");
17905779Sxy150489 
17915779Sxy150489 	if (hw->phy.media_type != e1000_media_type_copper) {
17925779Sxy150489 		DEBUGOUT("Phy info is only valid for copper media\n");
17935779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
17945779Sxy150489 		goto out;
17955779Sxy150489 	}
17965779Sxy150489 
17975779Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
17985779Sxy150489 	if (ret_val)
17995779Sxy150489 		goto out;
18005779Sxy150489 
18015779Sxy150489 	if (!link) {
18025779Sxy150489 		DEBUGOUT("Phy info is only valid if link is up\n");
18035779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
18045779Sxy150489 		goto out;
18055779Sxy150489 	}
18065779Sxy150489 
1807*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
18085779Sxy150489 	if (ret_val)
18095779Sxy150489 		goto out;
18105779Sxy150489 
18115779Sxy150489 	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
1812*8571SChenlu.Chen@Sun.COM 	    ? true : false;
18135779Sxy150489 
18145779Sxy150489 	ret_val = e1000_check_polarity_m88(hw);
18155779Sxy150489 	if (ret_val)
18165779Sxy150489 		goto out;
18175779Sxy150489 
1818*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
18195779Sxy150489 	if (ret_val)
18205779Sxy150489 		goto out;
18215779Sxy150489 
1822*8571SChenlu.Chen@Sun.COM 	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
18235779Sxy150489 
18245779Sxy150489 	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
1825*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
18265779Sxy150489 		if (ret_val)
18275779Sxy150489 			goto out;
18285779Sxy150489 
1829*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
18305779Sxy150489 		if (ret_val)
18315779Sxy150489 			goto out;
18325779Sxy150489 
18335779Sxy150489 		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
18345779Sxy150489 		    ? e1000_1000t_rx_status_ok
18355779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
18365779Sxy150489 
18375779Sxy150489 		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
18385779Sxy150489 		    ? e1000_1000t_rx_status_ok
18395779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
18405779Sxy150489 	} else {
18415779Sxy150489 		/* Set values to "undefined" */
18425779Sxy150489 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
18435779Sxy150489 		phy->local_rx = e1000_1000t_rx_status_undefined;
18445779Sxy150489 		phy->remote_rx = e1000_1000t_rx_status_undefined;
18455779Sxy150489 	}
18465779Sxy150489 
18475779Sxy150489 out:
18485779Sxy150489 	return (ret_val);
18495779Sxy150489 }
18505779Sxy150489 
18515779Sxy150489 /*
18525779Sxy150489  * e1000_get_phy_info_igp - Retrieve igp PHY information
18535779Sxy150489  * @hw: pointer to the HW structure
18545779Sxy150489  *
18555779Sxy150489  * Read PHY status to determine if link is up.  If link is up, then
18565779Sxy150489  * set/determine 10base-T extended distance and polarity correction.  Read
18575779Sxy150489  * PHY port status to determine MDI/MDIx and speed.  Based on the speed,
18585779Sxy150489  * determine on the cable length, local and remote receiver.
18595779Sxy150489  */
18605779Sxy150489 s32
18615779Sxy150489 e1000_get_phy_info_igp(struct e1000_hw *hw)
18625779Sxy150489 {
18635779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
18645779Sxy150489 	s32 ret_val;
18655779Sxy150489 	u16 data;
18665779Sxy150489 	bool link;
18675779Sxy150489 
18685779Sxy150489 	DEBUGFUNC("e1000_get_phy_info_igp");
18695779Sxy150489 
18705779Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
18715779Sxy150489 	if (ret_val)
18725779Sxy150489 		goto out;
18735779Sxy150489 
18745779Sxy150489 	if (!link) {
18755779Sxy150489 		DEBUGOUT("Phy info is only valid if link is up\n");
18765779Sxy150489 		ret_val = -E1000_ERR_CONFIG;
18775779Sxy150489 		goto out;
18785779Sxy150489 	}
18795779Sxy150489 
1880*8571SChenlu.Chen@Sun.COM 	phy->polarity_correction = true;
18815779Sxy150489 
18825779Sxy150489 	ret_val = e1000_check_polarity_igp(hw);
18835779Sxy150489 	if (ret_val)
18845779Sxy150489 		goto out;
18855779Sxy150489 
1886*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
18875779Sxy150489 	if (ret_val)
18885779Sxy150489 		goto out;
18895779Sxy150489 
1890*8571SChenlu.Chen@Sun.COM 	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
18915779Sxy150489 
18925779Sxy150489 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
18935779Sxy150489 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
1894*8571SChenlu.Chen@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
18955779Sxy150489 		if (ret_val)
18965779Sxy150489 			goto out;
18975779Sxy150489 
1898*8571SChenlu.Chen@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
18995779Sxy150489 		if (ret_val)
19005779Sxy150489 			goto out;
19015779Sxy150489 
19025779Sxy150489 		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
19035779Sxy150489 		    ? e1000_1000t_rx_status_ok
19045779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
19055779Sxy150489 
19065779Sxy150489 		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
19075779Sxy150489 		    ? e1000_1000t_rx_status_ok
19085779Sxy150489 		    : e1000_1000t_rx_status_not_ok;
19095779Sxy150489 	} else {
19105779Sxy150489 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
19115779Sxy150489 		phy->local_rx = e1000_1000t_rx_status_undefined;
19125779Sxy150489 		phy->remote_rx = e1000_1000t_rx_status_undefined;
19135779Sxy150489 	}
19145779Sxy150489 
19155779Sxy150489 out:
19165779Sxy150489 	return (ret_val);
19175779Sxy150489 }
19185779Sxy150489 
19195779Sxy150489 /*
19205779Sxy150489  * e1000_phy_sw_reset_generic - PHY software reset
19215779Sxy150489  * @hw: pointer to the HW structure
19225779Sxy150489  *
19235779Sxy150489  * Does a software reset of the PHY by reading the PHY control register and
19245779Sxy150489  * setting/write the control register reset bit to the PHY.
19255779Sxy150489  */
19265779Sxy150489 s32
19275779Sxy150489 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
19285779Sxy150489 {
1929*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
19305779Sxy150489 	u16 phy_ctrl;
19315779Sxy150489 
19325779Sxy150489 	DEBUGFUNC("e1000_phy_sw_reset_generic");
19335779Sxy150489 
1934*8571SChenlu.Chen@Sun.COM 	if (!(hw->phy.ops.read_reg))
1935*8571SChenlu.Chen@Sun.COM 		goto out;
1936*8571SChenlu.Chen@Sun.COM 
1937*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
19385779Sxy150489 	if (ret_val)
19395779Sxy150489 		goto out;
19405779Sxy150489 
19415779Sxy150489 	phy_ctrl |= MII_CR_RESET;
1942*8571SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
19435779Sxy150489 	if (ret_val)
19445779Sxy150489 		goto out;
19455779Sxy150489 
19465779Sxy150489 	usec_delay(1);
19475779Sxy150489 
19485779Sxy150489 out:
19495779Sxy150489 	return (ret_val);
19505779Sxy150489 }
19515779Sxy150489 
19525779Sxy150489 /*
19535779Sxy150489  * e1000_phy_hw_reset_generic - PHY hardware reset
19545779Sxy150489  * @hw: pointer to the HW structure
19555779Sxy150489  *
19565779Sxy150489  * Verify the reset block is not blocking us from resetting.  Acquire
19575779Sxy150489  * semaphore (if necessary) and read/set/write the device control reset
19585779Sxy150489  * bit in the PHY.  Wait the appropriate delay time for the device to
1959*8571SChenlu.Chen@Sun.COM  * reset and release the semaphore (if necessary).
19605779Sxy150489  */
19615779Sxy150489 s32
19625779Sxy150489 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
19635779Sxy150489 {
19645779Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
1965*8571SChenlu.Chen@Sun.COM 	s32 ret_val = E1000_SUCCESS;
19665779Sxy150489 	u32 ctrl;
19675779Sxy150489 
19685779Sxy150489 	DEBUGFUNC("e1000_phy_hw_reset_generic");
19695779Sxy150489 
1970*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.check_reset_block(hw);
19715779Sxy150489 	if (ret_val) {
19725779Sxy150489 		ret_val = E1000_SUCCESS;
19735779Sxy150489 		goto out;
19745779Sxy150489 	}
19755779Sxy150489 
1976*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.acquire(hw);
19775779Sxy150489 	if (ret_val)
19785779Sxy150489 		goto out;
19795779Sxy150489 
19805779Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
19815779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
19825779Sxy150489 	E1000_WRITE_FLUSH(hw);
19835779Sxy150489 
19845779Sxy150489 	usec_delay(phy->reset_delay_us);
19855779Sxy150489 
19865779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
19875779Sxy150489 	E1000_WRITE_FLUSH(hw);
19885779Sxy150489 
19895779Sxy150489 	usec_delay(150);
19905779Sxy150489 
1991*8571SChenlu.Chen@Sun.COM 	phy->ops.release(hw);
19925779Sxy150489 
1993*8571SChenlu.Chen@Sun.COM 	ret_val = phy->ops.get_cfg_done(hw);
19945779Sxy150489 
19955779Sxy150489 out:
19965779Sxy150489 	return (ret_val);
19975779Sxy150489 }
19985779Sxy150489 
19995779Sxy150489 /*
20005779Sxy150489  * e1000_get_cfg_done_generic - Generic configuration done
20015779Sxy150489  * @hw: pointer to the HW structure
20025779Sxy150489  *
20035779Sxy150489  * Generic function to wait 10 milli-seconds for configuration to complete
20045779Sxy150489  * and return success.
20055779Sxy150489  */
20065779Sxy150489 s32
20075779Sxy150489 e1000_get_cfg_done_generic(struct e1000_hw *hw)
20085779Sxy150489 {
20095779Sxy150489 	DEBUGFUNC("e1000_get_cfg_done_generic");
2010*8571SChenlu.Chen@Sun.COM 	UNREFERENCED_1PARAMETER(hw);
20115779Sxy150489 
20125779Sxy150489 	msec_delay_irq(10);
20135779Sxy150489 
20145779Sxy150489 	return (E1000_SUCCESS);
20155779Sxy150489 }
20165779Sxy150489 
20175779Sxy150489 /*
20185779Sxy150489  * e1000_phy_init_script_igp3 - Inits the IGP3 PHY
20195779Sxy150489  * @hw: pointer to the HW structure
20205779Sxy150489  *
20215779Sxy150489  * Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
20225779Sxy150489  */
20235779Sxy150489 s32
20245779Sxy150489 e1000_phy_init_script_igp3(struct e1000_hw *hw)
20255779Sxy150489 {
20265779Sxy150489 	DEBUGOUT("Running IGP 3 PHY init script\n");
20275779Sxy150489 
20285779Sxy150489 	/* PHY init IGP 3 */
20295779Sxy150489 	/* Enable rise/fall, 10-mode work in class-A */
2030*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
20315779Sxy150489 	/* Remove all caps from Replica path filter */
2032*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
20335779Sxy150489 	/* Bias trimming for ADC, AFE and Driver (Default) */
2034*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
20355779Sxy150489 	/* Increase Hybrid poly bias */
2036*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
2037*8571SChenlu.Chen@Sun.COM 	/* Add 4% to Tx amplitude in Gig mode */
2038*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
20395779Sxy150489 	/* Disable trimming (TTT) */
2040*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
20415779Sxy150489 	/* Poly DC correction to 94.6% + 2% for all channels */
2042*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
20435779Sxy150489 	/* ABS DC correction to 95.9% */
2044*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
20455779Sxy150489 	/* BG temp curve trim */
2046*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
20475779Sxy150489 	/* Increasing ADC OPAMP stage 1 currents to max */
2048*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
20495779Sxy150489 	/* Force 1000 ( required for enabling PHY regs configuration) */
2050*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
20515779Sxy150489 	/* Set upd_freq to 6 */
2052*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
20535779Sxy150489 	/* Disable NPDFE */
2054*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
20555779Sxy150489 	/* Disable adaptive fixed FFE (Default) */
2056*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
20575779Sxy150489 	/* Enable FFE hysteresis */
2058*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
20595779Sxy150489 	/* Fixed FFE for short cable lengths */
2060*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
20615779Sxy150489 	/* Fixed FFE for medium cable lengths */
2062*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
20635779Sxy150489 	/* Fixed FFE for long cable lengths */
2064*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
20655779Sxy150489 	/* Enable Adaptive Clip Threshold */
2066*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
20675779Sxy150489 	/* AHT reset limit to 1 */
2068*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
20695779Sxy150489 	/* Set AHT master delay to 127 msec */
2070*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
20715779Sxy150489 	/* Set scan bits for AHT */
2072*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
20735779Sxy150489 	/* Set AHT Preset bits */
2074*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
20755779Sxy150489 	/* Change integ_factor of channel A to 3 */
2076*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
20775779Sxy150489 	/* Change prop_factor of channels BCD to 8 */
2078*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
20795779Sxy150489 	/* Change cg_icount + enable integbp for channels BCD */
2080*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
20815779Sxy150489 	/*
20825779Sxy150489 	 * Change cg_icount + enable integbp + change prop_factor_master
20835779Sxy150489 	 * to 8 for channel A
20845779Sxy150489 	 */
2085*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
20865779Sxy150489 	/* Disable AHT in Slave mode on channel A */
2087*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
20885779Sxy150489 	/*
20895779Sxy150489 	 * Enable LPLU and disable AN to 1000 in non-D0a states,
20905779Sxy150489 	 * Enable SPD+B2B
20915779Sxy150489 	 */
2092*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
20935779Sxy150489 	/* Enable restart AN on an1000_dis change */
2094*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
20955779Sxy150489 	/* Enable wh_fifo read clock in 10/100 modes */
2096*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
20975779Sxy150489 	/* Restart AN, Speed selection is 1000 */
2098*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
20995779Sxy150489 
21005779Sxy150489 	return (E1000_SUCCESS);
21015779Sxy150489 }
21025779Sxy150489 
21035779Sxy150489 /*
21045779Sxy150489  * e1000_get_phy_type_from_id - Get PHY type from id
21055779Sxy150489  * @phy_id: phy_id read from the phy
21065779Sxy150489  *
21075779Sxy150489  * Returns the phy type from the id.
21085779Sxy150489  */
2109*8571SChenlu.Chen@Sun.COM enum e1000_phy_type
21105779Sxy150489 e1000_get_phy_type_from_id(u32 phy_id)
21115779Sxy150489 {
2112*8571SChenlu.Chen@Sun.COM 	enum e1000_phy_type phy_type = e1000_phy_unknown;
21135779Sxy150489 
21145779Sxy150489 	switch (phy_id)	{
21155779Sxy150489 	case M88E1000_I_PHY_ID:
21165779Sxy150489 	case M88E1000_E_PHY_ID:
21175779Sxy150489 	case M88E1111_I_PHY_ID:
21185779Sxy150489 	case M88E1011_I_PHY_ID:
21195779Sxy150489 		phy_type = e1000_phy_m88;
21205779Sxy150489 		break;
21215779Sxy150489 	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
21225779Sxy150489 		phy_type = e1000_phy_igp_2;
21235779Sxy150489 		break;
21245779Sxy150489 	case GG82563_E_PHY_ID:
21255779Sxy150489 		phy_type = e1000_phy_gg82563;
21265779Sxy150489 		break;
21275779Sxy150489 	case IGP03E1000_E_PHY_ID:
21285779Sxy150489 		phy_type = e1000_phy_igp_3;
21295779Sxy150489 		break;
21305779Sxy150489 	case IFE_E_PHY_ID:
21315779Sxy150489 	case IFE_PLUS_E_PHY_ID:
21325779Sxy150489 	case IFE_C_E_PHY_ID:
21335779Sxy150489 		phy_type = e1000_phy_ife;
21345779Sxy150489 		break;
21355779Sxy150489 	default:
21365779Sxy150489 		phy_type = e1000_phy_unknown;
21375779Sxy150489 		break;
21385779Sxy150489 	}
21395779Sxy150489 	return (phy_type);
21405779Sxy150489 }
21415779Sxy150489 
21425779Sxy150489 /*
21435779Sxy150489  * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
21445779Sxy150489  * @hw: pointer to the HW structure
21455779Sxy150489  *
21465779Sxy150489  * In the case of a PHY power down to save power, or to turn off link during a
21475779Sxy150489  * driver unload, or wake on lan is not enabled, restore the link to previous
21485779Sxy150489  * settings.
21495779Sxy150489  */
21505779Sxy150489 void
21515779Sxy150489 e1000_power_up_phy_copper(struct e1000_hw *hw)
21525779Sxy150489 {
21535779Sxy150489 	u16 mii_reg = 0;
21545779Sxy150489 
21555779Sxy150489 	/* The PHY will retain its settings across a power down/up cycle */
2156*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
21575779Sxy150489 	mii_reg &= ~MII_CR_POWER_DOWN;
2158*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
21595779Sxy150489 }
21605779Sxy150489 
21615779Sxy150489 /*
21625779Sxy150489  * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
21635779Sxy150489  * @hw: pointer to the HW structure
21645779Sxy150489  *
21655779Sxy150489  * In the case of a PHY power down to save power, or to turn off link during a
21665779Sxy150489  * driver unload, or wake on lan is not enabled, restore the link to previous
21675779Sxy150489  * settings.
21685779Sxy150489  */
21695779Sxy150489 void
21705779Sxy150489 e1000_power_down_phy_copper(struct e1000_hw *hw)
21715779Sxy150489 {
21725779Sxy150489 	u16 mii_reg = 0;
21735779Sxy150489 
21745779Sxy150489 	/* The PHY will retain its settings across a power down/up cycle */
2175*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
21765779Sxy150489 	mii_reg |= MII_CR_POWER_DOWN;
2177*8571SChenlu.Chen@Sun.COM 	(void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
21785779Sxy150489 	msec_delay(1);
21795779Sxy150489 }
2180