xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000_phy.c (revision 10680:45bda3640f27)
14919Sxy150489 /*
24919Sxy150489  * This file is provided under a CDDLv1 license.  When using or
34919Sxy150489  * redistributing this file, you may do so under this license.
44919Sxy150489  * In redistributing this file this license must be included
54919Sxy150489  * and no other modification of this header file is permitted.
64919Sxy150489  *
74919Sxy150489  * CDDL LICENSE SUMMARY
84919Sxy150489  *
98479SChenlu.Chen@Sun.COM  * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
104919Sxy150489  *
114919Sxy150489  * The contents of this file are subject to the terms of Version
124919Sxy150489  * 1.0 of the Common Development and Distribution License (the "License").
134919Sxy150489  *
144919Sxy150489  * You should have received a copy of the License with this software.
154919Sxy150489  * You can obtain a copy of the License at
164919Sxy150489  *	http://www.opensolaris.org/os/licensing.
174919Sxy150489  * See the License for the specific language governing permissions
184919Sxy150489  * and limitations under the License.
194919Sxy150489  */
204919Sxy150489 
214919Sxy150489 /*
228479SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
234919Sxy150489  * Use is subject to license terms of the CDDLv1.
244919Sxy150489  */
254919Sxy150489 
264919Sxy150489 /*
27*10680SMin.Xu@Sun.COM  * IntelVersion: 1.143 v3-1-3_2009-8-20
284919Sxy150489  */
294919Sxy150489 #include "e1000_api.h"
304919Sxy150489 
314919Sxy150489 static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
328479SChenlu.Chen@Sun.COM static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
338479SChenlu.Chen@Sun.COM     u16 *data, bool read);
344919Sxy150489 
35*10680SMin.Xu@Sun.COM static u32 e1000_get_phy_addr_for_hv_page(u32 page);
36*10680SMin.Xu@Sun.COM static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
37*10680SMin.Xu@Sun.COM     u16 *data, bool read);
38*10680SMin.Xu@Sun.COM 
394919Sxy150489 /* Cable length tables */
404919Sxy150489 static const u16 e1000_m88_cable_length_table[] =
414919Sxy150489 	{0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED};
424919Sxy150489 
434919Sxy150489 #define	M88E1000_CABLE_LENGTH_TABLE_SIZE \
444919Sxy150489 	(sizeof (e1000_m88_cable_length_table) / \
454919Sxy150489 	sizeof (e1000_m88_cable_length_table[0]))
464919Sxy150489 
474919Sxy150489 static const u16 e1000_igp_2_cable_length_table[] =
484919Sxy150489 	{0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
494919Sxy150489 	0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
504919Sxy150489 	6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
514919Sxy150489 	21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
524919Sxy150489 	40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
534919Sxy150489 	60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
544919Sxy150489 	83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
554919Sxy150489 	104, 109, 114, 118, 121, 124};
564919Sxy150489 
574919Sxy150489 #define	IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
584919Sxy150489 	(sizeof (e1000_igp_2_cable_length_table) / \
594919Sxy150489 	sizeof (e1000_igp_2_cable_length_table[0]))
604919Sxy150489 
614919Sxy150489 /*
626735Scc210113  * e1000_init_phy_ops_generic - Initialize PHY function pointers
636735Scc210113  * @hw: pointer to the HW structure
646735Scc210113  *
656735Scc210113  * Setups up the function pointers to no-op functions
666735Scc210113  */
676735Scc210113 void
686735Scc210113 e1000_init_phy_ops_generic(struct e1000_hw *hw)
696735Scc210113 {
706735Scc210113 	struct e1000_phy_info *phy = &hw->phy;
716735Scc210113 	DEBUGFUNC("e1000_init_phy_ops_generic");
726735Scc210113 
736735Scc210113 	/* Initialize function pointers */
746735Scc210113 	phy->ops.init_params = e1000_null_ops_generic;
756735Scc210113 	phy->ops.acquire = e1000_null_ops_generic;
766735Scc210113 	phy->ops.check_polarity = e1000_null_ops_generic;
776735Scc210113 	phy->ops.check_reset_block = e1000_null_ops_generic;
786735Scc210113 	phy->ops.commit = e1000_null_ops_generic;
796735Scc210113 	phy->ops.force_speed_duplex = e1000_null_ops_generic;
806735Scc210113 	phy->ops.get_cfg_done = e1000_null_ops_generic;
816735Scc210113 	phy->ops.get_cable_length = e1000_null_ops_generic;
826735Scc210113 	phy->ops.get_info = e1000_null_ops_generic;
836735Scc210113 	phy->ops.read_reg = e1000_null_read_reg;
846735Scc210113 	phy->ops.release = e1000_null_phy_generic;
856735Scc210113 	phy->ops.reset = e1000_null_ops_generic;
866735Scc210113 	phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
876735Scc210113 	phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
886735Scc210113 	phy->ops.write_reg = e1000_null_write_reg;
896735Scc210113 	phy->ops.power_up = e1000_null_phy_generic;
906735Scc210113 	phy->ops.power_down = e1000_null_phy_generic;
918479SChenlu.Chen@Sun.COM 	phy->ops.cfg_on_link_up = e1000_null_ops_generic;
926735Scc210113 }
936735Scc210113 
946735Scc210113 /*
956735Scc210113  * e1000_null_read_reg - No-op function, return 0
966735Scc210113  * @hw: pointer to the HW structure
976735Scc210113  */
986735Scc210113 s32
996735Scc210113 e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data)
1006735Scc210113 {
1016735Scc210113 	DEBUGFUNC("e1000_null_read_reg");
1026735Scc210113 	UNREFERENCED_3PARAMETER(hw, offset, data);
1036735Scc210113 	return (E1000_SUCCESS);
1046735Scc210113 }
1056735Scc210113 
1066735Scc210113 /*
1076735Scc210113  * e1000_null_phy_generic - No-op function, return void
1086735Scc210113  * @hw: pointer to the HW structure
1096735Scc210113  */
1106735Scc210113 void
1116735Scc210113 e1000_null_phy_generic(struct e1000_hw *hw)
1126735Scc210113 {
1136735Scc210113 	DEBUGFUNC("e1000_null_phy_generic");
1146735Scc210113 	UNREFERENCED_1PARAMETER(hw);
1156735Scc210113 }
1166735Scc210113 
1176735Scc210113 /*
1186735Scc210113  * e1000_null_lplu_state - No-op function, return 0
1196735Scc210113  * @hw: pointer to the HW structure
1206735Scc210113  */
1216735Scc210113 s32
1226735Scc210113 e1000_null_lplu_state(struct e1000_hw *hw, bool active)
1236735Scc210113 {
1246735Scc210113 	DEBUGFUNC("e1000_null_lplu_state");
1256735Scc210113 	UNREFERENCED_2PARAMETER(hw, active);
1266735Scc210113 	return (E1000_SUCCESS);
1276735Scc210113 }
1286735Scc210113 
1296735Scc210113 /*
1306735Scc210113  * e1000_null_write_reg - No-op function, return 0
1316735Scc210113  * @hw: pointer to the HW structure
1326735Scc210113  */
1336735Scc210113 s32
1346735Scc210113 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
1356735Scc210113 {
1366735Scc210113 	DEBUGFUNC("e1000_null_write_reg");
1376735Scc210113 	UNREFERENCED_3PARAMETER(hw, offset, data);
1386735Scc210113 	return (E1000_SUCCESS);
1396735Scc210113 }
1406735Scc210113 
1416735Scc210113 /*
1424919Sxy150489  * e1000_check_reset_block_generic - Check if PHY reset is blocked
1434919Sxy150489  * @hw: pointer to the HW structure
1444919Sxy150489  *
1454919Sxy150489  * Read the PHY management control register and check whether a PHY reset
1464919Sxy150489  * is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
1474919Sxy150489  * return E1000_BLK_PHY_RESET (12).
1484919Sxy150489  */
1494919Sxy150489 s32
1504919Sxy150489 e1000_check_reset_block_generic(struct e1000_hw *hw)
1514919Sxy150489 {
1524919Sxy150489 	u32 manc;
1534919Sxy150489 
1544919Sxy150489 	DEBUGFUNC("e1000_check_reset_block");
1554919Sxy150489 
1564919Sxy150489 	manc = E1000_READ_REG(hw, E1000_MANC);
1574919Sxy150489 
1584919Sxy150489 	return ((manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
1594919Sxy150489 	    E1000_BLK_PHY_RESET : E1000_SUCCESS);
1604919Sxy150489 }
1614919Sxy150489 
1624919Sxy150489 /*
1634919Sxy150489  * e1000_get_phy_id - Retrieve the PHY ID and revision
1644919Sxy150489  * @hw: pointer to the HW structure
1654919Sxy150489  *
1664919Sxy150489  * Reads the PHY registers and stores the PHY ID and possibly the PHY
1674919Sxy150489  * revision in the hardware structure.
1684919Sxy150489  */
1694919Sxy150489 s32
1704919Sxy150489 e1000_get_phy_id(struct e1000_hw *hw)
1714919Sxy150489 {
1724919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
1734919Sxy150489 	s32 ret_val = E1000_SUCCESS;
1744919Sxy150489 	u16 phy_id;
175*10680SMin.Xu@Sun.COM 	u16 retry_count = 0;
1764919Sxy150489 
1774919Sxy150489 	DEBUGFUNC("e1000_get_phy_id");
1784919Sxy150489 
1796735Scc210113 	if (!(phy->ops.read_reg))
1806735Scc210113 		goto out;
1816735Scc210113 
182*10680SMin.Xu@Sun.COM 	while (retry_count < 2) {
183*10680SMin.Xu@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
184*10680SMin.Xu@Sun.COM 		if (ret_val)
185*10680SMin.Xu@Sun.COM 			goto out;
186*10680SMin.Xu@Sun.COM 
187*10680SMin.Xu@Sun.COM 		phy->id = (u32)(phy_id << 16);
188*10680SMin.Xu@Sun.COM 		usec_delay(20);
189*10680SMin.Xu@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
190*10680SMin.Xu@Sun.COM 		if (ret_val)
191*10680SMin.Xu@Sun.COM 			goto out;
192*10680SMin.Xu@Sun.COM 
193*10680SMin.Xu@Sun.COM 		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
194*10680SMin.Xu@Sun.COM 		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
195*10680SMin.Xu@Sun.COM 
196*10680SMin.Xu@Sun.COM 		if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
197*10680SMin.Xu@Sun.COM 			goto out;
198*10680SMin.Xu@Sun.COM 
199*10680SMin.Xu@Sun.COM 		/*
200*10680SMin.Xu@Sun.COM 		 * If the PHY ID is still unknown, we may have an 82577 without
201*10680SMin.Xu@Sun.COM 		 * link. We will try again after setting Slow MDIC mode. No
202*10680SMin.Xu@Sun.COM 		 * harm in trying again in this case since the PHY ID is
203*10680SMin.Xu@Sun.COM 		 * unknown at this point anyway
204*10680SMin.Xu@Sun.COM 		 */
205*10680SMin.Xu@Sun.COM 		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
206*10680SMin.Xu@Sun.COM 		if (ret_val)
207*10680SMin.Xu@Sun.COM 			goto out;
208*10680SMin.Xu@Sun.COM 
209*10680SMin.Xu@Sun.COM 		retry_count++;
210*10680SMin.Xu@Sun.COM 	}
2114919Sxy150489 out:
212*10680SMin.Xu@Sun.COM 	/* Revert to MDIO fast mode, if applicable */
213*10680SMin.Xu@Sun.COM 	if (retry_count)
214*10680SMin.Xu@Sun.COM 		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
215*10680SMin.Xu@Sun.COM 
2164919Sxy150489 	return (ret_val);
2174919Sxy150489 }
2184919Sxy150489 
2194919Sxy150489 /*
2204919Sxy150489  * e1000_phy_reset_dsp_generic - Reset PHY DSP
2214919Sxy150489  * @hw: pointer to the HW structure
2224919Sxy150489  *
2234919Sxy150489  * Reset the digital signal processor.
2244919Sxy150489  */
2254919Sxy150489 s32
2264919Sxy150489 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
2274919Sxy150489 {
2286735Scc210113 	s32 ret_val = E1000_SUCCESS;
2294919Sxy150489 
2304919Sxy150489 	DEBUGFUNC("e1000_phy_reset_dsp_generic");
2314919Sxy150489 
2326735Scc210113 	if (!(hw->phy.ops.write_reg))
2336735Scc210113 		goto out;
2346735Scc210113 
2356735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
2364919Sxy150489 	if (ret_val)
2374919Sxy150489 		goto out;
2384919Sxy150489 
2396735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
2404919Sxy150489 
2414919Sxy150489 out:
2424919Sxy150489 	return (ret_val);
2434919Sxy150489 }
2444919Sxy150489 
2454919Sxy150489 /*
2464919Sxy150489  * e1000_read_phy_reg_mdic - Read MDI control register
2474919Sxy150489  * @hw: pointer to the HW structure
2484919Sxy150489  * @offset: register offset to be read
2494919Sxy150489  * @data: pointer to the read data
2504919Sxy150489  *
2516735Scc210113  * Reads the MDI control register in the PHY at offset and stores the
2524919Sxy150489  * information read to data.
2534919Sxy150489  */
2546735Scc210113 s32
2554919Sxy150489 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
2564919Sxy150489 {
2574919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
2584919Sxy150489 	u32 i, mdic = 0;
2594919Sxy150489 	s32 ret_val = E1000_SUCCESS;
2604919Sxy150489 
2614919Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_mdic");
2624919Sxy150489 
2634919Sxy150489 	/*
2644919Sxy150489 	 * Set up Op-code, Phy Address, and register offset in the MDI Control
2654919Sxy150489 	 * register.  The MAC will take care of interfacing with the PHY to
2664919Sxy150489 	 * retrieve the desired data.
2674919Sxy150489 	 */
2684919Sxy150489 	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
2694919Sxy150489 	    (phy->addr << E1000_MDIC_PHY_SHIFT) |
2704919Sxy150489 	    (E1000_MDIC_OP_READ));
2714919Sxy150489 
2724919Sxy150489 	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
2734919Sxy150489 
2746735Scc210113 	/*
2756735Scc210113 	 * Poll the ready bit to see if the MDI read completed
2766735Scc210113 	 * Increasing the time out as testing showed failures with
2776735Scc210113 	 * the lower time out
2786735Scc210113 	 */
2796735Scc210113 	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
2804919Sxy150489 		usec_delay(50);
2814919Sxy150489 		mdic = E1000_READ_REG(hw, E1000_MDIC);
2824919Sxy150489 		if (mdic & E1000_MDIC_READY)
2834919Sxy150489 			break;
2844919Sxy150489 	}
2854919Sxy150489 	if (!(mdic & E1000_MDIC_READY)) {
2864919Sxy150489 		DEBUGOUT("MDI Read did not complete\n");
2874919Sxy150489 		ret_val = -E1000_ERR_PHY;
2884919Sxy150489 		goto out;
2894919Sxy150489 	}
2904919Sxy150489 	if (mdic & E1000_MDIC_ERROR) {
2914919Sxy150489 		DEBUGOUT("MDI Error\n");
2924919Sxy150489 		ret_val = -E1000_ERR_PHY;
2934919Sxy150489 		goto out;
2944919Sxy150489 	}
2954919Sxy150489 	*data = (u16)mdic;
2964919Sxy150489 
2974919Sxy150489 out:
2984919Sxy150489 	return (ret_val);
2994919Sxy150489 }
3004919Sxy150489 
3014919Sxy150489 /*
3024919Sxy150489  * e1000_write_phy_reg_mdic - Write MDI control register
3034919Sxy150489  * @hw: pointer to the HW structure
3044919Sxy150489  * @offset: register offset to write to
3054919Sxy150489  * @data: data to write to register at offset
3064919Sxy150489  *
3074919Sxy150489  * Writes data to MDI control register in the PHY at offset.
3084919Sxy150489  */
3096735Scc210113 s32
3104919Sxy150489 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
3114919Sxy150489 {
3124919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
3134919Sxy150489 	u32 i, mdic = 0;
3144919Sxy150489 	s32 ret_val = E1000_SUCCESS;
3154919Sxy150489 
3164919Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_mdic");
3174919Sxy150489 
3184919Sxy150489 	/*
3194919Sxy150489 	 * Set up Op-code, Phy Address, and register offset in the MDI Control
3204919Sxy150489 	 * register.  The MAC will take care of interfacing with the PHY to
3214919Sxy150489 	 * retrieve the desired data.
3224919Sxy150489 	 */
3234919Sxy150489 	mdic = (((u32)data) |
3244919Sxy150489 	    (offset << E1000_MDIC_REG_SHIFT) |
3254919Sxy150489 	    (phy->addr << E1000_MDIC_PHY_SHIFT) |
3264919Sxy150489 	    (E1000_MDIC_OP_WRITE));
3274919Sxy150489 
3284919Sxy150489 	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
3294919Sxy150489 
3306735Scc210113 	/*
3316735Scc210113 	 * Poll the ready bit to see if the MDI read completed
3326735Scc210113 	 * Increasing the time out as testing showed failures with
3336735Scc210113 	 * the lower time out
3346735Scc210113 	 */
3356735Scc210113 	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
3366735Scc210113 		usec_delay(50);
3374919Sxy150489 		mdic = E1000_READ_REG(hw, E1000_MDIC);
3384919Sxy150489 		if (mdic & E1000_MDIC_READY)
3394919Sxy150489 			break;
3404919Sxy150489 	}
3414919Sxy150489 	if (!(mdic & E1000_MDIC_READY)) {
3424919Sxy150489 		DEBUGOUT("MDI Write did not complete\n");
3434919Sxy150489 		ret_val = -E1000_ERR_PHY;
3444919Sxy150489 		goto out;
3454919Sxy150489 	}
3466735Scc210113 	if (mdic & E1000_MDIC_ERROR) {
3476735Scc210113 		DEBUGOUT("MDI Error\n");
3486735Scc210113 		ret_val = -E1000_ERR_PHY;
3496735Scc210113 		goto out;
3506735Scc210113 	}
3514919Sxy150489 
3524919Sxy150489 out:
3534919Sxy150489 	return (ret_val);
3544919Sxy150489 }
3554919Sxy150489 
3564919Sxy150489 /*
3574919Sxy150489  * e1000_read_phy_reg_m88 - Read m88 PHY register
3584919Sxy150489  * @hw: pointer to the HW structure
3594919Sxy150489  * @offset: register offset to be read
3604919Sxy150489  * @data: pointer to the read data
3614919Sxy150489  *
3624919Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
3634919Sxy150489  * and storing the retrieved information in data.  Release any acquired
3644919Sxy150489  * semaphores before exiting.
3654919Sxy150489  */
3664919Sxy150489 s32
3674919Sxy150489 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
3684919Sxy150489 {
3696735Scc210113 	s32 ret_val = E1000_SUCCESS;
3704919Sxy150489 
3714919Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_m88");
3724919Sxy150489 
3736735Scc210113 	if (!(hw->phy.ops.acquire))
3746735Scc210113 		goto out;
3756735Scc210113 
3766735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
3774919Sxy150489 	if (ret_val)
3784919Sxy150489 		goto out;
3794919Sxy150489 
3804919Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw,
3814919Sxy150489 	    MAX_PHY_REG_ADDRESS & offset,
3824919Sxy150489 	    data);
3834919Sxy150489 
3846735Scc210113 	hw->phy.ops.release(hw);
3854919Sxy150489 
3864919Sxy150489 out:
3874919Sxy150489 	return (ret_val);
3884919Sxy150489 }
3894919Sxy150489 
3904919Sxy150489 /*
3914919Sxy150489  * e1000_write_phy_reg_m88 - Write m88 PHY register
3924919Sxy150489  * @hw: pointer to the HW structure
3934919Sxy150489  * @offset: register offset to write to
3944919Sxy150489  * @data: data to write at register offset
3954919Sxy150489  *
3964919Sxy150489  * Acquires semaphore, if necessary, then writes the data to PHY register
3974919Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
3984919Sxy150489  */
3994919Sxy150489 s32
4004919Sxy150489 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
4014919Sxy150489 {
4026735Scc210113 	s32 ret_val = E1000_SUCCESS;
4034919Sxy150489 
4044919Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_m88");
4054919Sxy150489 
4066735Scc210113 	if (!(hw->phy.ops.acquire))
4076735Scc210113 		goto out;
4086735Scc210113 
4096735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
4104919Sxy150489 	if (ret_val)
4114919Sxy150489 		goto out;
4124919Sxy150489 
4134919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
4144919Sxy150489 	    MAX_PHY_REG_ADDRESS & offset,
4154919Sxy150489 	    data);
4164919Sxy150489 
4176735Scc210113 	hw->phy.ops.release(hw);
4184919Sxy150489 
4194919Sxy150489 out:
4204919Sxy150489 	return (ret_val);
4214919Sxy150489 }
4224919Sxy150489 
4234919Sxy150489 /*
4244919Sxy150489  * e1000_read_phy_reg_igp - Read igp PHY register
4254919Sxy150489  * @hw: pointer to the HW structure
4264919Sxy150489  * @offset: register offset to be read
4274919Sxy150489  * @data: pointer to the read data
4284919Sxy150489  *
4294919Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
4304919Sxy150489  * and storing the retrieved information in data.  Release any acquired
4314919Sxy150489  * semaphores before exiting.
4324919Sxy150489  */
4334919Sxy150489 s32
4344919Sxy150489 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
4354919Sxy150489 {
4366735Scc210113 	s32 ret_val = E1000_SUCCESS;
4374919Sxy150489 
4384919Sxy150489 	DEBUGFUNC("e1000_read_phy_reg_igp");
4394919Sxy150489 
4406735Scc210113 	if (!(hw->phy.ops.acquire))
4416735Scc210113 		goto out;
4426735Scc210113 
4436735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
4444919Sxy150489 	if (ret_val)
4454919Sxy150489 		goto out;
4464919Sxy150489 
4474919Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
4484919Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw,
4494919Sxy150489 		    IGP01E1000_PHY_PAGE_SELECT,
4504919Sxy150489 		    (u16)offset);
4514919Sxy150489 		if (ret_val) {
4526735Scc210113 			hw->phy.ops.release(hw);
4534919Sxy150489 			goto out;
4544919Sxy150489 		}
4554919Sxy150489 	}
4564919Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw,
4574919Sxy150489 	    MAX_PHY_REG_ADDRESS & offset,
4584919Sxy150489 	    data);
4594919Sxy150489 
4606735Scc210113 	hw->phy.ops.release(hw);
4614919Sxy150489 
4624919Sxy150489 out:
4634919Sxy150489 	return (ret_val);
4644919Sxy150489 }
4654919Sxy150489 
4664919Sxy150489 /*
4674919Sxy150489  * e1000_write_phy_reg_igp - Write igp PHY register
4684919Sxy150489  * @hw: pointer to the HW structure
4694919Sxy150489  * @offset: register offset to write to
4704919Sxy150489  * @data: data to write at register offset
4714919Sxy150489  *
4724919Sxy150489  * Acquires semaphore, if necessary, then writes the data to PHY register
4734919Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
4744919Sxy150489  */
4754919Sxy150489 s32
4764919Sxy150489 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
4774919Sxy150489 {
4786735Scc210113 	s32 ret_val = E1000_SUCCESS;
4794919Sxy150489 
4804919Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_igp");
4814919Sxy150489 
4826735Scc210113 	if (!(hw->phy.ops.acquire))
4836735Scc210113 		goto out;
4846735Scc210113 
4856735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
4864919Sxy150489 	if (ret_val)
4874919Sxy150489 		goto out;
4884919Sxy150489 
4894919Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
4904919Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw,
4914919Sxy150489 		    IGP01E1000_PHY_PAGE_SELECT,
4924919Sxy150489 		    (u16)offset);
4934919Sxy150489 		if (ret_val) {
4946735Scc210113 			hw->phy.ops.release(hw);
4954919Sxy150489 			goto out;
4964919Sxy150489 		}
4974919Sxy150489 	}
4984919Sxy150489 
4994919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
5004919Sxy150489 	    MAX_PHY_REG_ADDRESS & offset,
5014919Sxy150489 	    data);
5024919Sxy150489 
5036735Scc210113 	hw->phy.ops.release(hw);
5044919Sxy150489 
5054919Sxy150489 out:
5064919Sxy150489 	return (ret_val);
5074919Sxy150489 }
5084919Sxy150489 
5094919Sxy150489 /*
5104919Sxy150489  * e1000_read_kmrn_reg_generic - Read kumeran register
5114919Sxy150489  * @hw: pointer to the HW structure
5124919Sxy150489  * @offset: register offset to be read
5134919Sxy150489  * @data: pointer to the read data
5144919Sxy150489  *
5154919Sxy150489  * Acquires semaphore, if necessary.  Then reads the PHY register at offset
5164919Sxy150489  * using the kumeran interface.  The information retrieved is stored in data.
5174919Sxy150489  * Release any acquired semaphores before exiting.
5184919Sxy150489  */
5194919Sxy150489 s32
5204919Sxy150489 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
5214919Sxy150489 {
5224919Sxy150489 	u32 kmrnctrlsta;
5236735Scc210113 	s32 ret_val = E1000_SUCCESS;
5244919Sxy150489 
5254919Sxy150489 	DEBUGFUNC("e1000_read_kmrn_reg_generic");
5264919Sxy150489 
5276735Scc210113 	if (!(hw->phy.ops.acquire))
5286735Scc210113 		goto out;
5296735Scc210113 
5306735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
5314919Sxy150489 	if (ret_val)
5324919Sxy150489 		goto out;
5334919Sxy150489 
5344919Sxy150489 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
5354919Sxy150489 	    E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
5364919Sxy150489 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
5374919Sxy150489 
5384919Sxy150489 	usec_delay(2);
5394919Sxy150489 
5404919Sxy150489 	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
5414919Sxy150489 	*data = (u16)kmrnctrlsta;
5424919Sxy150489 
5436735Scc210113 	hw->phy.ops.release(hw);
5444919Sxy150489 
5454919Sxy150489 out:
5464919Sxy150489 	return (ret_val);
5474919Sxy150489 }
5484919Sxy150489 
5494919Sxy150489 /*
5504919Sxy150489  * e1000_write_kmrn_reg_generic - Write kumeran register
5514919Sxy150489  * @hw: pointer to the HW structure
5524919Sxy150489  * @offset: register offset to write to
5534919Sxy150489  * @data: data to write at register offset
5544919Sxy150489  *
5554919Sxy150489  * Acquires semaphore, if necessary.  Then write the data to PHY register
5564919Sxy150489  * at the offset using the kumeran interface.  Release any acquired semaphores
5574919Sxy150489  * before exiting.
5584919Sxy150489  */
5594919Sxy150489 s32
5604919Sxy150489 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
5614919Sxy150489 {
5624919Sxy150489 	u32 kmrnctrlsta;
5636735Scc210113 	s32 ret_val = E1000_SUCCESS;
5644919Sxy150489 
5654919Sxy150489 	DEBUGFUNC("e1000_write_kmrn_reg_generic");
5664919Sxy150489 
5676735Scc210113 	if (!(hw->phy.ops.acquire))
5686735Scc210113 		goto out;
5696735Scc210113 
5706735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
5714919Sxy150489 	if (ret_val)
5724919Sxy150489 		goto out;
5734919Sxy150489 
5744919Sxy150489 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
5754919Sxy150489 	    E1000_KMRNCTRLSTA_OFFSET) | data;
5764919Sxy150489 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
5774919Sxy150489 
5784919Sxy150489 	usec_delay(2);
5796735Scc210113 	hw->phy.ops.release(hw);
5804919Sxy150489 
5814919Sxy150489 out:
5824919Sxy150489 	return (ret_val);
5834919Sxy150489 }
5844919Sxy150489 
5854919Sxy150489 /*
586*10680SMin.Xu@Sun.COM  * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
587*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
588*10680SMin.Xu@Sun.COM  *
589*10680SMin.Xu@Sun.COM  * Sets up Carrier-sense on Transmit and downshift values.
590*10680SMin.Xu@Sun.COM  */
591*10680SMin.Xu@Sun.COM s32
592*10680SMin.Xu@Sun.COM e1000_copper_link_setup_82577(struct e1000_hw *hw)
593*10680SMin.Xu@Sun.COM {
594*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
595*10680SMin.Xu@Sun.COM 	s32 ret_val;
596*10680SMin.Xu@Sun.COM 	u16 phy_data;
597*10680SMin.Xu@Sun.COM 
598*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_copper_link_setup_82577");
599*10680SMin.Xu@Sun.COM 
600*10680SMin.Xu@Sun.COM 	if (phy->reset_disable) {
601*10680SMin.Xu@Sun.COM 		ret_val = E1000_SUCCESS;
602*10680SMin.Xu@Sun.COM 		goto out;
603*10680SMin.Xu@Sun.COM 	}
604*10680SMin.Xu@Sun.COM 
605*10680SMin.Xu@Sun.COM 	/* Enable CRS on TX. This must be set for half-duplex operation. */
606*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data);
607*10680SMin.Xu@Sun.COM 	if (ret_val)
608*10680SMin.Xu@Sun.COM 		goto out;
609*10680SMin.Xu@Sun.COM 
610*10680SMin.Xu@Sun.COM 	phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
611*10680SMin.Xu@Sun.COM 
612*10680SMin.Xu@Sun.COM 	/* Enable downshift */
613*10680SMin.Xu@Sun.COM 	phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
614*10680SMin.Xu@Sun.COM 
615*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data);
616*10680SMin.Xu@Sun.COM 	if (ret_val)
617*10680SMin.Xu@Sun.COM 		goto out;
618*10680SMin.Xu@Sun.COM 
619*10680SMin.Xu@Sun.COM 	/* Set number of link attempts before downshift */
620*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data);
621*10680SMin.Xu@Sun.COM 	if (ret_val)
622*10680SMin.Xu@Sun.COM 		goto out;
623*10680SMin.Xu@Sun.COM 	phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK;
624*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data);
625*10680SMin.Xu@Sun.COM 
626*10680SMin.Xu@Sun.COM out:
627*10680SMin.Xu@Sun.COM 	return (ret_val);
628*10680SMin.Xu@Sun.COM }
629*10680SMin.Xu@Sun.COM 
630*10680SMin.Xu@Sun.COM /*
6314919Sxy150489  * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
6324919Sxy150489  * @hw: pointer to the HW structure
6334919Sxy150489  *
6344919Sxy150489  * Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
6354919Sxy150489  * and downshift values are set also.
6364919Sxy150489  */
6374919Sxy150489 s32
6384919Sxy150489 e1000_copper_link_setup_m88(struct e1000_hw *hw)
6394919Sxy150489 {
6404919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
6414919Sxy150489 	s32 ret_val;
6424919Sxy150489 	u16 phy_data;
6434919Sxy150489 
6444919Sxy150489 	DEBUGFUNC("e1000_copper_link_setup_m88");
6454919Sxy150489 
6464919Sxy150489 	if (phy->reset_disable) {
6474919Sxy150489 		ret_val = E1000_SUCCESS;
6484919Sxy150489 		goto out;
6494919Sxy150489 	}
6504919Sxy150489 
6514919Sxy150489 	/* Enable CRS on TX. This must be set for half-duplex operation. */
6526735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
6534919Sxy150489 	if (ret_val)
6544919Sxy150489 		goto out;
6554919Sxy150489 
656*10680SMin.Xu@Sun.COM 	/* For BM PHY this bit is downshift enable */
657*10680SMin.Xu@Sun.COM 	if (phy->type != e1000_phy_bm)
6584919Sxy150489 		phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
6594919Sxy150489 
6604919Sxy150489 	/*
6614919Sxy150489 	 * Options:
6624919Sxy150489 	 *   MDI/MDI-X = 0 (default)
6634919Sxy150489 	 *   0 - Auto for all speeds
6644919Sxy150489 	 *   1 - MDI mode
6654919Sxy150489 	 *   2 - MDI-X mode
6664919Sxy150489 	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
6674919Sxy150489 	 */
6684919Sxy150489 	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
6694919Sxy150489 
6704919Sxy150489 	switch (phy->mdix) {
6714919Sxy150489 	case 1:
6724919Sxy150489 		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
6734919Sxy150489 		break;
6744919Sxy150489 	case 2:
6754919Sxy150489 		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
6764919Sxy150489 		break;
6774919Sxy150489 	case 3:
6784919Sxy150489 		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
6794919Sxy150489 		break;
6804919Sxy150489 	case 0:
6814919Sxy150489 	default:
6824919Sxy150489 		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
6834919Sxy150489 		break;
6844919Sxy150489 	}
6854919Sxy150489 
6864919Sxy150489 	/*
6874919Sxy150489 	 * Options:
6884919Sxy150489 	 *   disable_polarity_correction = 0 (default)
6894919Sxy150489 	 *	Automatic Correction for Reversed Cable Polarity
6904919Sxy150489 	 *   0 - Disabled
6914919Sxy150489 	 *   1 - Enabled
6924919Sxy150489 	 */
6934919Sxy150489 	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
6944919Sxy150489 	if (phy->disable_polarity_correction == 1)
6954919Sxy150489 		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
6964919Sxy150489 
6976735Scc210113 	/* Enable downshift on BM (disabled by default) */
6986735Scc210113 	if (phy->type == e1000_phy_bm)
6996735Scc210113 		phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
7006735Scc210113 
7016735Scc210113 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
7024919Sxy150489 	if (ret_val)
7034919Sxy150489 		goto out;
7044919Sxy150489 
7056735Scc210113 	if ((phy->type == e1000_phy_m88) &&
7067607STed.You@Sun.COM 	    (phy->revision < E1000_REVISION_4) &&
7077607STed.You@Sun.COM 	    (phy->id != BME1000_E_PHY_ID_R2)) {
7084919Sxy150489 		/*
7094919Sxy150489 		 * Force TX_CLK in the Extended PHY Specific Control Register
7104919Sxy150489 		 * to 25MHz clock.
7114919Sxy150489 		 */
7126735Scc210113 		ret_val = phy->ops.read_reg(hw,
7134919Sxy150489 		    M88E1000_EXT_PHY_SPEC_CTRL,
7144919Sxy150489 		    &phy_data);
7154919Sxy150489 		if (ret_val)
7164919Sxy150489 			goto out;
7174919Sxy150489 
7184919Sxy150489 		phy_data |= M88E1000_EPSCR_TX_CLK_25;
7194919Sxy150489 
7204919Sxy150489 		if ((phy->revision == E1000_REVISION_2) &&
7214919Sxy150489 		    (phy->id == M88E1111_I_PHY_ID)) {
7224919Sxy150489 			/* 82573L PHY - set the downshift counter to 5x. */
7234919Sxy150489 			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
7244919Sxy150489 			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
7254919Sxy150489 		} else {
7264919Sxy150489 			/* Configure Master and Slave downshift values */
7274919Sxy150489 			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
7284919Sxy150489 			    M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
7294919Sxy150489 			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
7304919Sxy150489 			    M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
7314919Sxy150489 		}
7326735Scc210113 		ret_val = phy->ops.write_reg(hw,
7334919Sxy150489 		    M88E1000_EXT_PHY_SPEC_CTRL,
7344919Sxy150489 		    phy_data);
7354919Sxy150489 		if (ret_val)
7364919Sxy150489 			goto out;
7374919Sxy150489 	}
7384919Sxy150489 
7397607STed.You@Sun.COM 	if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
7407607STed.You@Sun.COM 		/* Set PHY page 0, register 29 to 0x0003 */
7417607STed.You@Sun.COM 		ret_val = phy->ops.write_reg(hw, 29, 0x0003);
7427607STed.You@Sun.COM 		if (ret_val)
7437607STed.You@Sun.COM 			goto out;
7447607STed.You@Sun.COM 
7457607STed.You@Sun.COM 		/* Set PHY page 0, register 30 to 0x0000 */
7467607STed.You@Sun.COM 		ret_val = phy->ops.write_reg(hw, 30, 0x0000);
7477607STed.You@Sun.COM 		if (ret_val)
7487607STed.You@Sun.COM 			goto out;
7497607STed.You@Sun.COM 	}
7507607STed.You@Sun.COM 
7514919Sxy150489 	/* Commit the changes. */
7526735Scc210113 	ret_val = phy->ops.commit(hw);
7534919Sxy150489 	if (ret_val) {
7544919Sxy150489 		DEBUGOUT("Error committing the PHY changes\n");
7554919Sxy150489 		goto out;
7564919Sxy150489 	}
7574919Sxy150489 
758*10680SMin.Xu@Sun.COM 	if (phy->type == e1000_phy_82578) {
759*10680SMin.Xu@Sun.COM 		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
760*10680SMin.Xu@Sun.COM 		    &phy_data);
761*10680SMin.Xu@Sun.COM 		if (ret_val)
762*10680SMin.Xu@Sun.COM 			goto out;
763*10680SMin.Xu@Sun.COM 
764*10680SMin.Xu@Sun.COM 		/* 82578 PHY - set the downshift count to 1x. */
765*10680SMin.Xu@Sun.COM 		phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
766*10680SMin.Xu@Sun.COM 		phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
767*10680SMin.Xu@Sun.COM 		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
768*10680SMin.Xu@Sun.COM 		    phy_data);
769*10680SMin.Xu@Sun.COM 		if (ret_val)
770*10680SMin.Xu@Sun.COM 			goto out;
771*10680SMin.Xu@Sun.COM }
772*10680SMin.Xu@Sun.COM 
7734919Sxy150489 out:
7744919Sxy150489 	return (ret_val);
7754919Sxy150489 }
7764919Sxy150489 
7774919Sxy150489 /*
7784919Sxy150489  * e1000_copper_link_setup_igp - Setup igp PHY's for copper link
7794919Sxy150489  * @hw: pointer to the HW structure
7804919Sxy150489  *
7814919Sxy150489  * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
7824919Sxy150489  * igp PHY's.
7834919Sxy150489  */
7844919Sxy150489 s32
7854919Sxy150489 e1000_copper_link_setup_igp(struct e1000_hw *hw)
7864919Sxy150489 {
7874919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
7884919Sxy150489 	s32 ret_val;
7894919Sxy150489 	u16 data;
7904919Sxy150489 
7914919Sxy150489 	DEBUGFUNC("e1000_copper_link_setup_igp");
7924919Sxy150489 
7934919Sxy150489 	if (phy->reset_disable) {
7944919Sxy150489 		ret_val = E1000_SUCCESS;
7954919Sxy150489 		goto out;
7964919Sxy150489 	}
7974919Sxy150489 
7987607STed.You@Sun.COM 	ret_val = hw->phy.ops.reset(hw);
7994919Sxy150489 	if (ret_val) {
8004919Sxy150489 		DEBUGOUT("Error resetting the PHY.\n");
8014919Sxy150489 		goto out;
8024919Sxy150489 	}
8034919Sxy150489 
8046735Scc210113 	/*
8056735Scc210113 	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
8066735Scc210113 	 * timeout issues when LFS is enabled.
8076735Scc210113 	 */
8086735Scc210113 	msec_delay(100);
8094919Sxy150489 
8104919Sxy150489 	/*
8114919Sxy150489 	 * The NVM settings will configure LPLU in D3 for non-IGP1 PHYs.
8124919Sxy150489 	 */
8134919Sxy150489 	if (phy->type == e1000_phy_igp) {
8144919Sxy150489 		/* disable lplu d3 during driver init */
8157607STed.You@Sun.COM 		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
8164919Sxy150489 		if (ret_val) {
8174919Sxy150489 			DEBUGOUT("Error Disabling LPLU D3\n");
8184919Sxy150489 			goto out;
8194919Sxy150489 		}
8204919Sxy150489 	}
8214919Sxy150489 
8224919Sxy150489 	/* disable lplu d0 during driver init */
8237607STed.You@Sun.COM 	if (hw->phy.ops.set_d0_lplu_state) {
8247607STed.You@Sun.COM 		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
8257607STed.You@Sun.COM 		if (ret_val) {
8267607STed.You@Sun.COM 			DEBUGOUT("Error Disabling LPLU D0\n");
8277607STed.You@Sun.COM 			goto out;
8287607STed.You@Sun.COM 		}
8294919Sxy150489 	}
8304919Sxy150489 	/* Configure mdi-mdix settings */
8316735Scc210113 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
8324919Sxy150489 	if (ret_val)
8334919Sxy150489 		goto out;
8344919Sxy150489 
8354919Sxy150489 	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
8364919Sxy150489 
8374919Sxy150489 	switch (phy->mdix) {
8384919Sxy150489 	case 1:
8394919Sxy150489 		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
8404919Sxy150489 		break;
8414919Sxy150489 	case 2:
8424919Sxy150489 		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
8434919Sxy150489 		break;
8444919Sxy150489 	case 0:
8454919Sxy150489 	default:
8464919Sxy150489 		data |= IGP01E1000_PSCR_AUTO_MDIX;
8474919Sxy150489 		break;
8484919Sxy150489 	}
8496735Scc210113 	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
8504919Sxy150489 	if (ret_val)
8514919Sxy150489 		goto out;
8524919Sxy150489 
8534919Sxy150489 	/* set auto-master slave resolution settings */
8544919Sxy150489 	if (hw->mac.autoneg) {
8554919Sxy150489 		/*
8564919Sxy150489 		 * when autonegotiation advertisement is only 1000Mbps then we
8574919Sxy150489 		 * should disable SmartSpeed and enable Auto MasterSlave
8584919Sxy150489 		 * resolution as hardware default.
8594919Sxy150489 		 */
8604919Sxy150489 		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
8614919Sxy150489 			/* Disable SmartSpeed */
8626735Scc210113 			ret_val = phy->ops.read_reg(hw,
8634919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
8644919Sxy150489 			    &data);
8654919Sxy150489 			if (ret_val)
8664919Sxy150489 				goto out;
8674919Sxy150489 
8684919Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
8696735Scc210113 			ret_val = phy->ops.write_reg(hw,
8704919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
8714919Sxy150489 			    data);
8724919Sxy150489 			if (ret_val)
8734919Sxy150489 				goto out;
8744919Sxy150489 
8754919Sxy150489 			/* Set auto Master/Slave resolution process */
8766735Scc210113 			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
8774919Sxy150489 			if (ret_val)
8784919Sxy150489 				goto out;
8794919Sxy150489 
8804919Sxy150489 			data &= ~CR_1000T_MS_ENABLE;
8816735Scc210113 			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
8824919Sxy150489 			if (ret_val)
8834919Sxy150489 				goto out;
8844919Sxy150489 		}
8854919Sxy150489 
8866735Scc210113 		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
8874919Sxy150489 		if (ret_val)
8884919Sxy150489 			goto out;
8894919Sxy150489 
8904919Sxy150489 		/* load defaults for future use */
8914919Sxy150489 		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
8924919Sxy150489 		    ((data & CR_1000T_MS_VALUE) ?
8934919Sxy150489 		    e1000_ms_force_master :
8944919Sxy150489 		    e1000_ms_force_slave) :
8954919Sxy150489 		    e1000_ms_auto;
8964919Sxy150489 
8974919Sxy150489 		switch (phy->ms_type) {
8984919Sxy150489 		case e1000_ms_force_master:
8994919Sxy150489 			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
9004919Sxy150489 			break;
9014919Sxy150489 		case e1000_ms_force_slave:
9024919Sxy150489 			data |= CR_1000T_MS_ENABLE;
9034919Sxy150489 			data &= ~(CR_1000T_MS_VALUE);
9044919Sxy150489 			break;
9054919Sxy150489 		case e1000_ms_auto:
9064919Sxy150489 			data &= ~CR_1000T_MS_ENABLE;
9074919Sxy150489 		default:
9084919Sxy150489 			break;
9094919Sxy150489 		}
9106735Scc210113 		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
9114919Sxy150489 		if (ret_val)
9124919Sxy150489 			goto out;
9134919Sxy150489 	}
9144919Sxy150489 
9154919Sxy150489 out:
9164919Sxy150489 	return (ret_val);
9174919Sxy150489 }
9184919Sxy150489 
9194919Sxy150489 /*
9204919Sxy150489  * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
9214919Sxy150489  * @hw: pointer to the HW structure
9224919Sxy150489  *
9234919Sxy150489  * Performs initial bounds checking on autoneg advertisement parameter, then
9244919Sxy150489  * configure to advertise the full capability.  Setup the PHY to autoneg
9254919Sxy150489  * and restart the negotiation process between the link partner.  If
9266735Scc210113  * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
9274919Sxy150489  */
9284919Sxy150489 s32
9294919Sxy150489 e1000_copper_link_autoneg(struct e1000_hw *hw)
9304919Sxy150489 {
9314919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
9324919Sxy150489 	s32 ret_val;
9334919Sxy150489 	u16 phy_ctrl;
9344919Sxy150489 
9354919Sxy150489 	DEBUGFUNC("e1000_copper_link_autoneg");
9364919Sxy150489 
9374919Sxy150489 	/*
9384919Sxy150489 	 * Perform some bounds checking on the autoneg advertisement
9394919Sxy150489 	 * parameter.
9404919Sxy150489 	 */
9414919Sxy150489 	phy->autoneg_advertised &= phy->autoneg_mask;
9424919Sxy150489 
9434919Sxy150489 	/*
9444919Sxy150489 	 * If autoneg_advertised is zero, we assume it was not defaulted by
9454919Sxy150489 	 * the calling code so we set to advertise full capability.
9464919Sxy150489 	 */
9474919Sxy150489 	if (phy->autoneg_advertised == 0)
9484919Sxy150489 		phy->autoneg_advertised = phy->autoneg_mask;
9494919Sxy150489 
9504919Sxy150489 	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
9514919Sxy150489 	ret_val = e1000_phy_setup_autoneg(hw);
9524919Sxy150489 	if (ret_val) {
9534919Sxy150489 		DEBUGOUT("Error Setting up Auto-Negotiation\n");
9544919Sxy150489 		goto out;
9554919Sxy150489 	}
9564919Sxy150489 	DEBUGOUT("Restarting Auto-Neg\n");
9574919Sxy150489 
9584919Sxy150489 	/*
9594919Sxy150489 	 * Restart auto-negotiation by setting the Auto Neg Enable bit and the
9604919Sxy150489 	 * Auto Neg Restart bit in the PHY control register.
9614919Sxy150489 	 */
9626735Scc210113 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
9634919Sxy150489 	if (ret_val)
9644919Sxy150489 		goto out;
9654919Sxy150489 
9664919Sxy150489 	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
9676735Scc210113 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
9684919Sxy150489 	if (ret_val)
9694919Sxy150489 		goto out;
9704919Sxy150489 
9714919Sxy150489 	/*
9724919Sxy150489 	 * Does the user want to wait for Auto-Neg to complete here, or check
9734919Sxy150489 	 * at a later time (for example, callback routine).
9744919Sxy150489 	 */
9756735Scc210113 	if (phy->autoneg_wait_to_complete) {
9767607STed.You@Sun.COM 		ret_val = hw->mac.ops.wait_autoneg(hw);
9774919Sxy150489 		if (ret_val) {
9784919Sxy150489 			DEBUGOUT("Error while waiting for "
9794919Sxy150489 			    "autoneg to complete\n");
9804919Sxy150489 			goto out;
9814919Sxy150489 		}
9824919Sxy150489 	}
9834919Sxy150489 
9847607STed.You@Sun.COM 	hw->mac.get_link_status = true;
9854919Sxy150489 
9864919Sxy150489 out:
9874919Sxy150489 	return (ret_val);
9884919Sxy150489 }
9894919Sxy150489 
9904919Sxy150489 /*
9914919Sxy150489  * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
9924919Sxy150489  * @hw: pointer to the HW structure
9934919Sxy150489  *
9944919Sxy150489  * Reads the MII auto-neg advertisement register and/or the 1000T control
9954919Sxy150489  * register and if the PHY is already setup for auto-negotiation, then
9964919Sxy150489  * return successful.  Otherwise, setup advertisement and flow control to
9974919Sxy150489  * the appropriate values for the wanted auto-negotiation.
9984919Sxy150489  */
9994919Sxy150489 s32
10004919Sxy150489 e1000_phy_setup_autoneg(struct e1000_hw *hw)
10014919Sxy150489 {
10024919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
10034919Sxy150489 	s32 ret_val;
10044919Sxy150489 	u16 mii_autoneg_adv_reg;
10054919Sxy150489 	u16 mii_1000t_ctrl_reg = 0;
10064919Sxy150489 
10074919Sxy150489 	DEBUGFUNC("e1000_phy_setup_autoneg");
10084919Sxy150489 
10094919Sxy150489 	phy->autoneg_advertised &= phy->autoneg_mask;
10104919Sxy150489 
10114919Sxy150489 	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
10126735Scc210113 	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
10134919Sxy150489 	if (ret_val)
10144919Sxy150489 		goto out;
10154919Sxy150489 
10164919Sxy150489 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
10174919Sxy150489 		/* Read the MII 1000Base-T Control Register (Address 9). */
10186735Scc210113 		ret_val = phy->ops.read_reg(hw,
10194919Sxy150489 		    PHY_1000T_CTRL,
10204919Sxy150489 		    &mii_1000t_ctrl_reg);
10214919Sxy150489 		if (ret_val)
10224919Sxy150489 			goto out;
10234919Sxy150489 	}
10244919Sxy150489 
10254919Sxy150489 	/*
10264919Sxy150489 	 * Need to parse both autoneg_advertised and fc and set up the
10274919Sxy150489 	 * appropriate PHY registers.  First we will parse for
10284919Sxy150489 	 * autoneg_advertised software override.  Since we can advertise a
10294919Sxy150489 	 * plethora of combinations, we need to check each bit individually.
10304919Sxy150489 	 */
10314919Sxy150489 
10324919Sxy150489 	/*
10334919Sxy150489 	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
10344919Sxy150489 	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
10354919Sxy150489 	 * the  1000Base-T Control Register (Address 9).
10364919Sxy150489 	 */
10374919Sxy150489 	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
10384919Sxy150489 	    NWAY_AR_100TX_HD_CAPS |
10394919Sxy150489 	    NWAY_AR_10T_FD_CAPS |
10404919Sxy150489 	    NWAY_AR_10T_HD_CAPS);
10414919Sxy150489 	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
10424919Sxy150489 
10434919Sxy150489 	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
10444919Sxy150489 
10454919Sxy150489 	/* Do we want to advertise 10 Mb Half Duplex? */
10464919Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
10474919Sxy150489 		DEBUGOUT("Advertise 10mb Half duplex\n");
10484919Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
10494919Sxy150489 	}
10504919Sxy150489 
10514919Sxy150489 	/* Do we want to advertise 10 Mb Full Duplex? */
10524919Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
10534919Sxy150489 		DEBUGOUT("Advertise 10mb Full duplex\n");
10544919Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
10554919Sxy150489 	}
10564919Sxy150489 
10574919Sxy150489 	/* Do we want to advertise 100 Mb Half Duplex? */
10584919Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
10594919Sxy150489 		DEBUGOUT("Advertise 100mb Half duplex\n");
10604919Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
10614919Sxy150489 	}
10624919Sxy150489 
10634919Sxy150489 	/* Do we want to advertise 100 Mb Full Duplex? */
10644919Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
10654919Sxy150489 		DEBUGOUT("Advertise 100mb Full duplex\n");
10664919Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
10674919Sxy150489 	}
10684919Sxy150489 
10694919Sxy150489 	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
10708479SChenlu.Chen@Sun.COM 	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
10714919Sxy150489 		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
10724919Sxy150489 
10734919Sxy150489 	/* Do we want to advertise 1000 Mb Full Duplex? */
10744919Sxy150489 	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
10754919Sxy150489 		DEBUGOUT("Advertise 1000mb Full duplex\n");
10764919Sxy150489 		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
10774919Sxy150489 	}
10784919Sxy150489 
10794919Sxy150489 	/*
10804919Sxy150489 	 * Check for a software override of the flow control settings, and
10814919Sxy150489 	 * setup the PHY advertisement registers accordingly.  If
10824919Sxy150489 	 * auto-negotiation is enabled, then software will have to set the
10834919Sxy150489 	 * "PAUSE" bits to the correct value in the Auto-Negotiation
10844919Sxy150489 	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
10854919Sxy150489 	 * negotiation.
10864919Sxy150489 	 *
10874919Sxy150489 	 * The possible values of the "fc" parameter are:
10884919Sxy150489 	 * 0:	Flow control is completely disabled
10894919Sxy150489 	 * 1:	Rx flow control is enabled (we can receive pause frames
10904919Sxy150489 	 *	but not send pause frames).
10914919Sxy150489 	 * 2:	Tx flow control is enabled (we can send pause frames
10924919Sxy150489 	 *	but we do not support receiving pause frames).
10936735Scc210113 	 * 3:	Both Rx and Tx flow control (symmetric) are enabled.
10944919Sxy150489 	 * other: No software override.  The flow control configuration
10954919Sxy150489 	 *	in the EEPROM is used.
10964919Sxy150489 	 */
10978479SChenlu.Chen@Sun.COM 	switch (hw->fc.current_mode) {
10984919Sxy150489 	case e1000_fc_none:
10994919Sxy150489 		/*
11006735Scc210113 		 * Flow control (Rx & Tx) is completely disabled by a software
11014919Sxy150489 		 * over-ride.
11024919Sxy150489 		 */
11034919Sxy150489 		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
11044919Sxy150489 		break;
11054919Sxy150489 	case e1000_fc_rx_pause:
11064919Sxy150489 		/*
11076735Scc210113 		 * Rx Flow control is enabled, and Tx Flow control is
11084919Sxy150489 		 * disabled, by a software over-ride.
11094919Sxy150489 		 *
11104919Sxy150489 		 * Since there really isn't a way to advertise that we are
11116735Scc210113 		 * capable of Rx Pause ONLY, we will advertise that we support
11126735Scc210113 		 * both symmetric and asymmetric Rx PAUSE.  Later (in
11134919Sxy150489 		 * e1000_config_fc_after_link_up) we will disable the hw's
11144919Sxy150489 		 * ability to send PAUSE frames.
11154919Sxy150489 		 */
11164919Sxy150489 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
11174919Sxy150489 		break;
11184919Sxy150489 	case e1000_fc_tx_pause:
11194919Sxy150489 		/*
11206735Scc210113 		 * Tx Flow control is enabled, and Rx Flow control is
11214919Sxy150489 		 * disabled, by a software over-ride.
11224919Sxy150489 		 */
11234919Sxy150489 		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
11244919Sxy150489 		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
11254919Sxy150489 		break;
11264919Sxy150489 	case e1000_fc_full:
11274919Sxy150489 		/*
11286735Scc210113 		 * Flow control (both Rx and Tx) is enabled by a software
11294919Sxy150489 		 * over-ride.
11304919Sxy150489 		 */
11314919Sxy150489 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
11324919Sxy150489 		break;
11334919Sxy150489 	default:
11344919Sxy150489 		DEBUGOUT("Flow control param set incorrectly\n");
11354919Sxy150489 		ret_val = -E1000_ERR_CONFIG;
11364919Sxy150489 		goto out;
11374919Sxy150489 	}
11384919Sxy150489 
11396735Scc210113 	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
11404919Sxy150489 	if (ret_val)
11414919Sxy150489 		goto out;
11424919Sxy150489 
11434919Sxy150489 	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
11444919Sxy150489 
11454919Sxy150489 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
11466735Scc210113 		ret_val = phy->ops.write_reg(hw,
11474919Sxy150489 		    PHY_1000T_CTRL,
11484919Sxy150489 		    mii_1000t_ctrl_reg);
11494919Sxy150489 		if (ret_val)
11504919Sxy150489 			goto out;
11514919Sxy150489 	}
11524919Sxy150489 
11534919Sxy150489 out:
11544919Sxy150489 	return (ret_val);
11554919Sxy150489 }
11564919Sxy150489 
11574919Sxy150489 /*
11584919Sxy150489  * e1000_setup_copper_link_generic - Configure copper link settings
11594919Sxy150489  * @hw: pointer to the HW structure
11604919Sxy150489  *
11614919Sxy150489  * Calls the appropriate function to configure the link for auto-neg or forced
11624919Sxy150489  * speed and duplex.  Then we check for link, once link is established calls
11634919Sxy150489  * to configure collision distance and flow control are called.  If link is
11644919Sxy150489  * not established, we return -E1000_ERR_PHY (-2).
11654919Sxy150489  */
11664919Sxy150489 s32
11674919Sxy150489 e1000_setup_copper_link_generic(struct e1000_hw *hw)
11684919Sxy150489 {
11694919Sxy150489 	s32 ret_val;
11706735Scc210113 	bool link;
11714919Sxy150489 
11724919Sxy150489 	DEBUGFUNC("e1000_setup_copper_link_generic");
11734919Sxy150489 
11744919Sxy150489 	if (hw->mac.autoneg) {
11754919Sxy150489 		/*
11764919Sxy150489 		 * Setup autoneg and flow control advertisement and perform
11774919Sxy150489 		 * autonegotiation.
11784919Sxy150489 		 */
11794919Sxy150489 		ret_val = e1000_copper_link_autoneg(hw);
11804919Sxy150489 		if (ret_val)
11814919Sxy150489 			goto out;
11824919Sxy150489 	} else {
11834919Sxy150489 		/*
11844919Sxy150489 		 * PHY will be set to 10H, 10F, 100H or 100F depending on user
11854919Sxy150489 		 * settings.
11864919Sxy150489 		 */
11874919Sxy150489 		DEBUGOUT("Forcing Speed and Duplex\n");
11886735Scc210113 		ret_val = hw->phy.ops.force_speed_duplex(hw);
11894919Sxy150489 		if (ret_val) {
11904919Sxy150489 			DEBUGOUT("Error Forcing Speed and Duplex\n");
11914919Sxy150489 			goto out;
11924919Sxy150489 		}
11934919Sxy150489 	}
11944919Sxy150489 
11954919Sxy150489 	/*
11964919Sxy150489 	 * Check link status. Wait up to 100 microseconds for link to become
11974919Sxy150489 	 * valid.
11984919Sxy150489 	 */
11994919Sxy150489 	ret_val = e1000_phy_has_link_generic(hw,
12004919Sxy150489 	    COPPER_LINK_UP_LIMIT,
12014919Sxy150489 	    10,
12024919Sxy150489 	    &link);
12034919Sxy150489 	if (ret_val)
12044919Sxy150489 		goto out;
12054919Sxy150489 
12064919Sxy150489 	if (link) {
12074919Sxy150489 		DEBUGOUT("Valid link established!!!\n");
12084919Sxy150489 		e1000_config_collision_dist_generic(hw);
12094919Sxy150489 		ret_val = e1000_config_fc_after_link_up_generic(hw);
12104919Sxy150489 	} else {
12114919Sxy150489 		DEBUGOUT("Unable to establish link!!!\n");
12124919Sxy150489 	}
12134919Sxy150489 
12144919Sxy150489 out:
12154919Sxy150489 	return (ret_val);
12164919Sxy150489 }
12174919Sxy150489 
12184919Sxy150489 /*
12194919Sxy150489  * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
12204919Sxy150489  * @hw: pointer to the HW structure
12214919Sxy150489  *
12224919Sxy150489  * Calls the PHY setup function to force speed and duplex.  Clears the
12234919Sxy150489  * auto-crossover to force MDI manually.  Waits for link and returns
12244919Sxy150489  * successful if link up is successful, else -E1000_ERR_PHY (-2).
12254919Sxy150489  */
12264919Sxy150489 s32
12274919Sxy150489 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
12284919Sxy150489 {
12294919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
12304919Sxy150489 	s32 ret_val;
12314919Sxy150489 	u16 phy_data;
12326735Scc210113 	bool link;
12334919Sxy150489 
12344919Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
12354919Sxy150489 
12366735Scc210113 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
12374919Sxy150489 	if (ret_val)
12384919Sxy150489 		goto out;
12394919Sxy150489 
12404919Sxy150489 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
12414919Sxy150489 
12426735Scc210113 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
12434919Sxy150489 	if (ret_val)
12444919Sxy150489 		goto out;
12454919Sxy150489 
12464919Sxy150489 	/*
12474919Sxy150489 	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
12484919Sxy150489 	 * forced whenever speed and duplex are forced.
12494919Sxy150489 	 */
12506735Scc210113 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
12514919Sxy150489 	if (ret_val)
12524919Sxy150489 		goto out;
12534919Sxy150489 
12544919Sxy150489 	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
12554919Sxy150489 	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
12564919Sxy150489 
12576735Scc210113 	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
12584919Sxy150489 	if (ret_val)
12594919Sxy150489 		goto out;
12604919Sxy150489 
12614919Sxy150489 	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
12624919Sxy150489 
12634919Sxy150489 	usec_delay(1);
12644919Sxy150489 
12656735Scc210113 	if (phy->autoneg_wait_to_complete) {
12664919Sxy150489 		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
12674919Sxy150489 
12684919Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
12694919Sxy150489 		    PHY_FORCE_LIMIT,
12704919Sxy150489 		    100000,
12714919Sxy150489 		    &link);
12724919Sxy150489 		if (ret_val)
12734919Sxy150489 			goto out;
12744919Sxy150489 
12758479SChenlu.Chen@Sun.COM 		if (!link)
12764919Sxy150489 			DEBUGOUT("Link taking longer than expected.\n");
12774919Sxy150489 
12784919Sxy150489 		/* Try once more */
12794919Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
12804919Sxy150489 		    PHY_FORCE_LIMIT,
12814919Sxy150489 		    100000,
12824919Sxy150489 		    &link);
12834919Sxy150489 		if (ret_val)
12844919Sxy150489 			goto out;
12854919Sxy150489 	}
12864919Sxy150489 
12874919Sxy150489 out:
12884919Sxy150489 	return (ret_val);
12894919Sxy150489 }
12904919Sxy150489 
12914919Sxy150489 /*
12924919Sxy150489  * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
12934919Sxy150489  * @hw: pointer to the HW structure
12944919Sxy150489  *
12954919Sxy150489  * Calls the PHY setup function to force speed and duplex.  Clears the
12964919Sxy150489  * auto-crossover to force MDI manually.  Resets the PHY to commit the
12974919Sxy150489  * changes.  If time expires while waiting for link up, we reset the DSP.
12986735Scc210113  * After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
12994919Sxy150489  * successful completion, else return corresponding error code.
13004919Sxy150489  */
13014919Sxy150489 s32
13024919Sxy150489 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
13034919Sxy150489 {
13044919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
13054919Sxy150489 	s32 ret_val;
13064919Sxy150489 	u16 phy_data;
13076735Scc210113 	bool link;
13084919Sxy150489 
13094919Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
13104919Sxy150489 
13114919Sxy150489 	/*
13124919Sxy150489 	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
13134919Sxy150489 	 * forced whenever speed and duplex are forced.
13144919Sxy150489 	 */
13156735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
13164919Sxy150489 	if (ret_val)
13174919Sxy150489 		goto out;
13184919Sxy150489 
13194919Sxy150489 	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
13206735Scc210113 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
13214919Sxy150489 	if (ret_val)
13224919Sxy150489 		goto out;
13234919Sxy150489 
13244919Sxy150489 	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
13254919Sxy150489 
13266735Scc210113 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
13274919Sxy150489 	if (ret_val)
13284919Sxy150489 		goto out;
13294919Sxy150489 
13304919Sxy150489 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
13314919Sxy150489 
13326735Scc210113 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
13334919Sxy150489 	if (ret_val)
13344919Sxy150489 		goto out;
13354919Sxy150489 
13368479SChenlu.Chen@Sun.COM 	/* Reset the phy to commit changes. */
13378479SChenlu.Chen@Sun.COM 	ret_val = hw->phy.ops.commit(hw);
13388479SChenlu.Chen@Sun.COM 	if (ret_val)
13398479SChenlu.Chen@Sun.COM 		goto out;
13404919Sxy150489 
13416735Scc210113 	if (phy->autoneg_wait_to_complete) {
13424919Sxy150489 		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
13434919Sxy150489 
13444919Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
13454919Sxy150489 		    PHY_FORCE_LIMIT,
13464919Sxy150489 		    100000,
13474919Sxy150489 		    &link);
13484919Sxy150489 		if (ret_val)
13494919Sxy150489 			goto out;
13504919Sxy150489 
13514919Sxy150489 		if (!link) {
13524919Sxy150489 			/*
13534919Sxy150489 			 * We didn't get link. Reset the DSP and cross our
13544919Sxy150489 			 * fingers.
13554919Sxy150489 			 */
13566735Scc210113 			ret_val = phy->ops.write_reg(hw,
13574919Sxy150489 			    M88E1000_PHY_PAGE_SELECT,
13584919Sxy150489 			    0x001d);
13594919Sxy150489 			if (ret_val)
13604919Sxy150489 				goto out;
13614919Sxy150489 			ret_val = e1000_phy_reset_dsp_generic(hw);
13624919Sxy150489 			if (ret_val)
13634919Sxy150489 				goto out;
13644919Sxy150489 		}
13654919Sxy150489 		/* Try once more */
13664919Sxy150489 		ret_val = e1000_phy_has_link_generic(hw,
13674919Sxy150489 		    PHY_FORCE_LIMIT,
13684919Sxy150489 		    100000,
13694919Sxy150489 		    &link);
13704919Sxy150489 		if (ret_val)
13714919Sxy150489 			goto out;
13724919Sxy150489 	}
13736735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
13744919Sxy150489 	if (ret_val)
13754919Sxy150489 		goto out;
13764919Sxy150489 
13774919Sxy150489 	/*
13784919Sxy150489 	 * Resetting the phy means we need to re-force TX_CLK in the Extended
13794919Sxy150489 	 * PHY Specific Control Register to 25MHz clock from the reset value
13804919Sxy150489 	 * of 2.5MHz.
13814919Sxy150489 	 */
13824919Sxy150489 	phy_data |= M88E1000_EPSCR_TX_CLK_25;
13836735Scc210113 	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
13844919Sxy150489 	if (ret_val)
13854919Sxy150489 		goto out;
13864919Sxy150489 
13874919Sxy150489 	/*
13884919Sxy150489 	 * In addition, we must re-enable CRS on Tx for both half and full
13894919Sxy150489 	 * duplex.
13904919Sxy150489 	 */
13916735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
13924919Sxy150489 	if (ret_val)
13934919Sxy150489 		goto out;
13944919Sxy150489 
13954919Sxy150489 	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
13966735Scc210113 	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
13974919Sxy150489 
13984919Sxy150489 out:
13994919Sxy150489 	return (ret_val);
14004919Sxy150489 }
14014919Sxy150489 
14024919Sxy150489 /*
1403*10680SMin.Xu@Sun.COM  * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
1404*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
1405*10680SMin.Xu@Sun.COM  *
1406*10680SMin.Xu@Sun.COM  * Forces the speed and duplex settings of the PHY.
1407*10680SMin.Xu@Sun.COM  * This is a function pointer entry point only called by
1408*10680SMin.Xu@Sun.COM  * PHY setup routines.
1409*10680SMin.Xu@Sun.COM  */
1410*10680SMin.Xu@Sun.COM s32
1411*10680SMin.Xu@Sun.COM e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
1412*10680SMin.Xu@Sun.COM {
1413*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
1414*10680SMin.Xu@Sun.COM 	s32 ret_val;
1415*10680SMin.Xu@Sun.COM 	u16 data;
1416*10680SMin.Xu@Sun.COM 	bool link;
1417*10680SMin.Xu@Sun.COM 
1418*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
1419*10680SMin.Xu@Sun.COM 
1420*10680SMin.Xu@Sun.COM 	if (phy->type != e1000_phy_ife) {
1421*10680SMin.Xu@Sun.COM 		ret_val = e1000_phy_force_speed_duplex_igp(hw);
1422*10680SMin.Xu@Sun.COM 		goto out;
1423*10680SMin.Xu@Sun.COM 	}
1424*10680SMin.Xu@Sun.COM 
1425*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
1426*10680SMin.Xu@Sun.COM 	if (ret_val)
1427*10680SMin.Xu@Sun.COM 		goto out;
1428*10680SMin.Xu@Sun.COM 
1429*10680SMin.Xu@Sun.COM 	e1000_phy_force_speed_duplex_setup(hw, &data);
1430*10680SMin.Xu@Sun.COM 
1431*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
1432*10680SMin.Xu@Sun.COM 	if (ret_val)
1433*10680SMin.Xu@Sun.COM 		goto out;
1434*10680SMin.Xu@Sun.COM 
1435*10680SMin.Xu@Sun.COM 	/* Disable MDI-X support for 10/100 */
1436*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
1437*10680SMin.Xu@Sun.COM 	if (ret_val)
1438*10680SMin.Xu@Sun.COM 		goto out;
1439*10680SMin.Xu@Sun.COM 
1440*10680SMin.Xu@Sun.COM 	data &= ~IFE_PMC_AUTO_MDIX;
1441*10680SMin.Xu@Sun.COM 	data &= ~IFE_PMC_FORCE_MDIX;
1442*10680SMin.Xu@Sun.COM 
1443*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
1444*10680SMin.Xu@Sun.COM 	if (ret_val)
1445*10680SMin.Xu@Sun.COM 		goto out;
1446*10680SMin.Xu@Sun.COM 
1447*10680SMin.Xu@Sun.COM 	DEBUGOUT1("IFE PMC: %X\n", data);
1448*10680SMin.Xu@Sun.COM 
1449*10680SMin.Xu@Sun.COM 	usec_delay(1);
1450*10680SMin.Xu@Sun.COM 
1451*10680SMin.Xu@Sun.COM 	if (phy->autoneg_wait_to_complete) {
1452*10680SMin.Xu@Sun.COM 		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
1453*10680SMin.Xu@Sun.COM 
1454*10680SMin.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
1455*10680SMin.Xu@Sun.COM 		    PHY_FORCE_LIMIT, 100000, &link);
1456*10680SMin.Xu@Sun.COM 		if (ret_val)
1457*10680SMin.Xu@Sun.COM 			goto out;
1458*10680SMin.Xu@Sun.COM 
1459*10680SMin.Xu@Sun.COM 		if (!link)
1460*10680SMin.Xu@Sun.COM 			DEBUGOUT("Link taking longer than expected.\n");
1461*10680SMin.Xu@Sun.COM 
1462*10680SMin.Xu@Sun.COM 		/* Try once more */
1463*10680SMin.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
1464*10680SMin.Xu@Sun.COM 		    PHY_FORCE_LIMIT, 100000, &link);
1465*10680SMin.Xu@Sun.COM 		if (ret_val)
1466*10680SMin.Xu@Sun.COM 			goto out;
1467*10680SMin.Xu@Sun.COM 	}
1468*10680SMin.Xu@Sun.COM 
1469*10680SMin.Xu@Sun.COM out:
1470*10680SMin.Xu@Sun.COM 	return (ret_val);
1471*10680SMin.Xu@Sun.COM }
1472*10680SMin.Xu@Sun.COM 
1473*10680SMin.Xu@Sun.COM /*
14744919Sxy150489  * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
14754919Sxy150489  * @hw: pointer to the HW structure
14764919Sxy150489  * @phy_ctrl: pointer to current value of PHY_CONTROL
14774919Sxy150489  *
14784919Sxy150489  * Forces speed and duplex on the PHY by doing the following: disable flow
14794919Sxy150489  * control, force speed/duplex on the MAC, disable auto speed detection,
14804919Sxy150489  * disable auto-negotiation, configure duplex, configure speed, configure
14814919Sxy150489  * the collision distance, write configuration to CTRL register.  The
14824919Sxy150489  * caller must write to the PHY_CONTROL register for these settings to
14834919Sxy150489  * take affect.
14844919Sxy150489  */
14854919Sxy150489 void
14864919Sxy150489 e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
14874919Sxy150489 {
14884919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
14894919Sxy150489 	u32 ctrl;
14904919Sxy150489 
14914919Sxy150489 	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
14924919Sxy150489 
14934919Sxy150489 	/* Turn off flow control when forcing speed/duplex */
14948479SChenlu.Chen@Sun.COM 	hw->fc.current_mode = e1000_fc_none;
14954919Sxy150489 
14964919Sxy150489 	/* Force speed/duplex on the mac */
14974919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
14984919Sxy150489 	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
14994919Sxy150489 	ctrl &= ~E1000_CTRL_SPD_SEL;
15004919Sxy150489 
15014919Sxy150489 	/* Disable Auto Speed Detection */
15024919Sxy150489 	ctrl &= ~E1000_CTRL_ASDE;
15034919Sxy150489 
15044919Sxy150489 	/* Disable autoneg on the phy */
15054919Sxy150489 	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
15064919Sxy150489 
15074919Sxy150489 	/* Forcing Full or Half Duplex? */
15084919Sxy150489 	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
15094919Sxy150489 		ctrl &= ~E1000_CTRL_FD;
15104919Sxy150489 		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
15114919Sxy150489 		DEBUGOUT("Half Duplex\n");
15124919Sxy150489 	} else {
15134919Sxy150489 		ctrl |= E1000_CTRL_FD;
15144919Sxy150489 		*phy_ctrl |= MII_CR_FULL_DUPLEX;
15154919Sxy150489 		DEBUGOUT("Full Duplex\n");
15164919Sxy150489 	}
15174919Sxy150489 
15184919Sxy150489 	/* Forcing 10mb or 100mb? */
15194919Sxy150489 	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
15204919Sxy150489 		ctrl |= E1000_CTRL_SPD_100;
15214919Sxy150489 		*phy_ctrl |= MII_CR_SPEED_100;
15224919Sxy150489 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
15234919Sxy150489 		DEBUGOUT("Forcing 100mb\n");
15244919Sxy150489 	} else {
15254919Sxy150489 		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
1526*10680SMin.Xu@Sun.COM 		/* LINTED */
15274919Sxy150489 		*phy_ctrl |= MII_CR_SPEED_10;
15284919Sxy150489 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
15294919Sxy150489 		DEBUGOUT("Forcing 10mb\n");
15304919Sxy150489 	}
15314919Sxy150489 
15324919Sxy150489 	e1000_config_collision_dist_generic(hw);
15334919Sxy150489 
15344919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
15354919Sxy150489 }
15364919Sxy150489 
15374919Sxy150489 /*
15384919Sxy150489  * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
15394919Sxy150489  * @hw: pointer to the HW structure
15404919Sxy150489  * @active: boolean used to enable/disable lplu
15414919Sxy150489  *
15424919Sxy150489  * Success returns 0, Failure returns 1
15434919Sxy150489  *
15444919Sxy150489  * The low power link up (lplu) state is set to the power management level D3
15454919Sxy150489  * and SmartSpeed is disabled when active is true, else clear lplu for D3
15464919Sxy150489  * and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
15474919Sxy150489  * is used during Dx states where the power conservation is most important.
15484919Sxy150489  * During driver activity, SmartSpeed should be enabled so performance is
15494919Sxy150489  * maintained.
15504919Sxy150489  */
15514919Sxy150489 s32
15526735Scc210113 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
15534919Sxy150489 {
15544919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
15556735Scc210113 	s32 ret_val = E1000_SUCCESS;
15564919Sxy150489 	u16 data;
15574919Sxy150489 
15584919Sxy150489 	DEBUGFUNC("e1000_set_d3_lplu_state_generic");
15594919Sxy150489 
15606735Scc210113 	if (!(hw->phy.ops.read_reg))
15616735Scc210113 		goto out;
15626735Scc210113 
15636735Scc210113 	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
15644919Sxy150489 	if (ret_val)
15654919Sxy150489 		goto out;
15664919Sxy150489 
15674919Sxy150489 	if (!active) {
15684919Sxy150489 		data &= ~IGP02E1000_PM_D3_LPLU;
15696735Scc210113 		ret_val = phy->ops.write_reg(hw,
15704919Sxy150489 		    IGP02E1000_PHY_POWER_MGMT,
15714919Sxy150489 		    data);
15724919Sxy150489 		if (ret_val)
15734919Sxy150489 			goto out;
15744919Sxy150489 		/*
15754919Sxy150489 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
15764919Sxy150489 		 * during Dx states where the power conservation is most
15774919Sxy150489 		 * important.  During driver activity we should enable
15784919Sxy150489 		 * SmartSpeed, so performance is maintained.
15794919Sxy150489 		 */
15804919Sxy150489 		if (phy->smart_speed == e1000_smart_speed_on) {
15816735Scc210113 			ret_val = phy->ops.read_reg(hw,
15824919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
15834919Sxy150489 			    &data);
15844919Sxy150489 			if (ret_val)
15854919Sxy150489 				goto out;
15864919Sxy150489 
15874919Sxy150489 			data |= IGP01E1000_PSCFR_SMART_SPEED;
15886735Scc210113 			ret_val = phy->ops.write_reg(hw,
15894919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
15904919Sxy150489 			    data);
15914919Sxy150489 			if (ret_val)
15924919Sxy150489 				goto out;
15934919Sxy150489 		} else if (phy->smart_speed == e1000_smart_speed_off) {
15946735Scc210113 			ret_val = phy->ops.read_reg(hw,
15954919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
15964919Sxy150489 			    &data);
15974919Sxy150489 			if (ret_val)
15984919Sxy150489 				goto out;
15994919Sxy150489 
16004919Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
16016735Scc210113 			ret_val = phy->ops.write_reg(hw,
16024919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
16034919Sxy150489 			    data);
16044919Sxy150489 			if (ret_val)
16054919Sxy150489 				goto out;
16064919Sxy150489 		}
16074919Sxy150489 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
16084919Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
16094919Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
16104919Sxy150489 		data |= IGP02E1000_PM_D3_LPLU;
16116735Scc210113 		ret_val = phy->ops.write_reg(hw,
16124919Sxy150489 		    IGP02E1000_PHY_POWER_MGMT,
16134919Sxy150489 		    data);
16144919Sxy150489 		if (ret_val)
16154919Sxy150489 			goto out;
16164919Sxy150489 
16174919Sxy150489 		/* When LPLU is enabled, we should disable SmartSpeed */
16186735Scc210113 		ret_val = phy->ops.read_reg(hw,
16194919Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
16204919Sxy150489 		    &data);
16214919Sxy150489 		if (ret_val)
16224919Sxy150489 			goto out;
16234919Sxy150489 
16244919Sxy150489 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
16256735Scc210113 		ret_val = phy->ops.write_reg(hw,
16264919Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
16274919Sxy150489 		    data);
16284919Sxy150489 	}
16294919Sxy150489 
16304919Sxy150489 out:
16314919Sxy150489 	return (ret_val);
16324919Sxy150489 }
16334919Sxy150489 
16344919Sxy150489 /*
16356735Scc210113  * e1000_check_downshift_generic - Checks whether a downshift in speed occurred
16364919Sxy150489  * @hw: pointer to the HW structure
16374919Sxy150489  *
16384919Sxy150489  * Success returns 0, Failure returns 1
16394919Sxy150489  *
16404919Sxy150489  * A downshift is detected by querying the PHY link health.
16414919Sxy150489  */
16424919Sxy150489 s32
16434919Sxy150489 e1000_check_downshift_generic(struct e1000_hw *hw)
16444919Sxy150489 {
16454919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
16464919Sxy150489 	s32 ret_val;
16474919Sxy150489 	u16 phy_data, offset, mask;
16484919Sxy150489 
16494919Sxy150489 	DEBUGFUNC("e1000_check_downshift_generic");
16504919Sxy150489 
16514919Sxy150489 	switch (phy->type) {
16524919Sxy150489 	case e1000_phy_m88:
16534919Sxy150489 	case e1000_phy_gg82563:
16544919Sxy150489 	case e1000_phy_bm:
1655*10680SMin.Xu@Sun.COM 	case e1000_phy_82578:
16564919Sxy150489 		offset = M88E1000_PHY_SPEC_STATUS;
16574919Sxy150489 		mask = M88E1000_PSSR_DOWNSHIFT;
16584919Sxy150489 		break;
16594919Sxy150489 	case e1000_phy_igp_2:
16604919Sxy150489 	case e1000_phy_igp:
16614919Sxy150489 	case e1000_phy_igp_3:
16624919Sxy150489 		offset = IGP01E1000_PHY_LINK_HEALTH;
16634919Sxy150489 		mask = IGP01E1000_PLHR_SS_DOWNGRADE;
16644919Sxy150489 		break;
16654919Sxy150489 	default:
16664919Sxy150489 		/* speed downshift not supported */
16677607STed.You@Sun.COM 		phy->speed_downgraded = false;
16684919Sxy150489 		ret_val = E1000_SUCCESS;
16694919Sxy150489 		goto out;
16704919Sxy150489 	}
16714919Sxy150489 
16726735Scc210113 	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
16734919Sxy150489 
16744919Sxy150489 	if (!ret_val)
16757607STed.You@Sun.COM 		phy->speed_downgraded = (phy_data & mask) ? true : false;
16764919Sxy150489 
16774919Sxy150489 out:
16784919Sxy150489 	return (ret_val);
16794919Sxy150489 }
16804919Sxy150489 
16814919Sxy150489 /*
16824919Sxy150489  * e1000_check_polarity_m88 - Checks the polarity.
16834919Sxy150489  * @hw: pointer to the HW structure
16844919Sxy150489  *
16854919Sxy150489  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
16864919Sxy150489  *
16874919Sxy150489  * Polarity is determined based on the PHY specific status register.
16884919Sxy150489  */
16894919Sxy150489 s32
16904919Sxy150489 e1000_check_polarity_m88(struct e1000_hw *hw)
16914919Sxy150489 {
16924919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
16934919Sxy150489 	s32 ret_val;
16944919Sxy150489 	u16 data;
16954919Sxy150489 
16964919Sxy150489 	DEBUGFUNC("e1000_check_polarity_m88");
16974919Sxy150489 
16986735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
16994919Sxy150489 
17004919Sxy150489 	if (!ret_val)
17014919Sxy150489 		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
17024919Sxy150489 		    ? e1000_rev_polarity_reversed
17034919Sxy150489 		    : e1000_rev_polarity_normal;
17044919Sxy150489 
17054919Sxy150489 	return (ret_val);
17064919Sxy150489 }
17074919Sxy150489 
17084919Sxy150489 /*
17094919Sxy150489  * e1000_check_polarity_igp - Checks the polarity.
17104919Sxy150489  * @hw: pointer to the HW structure
17114919Sxy150489  *
17124919Sxy150489  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
17134919Sxy150489  *
17144919Sxy150489  * Polarity is determined based on the PHY port status register, and the
17154919Sxy150489  * current speed (since there is no polarity at 100Mbps).
17164919Sxy150489  */
17174919Sxy150489 s32
17184919Sxy150489 e1000_check_polarity_igp(struct e1000_hw *hw)
17194919Sxy150489 {
17204919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
17214919Sxy150489 	s32 ret_val;
17224919Sxy150489 	u16 data, offset, mask;
17234919Sxy150489 
17244919Sxy150489 	DEBUGFUNC("e1000_check_polarity_igp");
17254919Sxy150489 
17264919Sxy150489 	/*
17274919Sxy150489 	 * Polarity is determined based on the speed of our connection.
17284919Sxy150489 	 */
17296735Scc210113 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
17304919Sxy150489 	if (ret_val)
17314919Sxy150489 		goto out;
17324919Sxy150489 
17334919Sxy150489 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
17344919Sxy150489 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
17354919Sxy150489 		offset = IGP01E1000_PHY_PCS_INIT_REG;
17364919Sxy150489 		mask = IGP01E1000_PHY_POLARITY_MASK;
17374919Sxy150489 	} else {
17384919Sxy150489 		/*
17394919Sxy150489 		 * This really only applies to 10Mbps since there is no
17404919Sxy150489 		 * polarity for 100Mbps (always 0).
17414919Sxy150489 		 */
17424919Sxy150489 		offset = IGP01E1000_PHY_PORT_STATUS;
17434919Sxy150489 		mask = IGP01E1000_PSSR_POLARITY_REVERSED;
17444919Sxy150489 	}
17454919Sxy150489 
17466735Scc210113 	ret_val = phy->ops.read_reg(hw, offset, &data);
17474919Sxy150489 
17484919Sxy150489 	if (!ret_val)
17494919Sxy150489 		phy->cable_polarity = (data & mask)
17504919Sxy150489 		    ? e1000_rev_polarity_reversed
17514919Sxy150489 		    : e1000_rev_polarity_normal;
17524919Sxy150489 
17534919Sxy150489 out:
17544919Sxy150489 	return (ret_val);
17554919Sxy150489 }
17564919Sxy150489 
17574919Sxy150489 /*
1758*10680SMin.Xu@Sun.COM  * e1000_check_polarity_ife - Check cable polarity for IFE PHY
1759*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
1760*10680SMin.Xu@Sun.COM  *
1761*10680SMin.Xu@Sun.COM  * Polarity is determined on the polarity reversal feature being enabled.
1762*10680SMin.Xu@Sun.COM  */
1763*10680SMin.Xu@Sun.COM s32
1764*10680SMin.Xu@Sun.COM e1000_check_polarity_ife(struct e1000_hw *hw)
1765*10680SMin.Xu@Sun.COM {
1766*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
1767*10680SMin.Xu@Sun.COM 	s32 ret_val;
1768*10680SMin.Xu@Sun.COM 	u16 phy_data, offset, mask;
1769*10680SMin.Xu@Sun.COM 
1770*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_check_polarity_ife");
1771*10680SMin.Xu@Sun.COM 
1772*10680SMin.Xu@Sun.COM 	/*
1773*10680SMin.Xu@Sun.COM 	 * Polarity is determined based on the reversal feature being enabled.
1774*10680SMin.Xu@Sun.COM 	 */
1775*10680SMin.Xu@Sun.COM 	if (phy->polarity_correction) {
1776*10680SMin.Xu@Sun.COM 		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
1777*10680SMin.Xu@Sun.COM 		mask = IFE_PESC_POLARITY_REVERSED;
1778*10680SMin.Xu@Sun.COM 	} else {
1779*10680SMin.Xu@Sun.COM 		offset = IFE_PHY_SPECIAL_CONTROL;
1780*10680SMin.Xu@Sun.COM 		mask = IFE_PSC_FORCE_POLARITY;
1781*10680SMin.Xu@Sun.COM 	}
1782*10680SMin.Xu@Sun.COM 
1783*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
1784*10680SMin.Xu@Sun.COM 
1785*10680SMin.Xu@Sun.COM 	if (!ret_val)
1786*10680SMin.Xu@Sun.COM 		phy->cable_polarity = (phy_data & mask)
1787*10680SMin.Xu@Sun.COM 		    ? e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
1788*10680SMin.Xu@Sun.COM 
1789*10680SMin.Xu@Sun.COM 	return (ret_val);
1790*10680SMin.Xu@Sun.COM }
1791*10680SMin.Xu@Sun.COM 
1792*10680SMin.Xu@Sun.COM /*
17936735Scc210113  * e1000_wait_autoneg_generic - Wait for auto-neg completion
17944919Sxy150489  * @hw: pointer to the HW structure
17954919Sxy150489  *
17964919Sxy150489  * Waits for auto-negotiation to complete or for the auto-negotiation time
17974919Sxy150489  * limit to expire, which ever happens first.
17984919Sxy150489  */
17994919Sxy150489 s32
18004919Sxy150489 e1000_wait_autoneg_generic(struct e1000_hw *hw)
18014919Sxy150489 {
18024919Sxy150489 	s32 ret_val = E1000_SUCCESS;
18034919Sxy150489 	u16 i, phy_status;
18044919Sxy150489 
18054919Sxy150489 	DEBUGFUNC("e1000_wait_autoneg_generic");
18064919Sxy150489 
18076735Scc210113 	if (!(hw->phy.ops.read_reg))
18086735Scc210113 		return (E1000_SUCCESS);
18096735Scc210113 
18104919Sxy150489 	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
18114919Sxy150489 	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
18126735Scc210113 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
18134919Sxy150489 		if (ret_val)
18144919Sxy150489 			break;
18156735Scc210113 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
18164919Sxy150489 		if (ret_val)
18174919Sxy150489 			break;
18184919Sxy150489 		if (phy_status & MII_SR_AUTONEG_COMPLETE)
18194919Sxy150489 			break;
18204919Sxy150489 		msec_delay(100);
18214919Sxy150489 	}
18224919Sxy150489 
18234919Sxy150489 	/*
18244919Sxy150489 	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation has
18254919Sxy150489 	 * completed.
18264919Sxy150489 	 */
18274919Sxy150489 	return (ret_val);
18284919Sxy150489 }
18294919Sxy150489 
18304919Sxy150489 /*
18314919Sxy150489  * e1000_phy_has_link_generic - Polls PHY for link
18324919Sxy150489  * @hw: pointer to the HW structure
18334919Sxy150489  * @iterations: number of times to poll for link
18344919Sxy150489  * @usec_interval: delay between polling attempts
18354919Sxy150489  * @success: pointer to whether polling was successful or not
18364919Sxy150489  *
18374919Sxy150489  * Polls the PHY status register for link, 'iterations' number of times.
18384919Sxy150489  */
18394919Sxy150489 s32
18404919Sxy150489 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
18416735Scc210113     u32 usec_interval, bool *success)
18424919Sxy150489 {
18434919Sxy150489 	s32 ret_val = E1000_SUCCESS;
18444919Sxy150489 	u16 i, phy_status;
18454919Sxy150489 
18464919Sxy150489 	DEBUGFUNC("e1000_phy_has_link_generic");
18474919Sxy150489 
18486735Scc210113 	if (!(hw->phy.ops.read_reg))
18496735Scc210113 		return (E1000_SUCCESS);
18506735Scc210113 
18514919Sxy150489 	for (i = 0; i < iterations; i++) {
18524919Sxy150489 		/*
18534919Sxy150489 		 * Some PHYs require the PHY_STATUS register to be read twice
18544919Sxy150489 		 * due to the link bit being sticky.  No harm doing it across
18554919Sxy150489 		 * the board.
18564919Sxy150489 		 */
18576735Scc210113 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
1858*10680SMin.Xu@Sun.COM 		if (ret_val) {
1859*10680SMin.Xu@Sun.COM 			/*
1860*10680SMin.Xu@Sun.COM 			 * If the first read fails, another entity may have
1861*10680SMin.Xu@Sun.COM 			 * ownership of the resources, wait and try again to
1862*10680SMin.Xu@Sun.COM 			 * see if they have relinquished the resources yet.
1863*10680SMin.Xu@Sun.COM 			 */
1864*10680SMin.Xu@Sun.COM 			usec_delay(usec_interval);
1865*10680SMin.Xu@Sun.COM 		}
1866*10680SMin.Xu@Sun.COM 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
1867*10680SMin.Xu@Sun.COM 		    &phy_status);
18684919Sxy150489 		if (ret_val)
18694919Sxy150489 			break;
18704919Sxy150489 		if (phy_status & MII_SR_LINK_STATUS)
18714919Sxy150489 			break;
18724919Sxy150489 		if (usec_interval >= 1000)
18734919Sxy150489 			msec_delay_irq(usec_interval / 1000);
18744919Sxy150489 		else
18754919Sxy150489 			usec_delay(usec_interval);
18764919Sxy150489 	}
18774919Sxy150489 
18787607STed.You@Sun.COM 	*success = (i < iterations) ? true : false;
18794919Sxy150489 
18804919Sxy150489 	return (ret_val);
18814919Sxy150489 }
18824919Sxy150489 
18834919Sxy150489 /*
18844919Sxy150489  * e1000_get_cable_length_m88 - Determine cable length for m88 PHY
18854919Sxy150489  * @hw: pointer to the HW structure
18864919Sxy150489  *
18874919Sxy150489  * Reads the PHY specific status register to retrieve the cable length
18884919Sxy150489  * information.  The cable length is determined by averaging the minimum and
18894919Sxy150489  * maximum values to get the "average" cable length.  The m88 PHY has four
18904919Sxy150489  * possible cable length values, which are:
18914919Sxy150489  *	Register Value		Cable Length
18924919Sxy150489  *	0			< 50 meters
18934919Sxy150489  *	1			50 - 80 meters
18944919Sxy150489  *	2			80 - 110 meters
18954919Sxy150489  *	3			110 - 140 meters
18964919Sxy150489  *	4			> 140 meters
18974919Sxy150489  */
18984919Sxy150489 s32
18994919Sxy150489 e1000_get_cable_length_m88(struct e1000_hw *hw)
19004919Sxy150489 {
19014919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
19024919Sxy150489 	s32 ret_val;
19034919Sxy150489 	u16 phy_data, index;
19044919Sxy150489 
19054919Sxy150489 	DEBUGFUNC("e1000_get_cable_length_m88");
19064919Sxy150489 
19076735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
19084919Sxy150489 	if (ret_val)
19094919Sxy150489 		goto out;
19104919Sxy150489 
19114919Sxy150489 	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
19124919Sxy150489 	    M88E1000_PSSR_CABLE_LENGTH_SHIFT;
19138479SChenlu.Chen@Sun.COM 
1914*10680SMin.Xu@Sun.COM 	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
19158479SChenlu.Chen@Sun.COM 		ret_val = E1000_ERR_PHY;
1916*10680SMin.Xu@Sun.COM 		goto out;
19178479SChenlu.Chen@Sun.COM 	}
1918*10680SMin.Xu@Sun.COM 	phy->min_cable_length = e1000_m88_cable_length_table[index];
1919*10680SMin.Xu@Sun.COM 	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
1920*10680SMin.Xu@Sun.COM 
1921*10680SMin.Xu@Sun.COM 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
19224919Sxy150489 
19234919Sxy150489 out:
19244919Sxy150489 	return (ret_val);
19254919Sxy150489 }
19264919Sxy150489 
19274919Sxy150489 /*
19284919Sxy150489  * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
19294919Sxy150489  * @hw: pointer to the HW structure
19304919Sxy150489  *
19314919Sxy150489  * The automatic gain control (agc) normalizes the amplitude of the
19324919Sxy150489  * received signal, adjusting for the attenuation produced by the
19336735Scc210113  * cable.  By reading the AGC registers, which represent the
19346735Scc210113  * combination of coarse and fine gain value, the value can be put
19354919Sxy150489  * into a lookup table to obtain the approximate cable length
19364919Sxy150489  * for each channel.
19374919Sxy150489  */
19384919Sxy150489 s32
19394919Sxy150489 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
19404919Sxy150489 {
19414919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
19426735Scc210113 	s32 ret_val = E1000_SUCCESS;
19434919Sxy150489 	u16 phy_data, i, agc_value = 0;
19444919Sxy150489 	u16 cur_agc_index, max_agc_index = 0;
19454919Sxy150489 	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
19464919Sxy150489 	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
19474919Sxy150489 		{IGP02E1000_PHY_AGC_A,
19484919Sxy150489 		IGP02E1000_PHY_AGC_B,
19494919Sxy150489 		IGP02E1000_PHY_AGC_C,
19504919Sxy150489 		IGP02E1000_PHY_AGC_D};
19514919Sxy150489 
19524919Sxy150489 	DEBUGFUNC("e1000_get_cable_length_igp_2");
19534919Sxy150489 
19544919Sxy150489 	/* Read the AGC registers for all channels */
19554919Sxy150489 	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
19566735Scc210113 		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
19574919Sxy150489 		if (ret_val)
19584919Sxy150489 			goto out;
19594919Sxy150489 
19604919Sxy150489 		/*
19614919Sxy150489 		 * Getting bits 15:9, which represent the combination of
19626735Scc210113 		 * coarse and fine gain values.  The result is a number that
19634919Sxy150489 		 * can be put into the lookup table to obtain the approximate
19644919Sxy150489 		 * cable length.
19654919Sxy150489 		 */
19664919Sxy150489 		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
19674919Sxy150489 		    IGP02E1000_AGC_LENGTH_MASK;
19684919Sxy150489 
19694919Sxy150489 		/* Array index bound check. */
19704919Sxy150489 		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
19714919Sxy150489 		    (cur_agc_index == 0)) {
19724919Sxy150489 			ret_val = -E1000_ERR_PHY;
19734919Sxy150489 			goto out;
19744919Sxy150489 		}
19754919Sxy150489 
19764919Sxy150489 		/* Remove min & max AGC values from calculation. */
19774919Sxy150489 		if (e1000_igp_2_cable_length_table[min_agc_index] >
19784919Sxy150489 		    e1000_igp_2_cable_length_table[cur_agc_index])
19794919Sxy150489 			min_agc_index = cur_agc_index;
19804919Sxy150489 		if (e1000_igp_2_cable_length_table[max_agc_index] <
19814919Sxy150489 		    e1000_igp_2_cable_length_table[cur_agc_index])
19824919Sxy150489 			max_agc_index = cur_agc_index;
19834919Sxy150489 
19844919Sxy150489 		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
19854919Sxy150489 	}
19864919Sxy150489 
19874919Sxy150489 	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
19884919Sxy150489 	    e1000_igp_2_cable_length_table[max_agc_index]);
19894919Sxy150489 	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
19904919Sxy150489 
19914919Sxy150489 	/* Calculate cable length with the error range of +/- 10 meters. */
19924919Sxy150489 	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
19934919Sxy150489 	    (agc_value - IGP02E1000_AGC_RANGE) : 0;
19944919Sxy150489 	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
19954919Sxy150489 
19964919Sxy150489 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
19974919Sxy150489 
19984919Sxy150489 out:
19994919Sxy150489 	return (ret_val);
20004919Sxy150489 }
20014919Sxy150489 
20024919Sxy150489 /*
20034919Sxy150489  * e1000_get_phy_info_m88 - Retrieve PHY information
20044919Sxy150489  * @hw: pointer to the HW structure
20054919Sxy150489  *
20064919Sxy150489  * Valid for only copper links.  Read the PHY status register (sticky read)
20074919Sxy150489  * to verify that link is up.  Read the PHY special control register to
20084919Sxy150489  * determine the polarity and 10base-T extended distance.  Read the PHY
20094919Sxy150489  * special status register to determine MDI/MDIx and current speed.  If
20104919Sxy150489  * speed is 1000, then determine cable length, local and remote receiver.
20114919Sxy150489  */
20124919Sxy150489 s32
20134919Sxy150489 e1000_get_phy_info_m88(struct e1000_hw *hw)
20144919Sxy150489 {
20154919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
20164919Sxy150489 	s32 ret_val;
20174919Sxy150489 	u16 phy_data;
20186735Scc210113 	bool link;
20194919Sxy150489 
20204919Sxy150489 	DEBUGFUNC("e1000_get_phy_info_m88");
20214919Sxy150489 
20226735Scc210113 	if (hw->phy.media_type != e1000_media_type_copper) {
20234919Sxy150489 		DEBUGOUT("Phy info is only valid for copper media\n");
20244919Sxy150489 		ret_val = -E1000_ERR_CONFIG;
20254919Sxy150489 		goto out;
20264919Sxy150489 	}
20274919Sxy150489 
20284919Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
20294919Sxy150489 	if (ret_val)
20304919Sxy150489 		goto out;
20314919Sxy150489 
20324919Sxy150489 	if (!link) {
20334919Sxy150489 		DEBUGOUT("Phy info is only valid if link is up\n");
20344919Sxy150489 		ret_val = -E1000_ERR_CONFIG;
20354919Sxy150489 		goto out;
20364919Sxy150489 	}
20374919Sxy150489 
20386735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
20394919Sxy150489 	if (ret_val)
20404919Sxy150489 		goto out;
20414919Sxy150489 
20424919Sxy150489 	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
20437607STed.You@Sun.COM 	    ? true
20447607STed.You@Sun.COM 	    : false;
20454919Sxy150489 
20464919Sxy150489 	ret_val = e1000_check_polarity_m88(hw);
20474919Sxy150489 	if (ret_val)
20484919Sxy150489 		goto out;
20494919Sxy150489 
20506735Scc210113 	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
20514919Sxy150489 	if (ret_val)
20524919Sxy150489 		goto out;
20534919Sxy150489 
20547607STed.You@Sun.COM 	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
20554919Sxy150489 
20564919Sxy150489 	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
20577607STed.You@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
20584919Sxy150489 		if (ret_val)
20594919Sxy150489 			goto out;
20604919Sxy150489 
20616735Scc210113 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
20624919Sxy150489 		if (ret_val)
20634919Sxy150489 			goto out;
20644919Sxy150489 
20654919Sxy150489 		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
20664919Sxy150489 		    ? e1000_1000t_rx_status_ok
20674919Sxy150489 		    : e1000_1000t_rx_status_not_ok;
20684919Sxy150489 
20694919Sxy150489 		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
20704919Sxy150489 		    ? e1000_1000t_rx_status_ok
20714919Sxy150489 		    : e1000_1000t_rx_status_not_ok;
20724919Sxy150489 	} else {
20734919Sxy150489 		/* Set values to "undefined" */
20744919Sxy150489 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
20754919Sxy150489 		phy->local_rx = e1000_1000t_rx_status_undefined;
20764919Sxy150489 		phy->remote_rx = e1000_1000t_rx_status_undefined;
20774919Sxy150489 	}
20784919Sxy150489 
20794919Sxy150489 out:
20804919Sxy150489 	return (ret_val);
20814919Sxy150489 }
20824919Sxy150489 
20834919Sxy150489 /*
20844919Sxy150489  * e1000_get_phy_info_igp - Retrieve igp PHY information
20854919Sxy150489  * @hw: pointer to the HW structure
20864919Sxy150489  *
20874919Sxy150489  * Read PHY status to determine if link is up.  If link is up, then
20884919Sxy150489  * set/determine 10base-T extended distance and polarity correction.  Read
20894919Sxy150489  * PHY port status to determine MDI/MDIx and speed.  Based on the speed,
20904919Sxy150489  * determine on the cable length, local and remote receiver.
20914919Sxy150489  */
20924919Sxy150489 s32
20934919Sxy150489 e1000_get_phy_info_igp(struct e1000_hw *hw)
20944919Sxy150489 {
20954919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
20964919Sxy150489 	s32 ret_val;
20974919Sxy150489 	u16 data;
20986735Scc210113 	bool link;
20994919Sxy150489 
21004919Sxy150489 	DEBUGFUNC("e1000_get_phy_info_igp");
21014919Sxy150489 
21024919Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
21034919Sxy150489 	if (ret_val)
21044919Sxy150489 		goto out;
21054919Sxy150489 
21064919Sxy150489 	if (!link) {
21074919Sxy150489 		DEBUGOUT("Phy info is only valid if link is up\n");
21084919Sxy150489 		ret_val = -E1000_ERR_CONFIG;
21094919Sxy150489 		goto out;
21104919Sxy150489 	}
21114919Sxy150489 
21127607STed.You@Sun.COM 	phy->polarity_correction = true;
21134919Sxy150489 
21144919Sxy150489 	ret_val = e1000_check_polarity_igp(hw);
21154919Sxy150489 	if (ret_val)
21164919Sxy150489 		goto out;
21174919Sxy150489 
21186735Scc210113 	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
21194919Sxy150489 	if (ret_val)
21204919Sxy150489 		goto out;
21214919Sxy150489 
21227607STed.You@Sun.COM 	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
21234919Sxy150489 
21244919Sxy150489 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
21254919Sxy150489 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
21267607STed.You@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
21274919Sxy150489 		if (ret_val)
21284919Sxy150489 			goto out;
21294919Sxy150489 
21306735Scc210113 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
21314919Sxy150489 		if (ret_val)
21324919Sxy150489 			goto out;
21334919Sxy150489 
21344919Sxy150489 		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
21354919Sxy150489 		    ? e1000_1000t_rx_status_ok
21364919Sxy150489 		    : e1000_1000t_rx_status_not_ok;
21374919Sxy150489 
21384919Sxy150489 		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
21394919Sxy150489 		    ? e1000_1000t_rx_status_ok
21404919Sxy150489 		    : e1000_1000t_rx_status_not_ok;
21414919Sxy150489 	} else {
21424919Sxy150489 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
21434919Sxy150489 		phy->local_rx = e1000_1000t_rx_status_undefined;
21444919Sxy150489 		phy->remote_rx = e1000_1000t_rx_status_undefined;
21454919Sxy150489 	}
21464919Sxy150489 
21474919Sxy150489 out:
21484919Sxy150489 	return (ret_val);
21494919Sxy150489 }
21504919Sxy150489 
21514919Sxy150489 /*
21524919Sxy150489  * e1000_phy_sw_reset_generic - PHY software reset
21534919Sxy150489  * @hw: pointer to the HW structure
21544919Sxy150489  *
21554919Sxy150489  * Does a software reset of the PHY by reading the PHY control register and
21564919Sxy150489  * setting/write the control register reset bit to the PHY.
21574919Sxy150489  */
21584919Sxy150489 s32
21594919Sxy150489 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
21604919Sxy150489 {
21616735Scc210113 	s32 ret_val = E1000_SUCCESS;
21624919Sxy150489 	u16 phy_ctrl;
21634919Sxy150489 
21644919Sxy150489 	DEBUGFUNC("e1000_phy_sw_reset_generic");
21654919Sxy150489 
21666735Scc210113 	if (!(hw->phy.ops.read_reg))
21676735Scc210113 		goto out;
21686735Scc210113 
21696735Scc210113 	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
21704919Sxy150489 	if (ret_val)
21714919Sxy150489 		goto out;
21724919Sxy150489 
21734919Sxy150489 	phy_ctrl |= MII_CR_RESET;
21746735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
21754919Sxy150489 	if (ret_val)
21764919Sxy150489 		goto out;
21774919Sxy150489 
21784919Sxy150489 	usec_delay(1);
21794919Sxy150489 
21804919Sxy150489 out:
21814919Sxy150489 	return (ret_val);
21824919Sxy150489 }
21834919Sxy150489 
21844919Sxy150489 /*
21854919Sxy150489  * e1000_phy_hw_reset_generic - PHY hardware reset
21864919Sxy150489  * @hw: pointer to the HW structure
21874919Sxy150489  *
21884919Sxy150489  * Verify the reset block is not blocking us from resetting.  Acquire
21894919Sxy150489  * semaphore (if necessary) and read/set/write the device control reset
21904919Sxy150489  * bit in the PHY.  Wait the appropriate delay time for the device to
21916735Scc210113  * reset and release the semaphore (if necessary).
21924919Sxy150489  */
21934919Sxy150489 s32
21944919Sxy150489 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
21954919Sxy150489 {
21964919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
21976735Scc210113 	s32 ret_val = E1000_SUCCESS;
21984919Sxy150489 	u32 ctrl;
21994919Sxy150489 
22004919Sxy150489 	DEBUGFUNC("e1000_phy_hw_reset_generic");
22014919Sxy150489 
22026735Scc210113 	ret_val = phy->ops.check_reset_block(hw);
22034919Sxy150489 	if (ret_val) {
22044919Sxy150489 		ret_val = E1000_SUCCESS;
22054919Sxy150489 		goto out;
22064919Sxy150489 	}
22074919Sxy150489 
22086735Scc210113 	ret_val = phy->ops.acquire(hw);
22094919Sxy150489 	if (ret_val)
22104919Sxy150489 		goto out;
22114919Sxy150489 
22124919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
22134919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
22144919Sxy150489 	E1000_WRITE_FLUSH(hw);
22154919Sxy150489 
22164919Sxy150489 	usec_delay(phy->reset_delay_us);
22174919Sxy150489 
22184919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
22194919Sxy150489 	E1000_WRITE_FLUSH(hw);
22204919Sxy150489 
22214919Sxy150489 	usec_delay(150);
22224919Sxy150489 
22236735Scc210113 	phy->ops.release(hw);
22244919Sxy150489 
22256735Scc210113 	ret_val = phy->ops.get_cfg_done(hw);
22264919Sxy150489 
22274919Sxy150489 out:
22284919Sxy150489 	return (ret_val);
22294919Sxy150489 }
22304919Sxy150489 
22314919Sxy150489 /*
22324919Sxy150489  * e1000_get_cfg_done_generic - Generic configuration done
22334919Sxy150489  * @hw: pointer to the HW structure
22344919Sxy150489  *
22354919Sxy150489  * Generic function to wait 10 milli-seconds for configuration to complete
22364919Sxy150489  * and return success.
22374919Sxy150489  */
22384919Sxy150489 s32
22394919Sxy150489 e1000_get_cfg_done_generic(struct e1000_hw *hw)
22404919Sxy150489 {
22414919Sxy150489 	DEBUGFUNC("e1000_get_cfg_done_generic");
22426735Scc210113 	UNREFERENCED_1PARAMETER(hw);
22434919Sxy150489 
22444919Sxy150489 	msec_delay_irq(10);
22454919Sxy150489 
22464919Sxy150489 	return (E1000_SUCCESS);
22474919Sxy150489 }
22484919Sxy150489 
22494919Sxy150489 /*
22504919Sxy150489  * e1000_phy_init_script_igp3 - Inits the IGP3 PHY
22514919Sxy150489  * @hw: pointer to the HW structure
22524919Sxy150489  *
22534919Sxy150489  * Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
22544919Sxy150489  */
22554919Sxy150489 s32
22564919Sxy150489 e1000_phy_init_script_igp3(struct e1000_hw *hw)
22574919Sxy150489 {
22584919Sxy150489 	DEBUGOUT("Running IGP 3 PHY init script\n");
22594919Sxy150489 
22604919Sxy150489 	/* PHY init IGP 3 */
22614919Sxy150489 	/* Enable rise/fall, 10-mode work in class-A */
22626735Scc210113 	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
22634919Sxy150489 	/* Remove all caps from Replica path filter */
22646735Scc210113 	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
22654919Sxy150489 	/* Bias trimming for ADC, AFE and Driver (Default) */
22666735Scc210113 	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
22674919Sxy150489 	/* Increase Hybrid poly bias */
22686735Scc210113 	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
22694919Sxy150489 	/* Add 4% to TX amplitude in Giga mode */
22706735Scc210113 	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
22714919Sxy150489 	/* Disable trimming (TTT) */
22726735Scc210113 	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
22734919Sxy150489 	/* Poly DC correction to 94.6% + 2% for all channels */
22746735Scc210113 	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
22754919Sxy150489 	/* ABS DC correction to 95.9% */
22766735Scc210113 	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
22774919Sxy150489 	/* BG temp curve trim */
22786735Scc210113 	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
22794919Sxy150489 	/* Increasing ADC OPAMP stage 1 currents to max */
22806735Scc210113 	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
22814919Sxy150489 	/* Force 1000 ( required for enabling PHY regs configuration) */
22826735Scc210113 	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
22834919Sxy150489 	/* Set upd_freq to 6 */
22846735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
22854919Sxy150489 	/* Disable NPDFE */
22866735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
22874919Sxy150489 	/* Disable adaptive fixed FFE (Default) */
22886735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
22894919Sxy150489 	/* Enable FFE hysteresis */
22906735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
22914919Sxy150489 	/* Fixed FFE for short cable lengths */
22926735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
22934919Sxy150489 	/* Fixed FFE for medium cable lengths */
22946735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
22954919Sxy150489 	/* Fixed FFE for long cable lengths */
22966735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
22974919Sxy150489 	/* Enable Adaptive Clip Threshold */
22986735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
22994919Sxy150489 	/* AHT reset limit to 1 */
23006735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
23014919Sxy150489 	/* Set AHT master delay to 127 msec */
23026735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
23034919Sxy150489 	/* Set scan bits for AHT */
23046735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
23054919Sxy150489 	/* Set AHT Preset bits */
23066735Scc210113 	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
23074919Sxy150489 	/* Change integ_factor of channel A to 3 */
23086735Scc210113 	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
23094919Sxy150489 	/* Change prop_factor of channels BCD to 8 */
23106735Scc210113 	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
23114919Sxy150489 	/* Change cg_icount + enable integbp for channels BCD */
23126735Scc210113 	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
23134919Sxy150489 	/*
23144919Sxy150489 	 * Change cg_icount + enable integbp + change prop_factor_master to 8
23154919Sxy150489 	 * for channel A
23164919Sxy150489 	 */
23176735Scc210113 	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
23184919Sxy150489 	/* Disable AHT in Slave mode on channel A */
23196735Scc210113 	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
23204919Sxy150489 	/*
23214919Sxy150489 	 * Enable LPLU and disable AN to 1000 in non-D0a states, Enable
23224919Sxy150489 	 * SPD+B2B
23234919Sxy150489 	 */
23246735Scc210113 	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
23254919Sxy150489 	/* Enable restart AN on an1000_dis change */
23266735Scc210113 	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
23274919Sxy150489 	/* Enable wh_fifo read clock in 10/100 modes */
23286735Scc210113 	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
23294919Sxy150489 	/* Restart AN, Speed selection is 1000 */
23306735Scc210113 	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
23314919Sxy150489 
23324919Sxy150489 	return (E1000_SUCCESS);
23334919Sxy150489 }
23344919Sxy150489 
23354919Sxy150489 /*
23364919Sxy150489  * e1000_get_phy_type_from_id - Get PHY type from id
23374919Sxy150489  * @phy_id: phy_id read from the phy
23384919Sxy150489  *
23394919Sxy150489  * Returns the phy type from the id.
23404919Sxy150489  */
23418479SChenlu.Chen@Sun.COM enum e1000_phy_type
23424919Sxy150489 e1000_get_phy_type_from_id(u32 phy_id)
23434919Sxy150489 {
23448479SChenlu.Chen@Sun.COM 	enum e1000_phy_type phy_type = e1000_phy_unknown;
23454919Sxy150489 
23464919Sxy150489 	switch (phy_id) {
23474919Sxy150489 	case M88E1000_I_PHY_ID:
23484919Sxy150489 	case M88E1000_E_PHY_ID:
23494919Sxy150489 	case M88E1111_I_PHY_ID:
23504919Sxy150489 	case M88E1011_I_PHY_ID:
23514919Sxy150489 		phy_type = e1000_phy_m88;
23524919Sxy150489 		break;
23534919Sxy150489 	case IGP01E1000_I_PHY_ID:	/* IGP 1 & 2 share this */
23544919Sxy150489 		phy_type = e1000_phy_igp_2;
23554919Sxy150489 		break;
23564919Sxy150489 	case GG82563_E_PHY_ID:
23574919Sxy150489 		phy_type = e1000_phy_gg82563;
23584919Sxy150489 		break;
23594919Sxy150489 	case IGP03E1000_E_PHY_ID:
23604919Sxy150489 		phy_type = e1000_phy_igp_3;
23614919Sxy150489 		break;
23624919Sxy150489 	case IFE_E_PHY_ID:
23634919Sxy150489 	case IFE_PLUS_E_PHY_ID:
23644919Sxy150489 	case IFE_C_E_PHY_ID:
23654919Sxy150489 		phy_type = e1000_phy_ife;
23664919Sxy150489 		break;
23674919Sxy150489 	case BME1000_E_PHY_ID:
23686735Scc210113 	case BME1000_E_PHY_ID_R2:
23694919Sxy150489 		phy_type = e1000_phy_bm;
23704919Sxy150489 		break;
2371*10680SMin.Xu@Sun.COM 	case I82578_E_PHY_ID:
2372*10680SMin.Xu@Sun.COM 		phy_type = e1000_phy_82578;
2373*10680SMin.Xu@Sun.COM 		break;
2374*10680SMin.Xu@Sun.COM 	case I82577_E_PHY_ID:
2375*10680SMin.Xu@Sun.COM 		phy_type = e1000_phy_82577;
2376*10680SMin.Xu@Sun.COM 		break;
23774919Sxy150489 	default:
23784919Sxy150489 		phy_type = e1000_phy_unknown;
23794919Sxy150489 		break;
23804919Sxy150489 	}
23814919Sxy150489 	return (phy_type);
23824919Sxy150489 }
23834919Sxy150489 
23844919Sxy150489 /*
23854919Sxy150489  * e1000_determine_phy_address - Determines PHY address.
23864919Sxy150489  * @hw: pointer to the HW structure
23874919Sxy150489  *
23884919Sxy150489  * This uses a trial and error method to loop through possible PHY
23894919Sxy150489  * addresses. It tests each by reading the PHY ID registers and
23904919Sxy150489  * checking for a match.
23914919Sxy150489  */
23924919Sxy150489 s32
23934919Sxy150489 e1000_determine_phy_address(struct e1000_hw *hw)
23944919Sxy150489 {
23954919Sxy150489 	s32 ret_val = -E1000_ERR_PHY_TYPE;
23964919Sxy150489 	u32 phy_addr = 0;
23976735Scc210113 	u32 i;
23988479SChenlu.Chen@Sun.COM 	enum e1000_phy_type phy_type = e1000_phy_unknown;
23994919Sxy150489 
2400*10680SMin.Xu@Sun.COM 	hw->phy.id = phy_type;
2401*10680SMin.Xu@Sun.COM 
24026735Scc210113 	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
24034919Sxy150489 		hw->phy.addr = phy_addr;
24046735Scc210113 		i = 0;
24056735Scc210113 
24066735Scc210113 		do {
24077426SChenliang.Xu@Sun.COM 			(void) e1000_get_phy_id(hw);
24086735Scc210113 			phy_type = e1000_get_phy_type_from_id(hw->phy.id);
24094919Sxy150489 
24106735Scc210113 			/*
24116735Scc210113 			 * If phy_type is valid, break - we found our
24126735Scc210113 			 * PHY address
24136735Scc210113 			 */
24146735Scc210113 			if (phy_type != e1000_phy_unknown) {
24156735Scc210113 				ret_val = E1000_SUCCESS;
24166735Scc210113 				goto out;
24176735Scc210113 			}
24186735Scc210113 			msec_delay(1);
24196735Scc210113 			i++;
24206735Scc210113 		} while (i < 10);
24214919Sxy150489 	}
24224919Sxy150489 
24236735Scc210113 out:
24244919Sxy150489 	return (ret_val);
24254919Sxy150489 }
24264919Sxy150489 
24274919Sxy150489 /*
24284919Sxy150489  * e1000_get_phy_addr_for_bm_page - Retrieve PHY page address
24294919Sxy150489  * @page: page to access
24304919Sxy150489  *
24314919Sxy150489  * Returns the phy address for the page requested.
24324919Sxy150489  */
24334919Sxy150489 static u32
24344919Sxy150489 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg)
24354919Sxy150489 {
24364919Sxy150489 	u32 phy_addr = 2;
24374919Sxy150489 
24384919Sxy150489 	if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
24394919Sxy150489 		phy_addr = 1;
24404919Sxy150489 
24414919Sxy150489 	return (phy_addr);
24424919Sxy150489 }
24434919Sxy150489 
24444919Sxy150489 /*
24454919Sxy150489  * e1000_write_phy_reg_bm - Write BM PHY register
24464919Sxy150489  * @hw: pointer to the HW structure
24474919Sxy150489  * @offset: register offset to write to
24484919Sxy150489  * @data: data to write at register offset
24494919Sxy150489  *
24504919Sxy150489  * Acquires semaphore, if necessary, then writes the data to PHY register
24514919Sxy150489  * at the offset.  Release any acquired semaphores before exiting.
24524919Sxy150489  */
24534919Sxy150489 s32
24544919Sxy150489 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
24554919Sxy150489 {
24564919Sxy150489 	s32 ret_val;
24574919Sxy150489 	u32 page_select = 0;
24584919Sxy150489 	u32 page = offset >> IGP_PAGE_SHIFT;
24594919Sxy150489 	u32 page_shift = 0;
24604919Sxy150489 
24614919Sxy150489 	DEBUGFUNC("e1000_write_phy_reg_bm");
24624919Sxy150489 
24634919Sxy150489 	/* Page 800 works differently than the rest so it has its own func */
24644919Sxy150489 	if (page == BM_WUC_PAGE) {
24654919Sxy150489 		ret_val = e1000_access_phy_wakeup_reg_bm(hw,
24667607STed.You@Sun.COM 		    offset, &data, false);
24674919Sxy150489 		goto out;
24684919Sxy150489 	}
24696735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
24704919Sxy150489 	if (ret_val)
24714919Sxy150489 		goto out;
24724919Sxy150489 
24734919Sxy150489 	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
24744919Sxy150489 
24754919Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
24764919Sxy150489 		/*
24774919Sxy150489 		 * Page select is register 31 for phy address 1 and 22 for phy
24784919Sxy150489 		 * address 2 and 3. Page select is shifted only for phy
24794919Sxy150489 		 * address 1.
24804919Sxy150489 		 */
24814919Sxy150489 		if (hw->phy.addr == 1) {
24824919Sxy150489 			page_shift = IGP_PAGE_SHIFT;
24834919Sxy150489 			page_select = IGP01E1000_PHY_PAGE_SELECT;
24844919Sxy150489 		} else {
24854919Sxy150489 			page_shift = 0;
24864919Sxy150489 			page_select = BM_PHY_PAGE_SELECT;
24874919Sxy150489 		}
24884919Sxy150489 
24894919Sxy150489 		/* Page is shifted left, PHY expects (page x 32) */
24904919Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw, page_select,
24914919Sxy150489 		    (page << page_shift));
24924919Sxy150489 		if (ret_val) {
24936735Scc210113 			hw->phy.ops.release(hw);
24944919Sxy150489 			goto out;
24954919Sxy150489 		}
24964919Sxy150489 	}
24974919Sxy150489 
24984919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
24994919Sxy150489 	    MAX_PHY_REG_ADDRESS & offset,
25004919Sxy150489 	    data);
25014919Sxy150489 
25026735Scc210113 	hw->phy.ops.release(hw);
25034919Sxy150489 
25044919Sxy150489 out:
25054919Sxy150489 	return (ret_val);
25064919Sxy150489 }
25074919Sxy150489 
25084919Sxy150489 /*
25094919Sxy150489  * e1000_read_phy_reg_bm - Read BM PHY register
25104919Sxy150489  * @hw: pointer to the HW structure
25114919Sxy150489  * @offset: register offset to be read
25124919Sxy150489  * @data: pointer to the read data
25134919Sxy150489  *
25144919Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
25154919Sxy150489  * and storing the retrieved information in data.  Release any acquired
25164919Sxy150489  * semaphores before exiting.
25174919Sxy150489  */
25184919Sxy150489 s32
25194919Sxy150489 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
25204919Sxy150489 {
25214919Sxy150489 	s32 ret_val;
25224919Sxy150489 	u32 page_select = 0;
25234919Sxy150489 	u32 page = offset >> IGP_PAGE_SHIFT;
25244919Sxy150489 	u32 page_shift = 0;
25254919Sxy150489 
25266735Scc210113 	DEBUGFUNC("e1000_read_phy_reg_bm");
25274919Sxy150489 
25284919Sxy150489 	/* Page 800 works differently than the rest so it has its own func */
25294919Sxy150489 	if (page == BM_WUC_PAGE) {
25304919Sxy150489 		ret_val = e1000_access_phy_wakeup_reg_bm(hw,
25317607STed.You@Sun.COM 		    offset, data, true);
25324919Sxy150489 		goto out;
25334919Sxy150489 	}
25346735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
25354919Sxy150489 	if (ret_val)
25364919Sxy150489 		goto out;
25374919Sxy150489 
25384919Sxy150489 	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
25394919Sxy150489 
25404919Sxy150489 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
25414919Sxy150489 		/*
25424919Sxy150489 		 * Page select is register 31 for phy address 1 and 22 for phy
25434919Sxy150489 		 * address 2 and 3. Page select is shifted only for phy
25444919Sxy150489 		 * address 1.
25454919Sxy150489 		 */
25464919Sxy150489 		if (hw->phy.addr == 1) {
25474919Sxy150489 			page_shift = IGP_PAGE_SHIFT;
25484919Sxy150489 			page_select = IGP01E1000_PHY_PAGE_SELECT;
25494919Sxy150489 		} else {
25504919Sxy150489 			page_shift = 0;
25514919Sxy150489 			page_select = BM_PHY_PAGE_SELECT;
25524919Sxy150489 		}
25534919Sxy150489 
25544919Sxy150489 		/* Page is shifted left, PHY expects (page x 32) */
25554919Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw, page_select,
25564919Sxy150489 		    (page << page_shift));
25574919Sxy150489 		if (ret_val) {
25586735Scc210113 			hw->phy.ops.release(hw);
25594919Sxy150489 			goto out;
25604919Sxy150489 		}
25614919Sxy150489 	}
25624919Sxy150489 
25634919Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw,
25644919Sxy150489 	    MAX_PHY_REG_ADDRESS & offset,
25654919Sxy150489 	    data);
25666735Scc210113 	hw->phy.ops.release(hw);
25674919Sxy150489 
25684919Sxy150489 out:
25694919Sxy150489 	return (ret_val);
25704919Sxy150489 }
25714919Sxy150489 
25724919Sxy150489 /*
25737607STed.You@Sun.COM  * e1000_read_phy_reg_bm2 - Read BM PHY register
25747607STed.You@Sun.COM  * @hw: pointer to the HW structure
25757607STed.You@Sun.COM  * @offset: register offset to be read
25767607STed.You@Sun.COM  * @data: pointer to the read data
25777607STed.You@Sun.COM  *
25787607STed.You@Sun.COM  * Acquires semaphore, if necessary, then reads the PHY register at offset
25797607STed.You@Sun.COM  * and storing the retrieved information in data.  Release any acquired
25807607STed.You@Sun.COM  * semaphores before exiting.
25817607STed.You@Sun.COM  */
25827607STed.You@Sun.COM s32
25837607STed.You@Sun.COM e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
25847607STed.You@Sun.COM {
25857607STed.You@Sun.COM 	s32 ret_val;
25867607STed.You@Sun.COM 	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
25877607STed.You@Sun.COM 
25887607STed.You@Sun.COM 	DEBUGFUNC("e1000_write_phy_reg_bm2");
25897607STed.You@Sun.COM 
25907607STed.You@Sun.COM 	/* Page 800 works differently than the rest so it has its own func */
25917607STed.You@Sun.COM 	if (page == BM_WUC_PAGE) {
25927607STed.You@Sun.COM 		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
25937607STed.You@Sun.COM 		    true);
25947607STed.You@Sun.COM 		goto out;
25957607STed.You@Sun.COM 	}
25967607STed.You@Sun.COM 
25977607STed.You@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
25987607STed.You@Sun.COM 	if (ret_val)
25997607STed.You@Sun.COM 		goto out;
26007607STed.You@Sun.COM 
26017607STed.You@Sun.COM 	hw->phy.addr = 1;
26027607STed.You@Sun.COM 
26037607STed.You@Sun.COM 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
26047607STed.You@Sun.COM 
26057607STed.You@Sun.COM 		/* Page is shifted left, PHY expects (page x 32) */
26067607STed.You@Sun.COM 		ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
26077607STed.You@Sun.COM 		    page);
26087607STed.You@Sun.COM 
26097607STed.You@Sun.COM 		if (ret_val) {
26107607STed.You@Sun.COM 			hw->phy.ops.release(hw);
26117607STed.You@Sun.COM 			goto out;
26127607STed.You@Sun.COM 		}
26137607STed.You@Sun.COM 	}
26147607STed.You@Sun.COM 
26157607STed.You@Sun.COM 	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
26167607STed.You@Sun.COM 	    data);
26177607STed.You@Sun.COM 	hw->phy.ops.release(hw);
26187607STed.You@Sun.COM 
26197607STed.You@Sun.COM out:
26207607STed.You@Sun.COM 	return (ret_val);
26217607STed.You@Sun.COM }
26227607STed.You@Sun.COM 
26237607STed.You@Sun.COM /*
26247607STed.You@Sun.COM  * e1000_write_phy_reg_bm2 - Write BM PHY register
26257607STed.You@Sun.COM  * @hw: pointer to the HW structure
26267607STed.You@Sun.COM  * @offset: register offset to write to
26277607STed.You@Sun.COM  * @data: data to write at register offset
26287607STed.You@Sun.COM  *
26297607STed.You@Sun.COM  * Acquires semaphore, if necessary, then writes the data to PHY register
26307607STed.You@Sun.COM  * at the offset.  Release any acquired semaphores before exiting.
26317607STed.You@Sun.COM  */
26327607STed.You@Sun.COM s32
26337607STed.You@Sun.COM e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
26347607STed.You@Sun.COM {
26357607STed.You@Sun.COM 	s32 ret_val;
26367607STed.You@Sun.COM 	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
26377607STed.You@Sun.COM 
26387607STed.You@Sun.COM 	DEBUGFUNC("e1000_write_phy_reg_bm2");
26397607STed.You@Sun.COM 
26407607STed.You@Sun.COM 	/* Page 800 works differently than the rest so it has its own func */
26417607STed.You@Sun.COM 	if (page == BM_WUC_PAGE) {
26427607STed.You@Sun.COM 		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
26437607STed.You@Sun.COM 		    false);
26447607STed.You@Sun.COM 		goto out;
26457607STed.You@Sun.COM 	}
26467607STed.You@Sun.COM 
26477607STed.You@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
26487607STed.You@Sun.COM 	if (ret_val)
26497607STed.You@Sun.COM 		goto out;
26507607STed.You@Sun.COM 
26517607STed.You@Sun.COM 	hw->phy.addr = 1;
26527607STed.You@Sun.COM 
26537607STed.You@Sun.COM 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
26547607STed.You@Sun.COM 		/* Page is shifted left, PHY expects (page x 32) */
26557607STed.You@Sun.COM 		ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
26567607STed.You@Sun.COM 		    page);
26577607STed.You@Sun.COM 
26587607STed.You@Sun.COM 		if (ret_val) {
26597607STed.You@Sun.COM 			hw->phy.ops.release(hw);
26607607STed.You@Sun.COM 			goto out;
26617607STed.You@Sun.COM 		}
26627607STed.You@Sun.COM 	}
26637607STed.You@Sun.COM 
26647607STed.You@Sun.COM 	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
26657607STed.You@Sun.COM 	    data);
26667607STed.You@Sun.COM 
26677607STed.You@Sun.COM 	hw->phy.ops.release(hw);
26687607STed.You@Sun.COM 
26697607STed.You@Sun.COM out:
26707607STed.You@Sun.COM 	return (ret_val);
26717607STed.You@Sun.COM }
26727607STed.You@Sun.COM 
26737607STed.You@Sun.COM /*
26744919Sxy150489  * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
26754919Sxy150489  * @hw: pointer to the HW structure
26764919Sxy150489  * @offset: register offset to be read or written
26774919Sxy150489  * @data: pointer to the data to read or write
26784919Sxy150489  * @read: determines if operation is read or write
26794919Sxy150489  *
26804919Sxy150489  * Acquires semaphore, if necessary, then reads the PHY register at offset
26814919Sxy150489  * and storing the retrieved information in data.  Release any acquired
26824919Sxy150489  * semaphores before exiting. Note that procedure to read the wakeup
26834919Sxy150489  * registers are different. It works as such:
26844919Sxy150489  * 1) Set page 769, register 17, bit 2 = 1
26854919Sxy150489  * 2) Set page to 800 for host (801 if we were manageability)
26864919Sxy150489  * 3) Write the address using the address opcode (0x11)
26874919Sxy150489  * 4) Read or write the data using the data opcode (0x12)
26884919Sxy150489  * 5) Restore 769_17.2 to its original value
26894919Sxy150489  */
26908479SChenlu.Chen@Sun.COM static s32
26914919Sxy150489 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw,
26926735Scc210113     u32 offset, u16 *data, bool read)
26934919Sxy150489 {
26944919Sxy150489 	s32 ret_val;
2695*10680SMin.Xu@Sun.COM 	u16 reg = BM_PHY_REG_NUM(offset);
26964919Sxy150489 	u16 phy_reg = 0;
26974919Sxy150489 	u8 phy_acquired = 1;
26984919Sxy150489 
2699*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_access_phy_wakeup_reg_bm");
2700*10680SMin.Xu@Sun.COM 
2701*10680SMin.Xu@Sun.COM 	/* Gig must be disabled for MDIO accesses to page 800 */
2702*10680SMin.Xu@Sun.COM 	if ((hw->mac.type == e1000_pchlan) &&
2703*10680SMin.Xu@Sun.COM 	    (!(E1000_READ_REG(hw, E1000_PHY_CTRL) &
2704*10680SMin.Xu@Sun.COM 	    E1000_PHY_CTRL_GBE_DISABLE)))
2705*10680SMin.Xu@Sun.COM 		DEBUGOUT("Attempting to access page 800 while gig enabled.\n");
27064919Sxy150489 
27076735Scc210113 	ret_val = hw->phy.ops.acquire(hw);
27084919Sxy150489 	if (ret_val) {
27096735Scc210113 		DEBUGOUT("Could not acquire PHY\n");
27104919Sxy150489 		phy_acquired = 0;
27114919Sxy150489 		goto out;
27124919Sxy150489 	}
27134919Sxy150489 
27144919Sxy150489 	/* All operations in this function are phy address 1 */
27154919Sxy150489 	hw->phy.addr = 1;
27164919Sxy150489 
27174919Sxy150489 	/* Set page 769 */
27187426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
27194919Sxy150489 	    (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
27204919Sxy150489 
27214919Sxy150489 	ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
27224919Sxy150489 	if (ret_val) {
27236735Scc210113 		DEBUGOUT("Could not read PHY page 769\n");
27244919Sxy150489 		goto out;
27254919Sxy150489 	}
27264919Sxy150489 
27274919Sxy150489 	/* First clear bit 4 to avoid a power state change */
27284919Sxy150489 	phy_reg &= ~(BM_WUC_HOST_WU_BIT);
27294919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
27304919Sxy150489 	if (ret_val) {
27316735Scc210113 		DEBUGOUT("Could not clear PHY page 769 bit 4\n");
27324919Sxy150489 		goto out;
27334919Sxy150489 	}
27344919Sxy150489 
27354919Sxy150489 	/* Write bit 2 = 1, and clear bit 4 to 769_17 */
27364919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
27374919Sxy150489 	    phy_reg | BM_WUC_ENABLE_BIT);
27384919Sxy150489 	if (ret_val) {
27396735Scc210113 		DEBUGOUT("Could not write PHY page 769 bit 2\n");
27404919Sxy150489 		goto out;
27414919Sxy150489 	}
27424919Sxy150489 
27434919Sxy150489 	/* Select page 800 */
27444919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw,
27454919Sxy150489 	    IGP01E1000_PHY_PAGE_SELECT,
27464919Sxy150489 	    (BM_WUC_PAGE << IGP_PAGE_SHIFT));
27474919Sxy150489 
27484919Sxy150489 	/* Write the page 800 offset value using opcode 0x11 */
27494919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
27504919Sxy150489 	if (ret_val) {
27516735Scc210113 		DEBUGOUT("Could not write address opcode to page 800\n");
27524919Sxy150489 		goto out;
27534919Sxy150489 	}
27544919Sxy150489 
27554919Sxy150489 	if (read) {
27564919Sxy150489 		/* Read the page 800 value using opcode 0x12 */
27574919Sxy150489 		ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
27584919Sxy150489 		    data);
27594919Sxy150489 	} else {
2760*10680SMin.Xu@Sun.COM 		/* Write the page 800 value using opcode 0x12 */
27614919Sxy150489 		ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
27624919Sxy150489 		    *data);
27634919Sxy150489 	}
27644919Sxy150489 
27654919Sxy150489 	if (ret_val) {
2766*10680SMin.Xu@Sun.COM 		DEBUGOUT("Could not access data value from page 800\n");
27674919Sxy150489 		goto out;
27684919Sxy150489 	}
27694919Sxy150489 
27704919Sxy150489 	/*
27714919Sxy150489 	 * Restore 769_17.2 to its original value Set page 769
27724919Sxy150489 	 */
27737426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
27744919Sxy150489 	    (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
27754919Sxy150489 
27764919Sxy150489 	/* Clear 769_17.2 */
27774919Sxy150489 	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
27784919Sxy150489 	if (ret_val) {
27796735Scc210113 		DEBUGOUT("Could not clear PHY page 769 bit 2\n");
27804919Sxy150489 		goto out;
27814919Sxy150489 	}
27824919Sxy150489 
27834919Sxy150489 out:
27844919Sxy150489 	if (phy_acquired == 1)
27856735Scc210113 		hw->phy.ops.release(hw);
27864919Sxy150489 	return (ret_val);
27874919Sxy150489 }
27886735Scc210113 
27896735Scc210113 /*
27906735Scc210113  * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
27916735Scc210113  * @hw: pointer to the HW structure
27926735Scc210113  *
27936735Scc210113  * In the case of a PHY power down to save power, or to turn off link during a
27946735Scc210113  * driver unload, or wake on lan is not enabled, restore the link to previous
27956735Scc210113  * settings.
27966735Scc210113  */
27976735Scc210113 void
27986735Scc210113 e1000_power_up_phy_copper(struct e1000_hw *hw)
27996735Scc210113 {
28006735Scc210113 	u16 mii_reg = 0;
28016735Scc210113 
28026735Scc210113 	/* The PHY will retain its settings across a power down/up cycle */
28036735Scc210113 	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
28046735Scc210113 	mii_reg &= ~MII_CR_POWER_DOWN;
28056735Scc210113 	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
28066735Scc210113 }
28076735Scc210113 
28086735Scc210113 /*
28096735Scc210113  * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
28106735Scc210113  * @hw: pointer to the HW structure
28116735Scc210113  *
28126735Scc210113  * In the case of a PHY power down to save power, or to turn off link during a
28136735Scc210113  * driver unload, or wake on lan is not enabled, restore the link to previous
28146735Scc210113  * settings.
28156735Scc210113  */
28166735Scc210113 void
28176735Scc210113 e1000_power_down_phy_copper(struct e1000_hw *hw)
28186735Scc210113 {
28196735Scc210113 	u16 mii_reg = 0;
28206735Scc210113 
28216735Scc210113 	/* The PHY will retain its settings across a power down/up cycle */
28226735Scc210113 	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
28236735Scc210113 	mii_reg |= MII_CR_POWER_DOWN;
28246735Scc210113 	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
28256735Scc210113 	msec_delay(1);
28266735Scc210113 }
2827*10680SMin.Xu@Sun.COM 
2828*10680SMin.Xu@Sun.COM s32
2829*10680SMin.Xu@Sun.COM e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
2830*10680SMin.Xu@Sun.COM {
2831*10680SMin.Xu@Sun.COM 	s32 ret_val = E1000_SUCCESS;
2832*10680SMin.Xu@Sun.COM 	u16 data = 0;
2833*10680SMin.Xu@Sun.COM 
2834*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
2835*10680SMin.Xu@Sun.COM 	if (ret_val)
2836*10680SMin.Xu@Sun.COM 		return (ret_val);
2837*10680SMin.Xu@Sun.COM 
2838*10680SMin.Xu@Sun.COM 	/* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
2839*10680SMin.Xu@Sun.COM 	hw->phy.addr = 1;
2840*10680SMin.Xu@Sun.COM 	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
2841*10680SMin.Xu@Sun.COM 	    (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
2842*10680SMin.Xu@Sun.COM 	if (ret_val)
2843*10680SMin.Xu@Sun.COM 		goto out;
2844*10680SMin.Xu@Sun.COM 
2845*10680SMin.Xu@Sun.COM 	ret_val = e1000_write_phy_reg_mdic(hw, BM_CS_CTRL1,
2846*10680SMin.Xu@Sun.COM 	    (0x2180 | (slow << 10)));
2847*10680SMin.Xu@Sun.COM 
2848*10680SMin.Xu@Sun.COM 	if (ret_val)
2849*10680SMin.Xu@Sun.COM 		goto out;
2850*10680SMin.Xu@Sun.COM 
2851*10680SMin.Xu@Sun.COM 	/* dummy read when reverting to fast mode - throw away result */
2852*10680SMin.Xu@Sun.COM 	if (!slow)
2853*10680SMin.Xu@Sun.COM 		ret_val = e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
2854*10680SMin.Xu@Sun.COM 
2855*10680SMin.Xu@Sun.COM out:
2856*10680SMin.Xu@Sun.COM 	hw->phy.ops.release(hw);
2857*10680SMin.Xu@Sun.COM 	return (ret_val);
2858*10680SMin.Xu@Sun.COM }
2859*10680SMin.Xu@Sun.COM 
2860*10680SMin.Xu@Sun.COM /*
2861*10680SMin.Xu@Sun.COM  * e1000_read_phy_reg_hv -  Read HV PHY register
2862*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
2863*10680SMin.Xu@Sun.COM  * @offset: register offset to be read
2864*10680SMin.Xu@Sun.COM  * @data: pointer to the read data
2865*10680SMin.Xu@Sun.COM  *
2866*10680SMin.Xu@Sun.COM  * Acquires semaphore, if necessary, then reads the PHY register at offset
2867*10680SMin.Xu@Sun.COM  * and storing the retrieved information in data.  Release any acquired
2868*10680SMin.Xu@Sun.COM  * semaphore before exiting.
2869*10680SMin.Xu@Sun.COM  */
2870*10680SMin.Xu@Sun.COM s32
2871*10680SMin.Xu@Sun.COM e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
2872*10680SMin.Xu@Sun.COM {
2873*10680SMin.Xu@Sun.COM 	s32 ret_val;
2874*10680SMin.Xu@Sun.COM 	u16 page = BM_PHY_REG_PAGE(offset);
2875*10680SMin.Xu@Sun.COM 	u16 reg = BM_PHY_REG_NUM(offset);
2876*10680SMin.Xu@Sun.COM 	bool in_slow_mode = false;
2877*10680SMin.Xu@Sun.COM 
2878*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_read_phy_reg_hv");
2879*10680SMin.Xu@Sun.COM 
2880*10680SMin.Xu@Sun.COM 	/* Workaround failure in MDIO access while cable is disconnected */
2881*10680SMin.Xu@Sun.COM 	if ((hw->phy.type == e1000_phy_82577) &&
2882*10680SMin.Xu@Sun.COM 	    !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
2883*10680SMin.Xu@Sun.COM 		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
2884*10680SMin.Xu@Sun.COM 		if (ret_val)
2885*10680SMin.Xu@Sun.COM 			goto out;
2886*10680SMin.Xu@Sun.COM 
2887*10680SMin.Xu@Sun.COM 		in_slow_mode = true;
2888*10680SMin.Xu@Sun.COM 	}
2889*10680SMin.Xu@Sun.COM 
2890*10680SMin.Xu@Sun.COM 	/* Page 800 works differently than the rest so it has its own func */
2891*10680SMin.Xu@Sun.COM 	if (page == BM_WUC_PAGE) {
2892*10680SMin.Xu@Sun.COM 		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
2893*10680SMin.Xu@Sun.COM 		    data, true);
2894*10680SMin.Xu@Sun.COM 		goto out;
2895*10680SMin.Xu@Sun.COM 	}
2896*10680SMin.Xu@Sun.COM 
2897*10680SMin.Xu@Sun.COM 	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
2898*10680SMin.Xu@Sun.COM 		ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
2899*10680SMin.Xu@Sun.COM 		    data, true);
2900*10680SMin.Xu@Sun.COM 		goto out;
2901*10680SMin.Xu@Sun.COM 	}
2902*10680SMin.Xu@Sun.COM 
2903*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
2904*10680SMin.Xu@Sun.COM 	if (ret_val)
2905*10680SMin.Xu@Sun.COM 		goto out;
2906*10680SMin.Xu@Sun.COM 
2907*10680SMin.Xu@Sun.COM 	hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
2908*10680SMin.Xu@Sun.COM 
2909*10680SMin.Xu@Sun.COM 	if (page == HV_INTC_FC_PAGE_START)
2910*10680SMin.Xu@Sun.COM 		page = 0;
2911*10680SMin.Xu@Sun.COM 
2912*10680SMin.Xu@Sun.COM 	if (reg > MAX_PHY_MULTI_PAGE_REG) {
2913*10680SMin.Xu@Sun.COM 		u32 phy_addr = hw->phy.addr;
2914*10680SMin.Xu@Sun.COM 		hw->phy.addr = 1;
2915*10680SMin.Xu@Sun.COM 
2916*10680SMin.Xu@Sun.COM 		/* Page is shifted left, PHY expects (page x 32) */
2917*10680SMin.Xu@Sun.COM 		ret_val = e1000_write_phy_reg_mdic(hw,
2918*10680SMin.Xu@Sun.COM 		    IGP01E1000_PHY_PAGE_SELECT,
2919*10680SMin.Xu@Sun.COM 		    (page << IGP_PAGE_SHIFT));
2920*10680SMin.Xu@Sun.COM 		hw->phy.addr = phy_addr;
2921*10680SMin.Xu@Sun.COM 
2922*10680SMin.Xu@Sun.COM 		if (ret_val) {
2923*10680SMin.Xu@Sun.COM 			hw->phy.ops.release(hw);
2924*10680SMin.Xu@Sun.COM 			goto out;
2925*10680SMin.Xu@Sun.COM 		}
2926*10680SMin.Xu@Sun.COM 	}
2927*10680SMin.Xu@Sun.COM 
2928*10680SMin.Xu@Sun.COM 	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
2929*10680SMin.Xu@Sun.COM 	    data);
2930*10680SMin.Xu@Sun.COM 	hw->phy.ops.release(hw);
2931*10680SMin.Xu@Sun.COM 
2932*10680SMin.Xu@Sun.COM out:
2933*10680SMin.Xu@Sun.COM 	/* Revert to MDIO fast mode, if applicable */
2934*10680SMin.Xu@Sun.COM 	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
2935*10680SMin.Xu@Sun.COM 		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
2936*10680SMin.Xu@Sun.COM 
2937*10680SMin.Xu@Sun.COM 	return (ret_val);
2938*10680SMin.Xu@Sun.COM }
2939*10680SMin.Xu@Sun.COM 
2940*10680SMin.Xu@Sun.COM /*
2941*10680SMin.Xu@Sun.COM  * e1000_write_phy_reg_hv - Write HV PHY register
2942*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
2943*10680SMin.Xu@Sun.COM  * @offset: register offset to write to
2944*10680SMin.Xu@Sun.COM  * @data: data to write at register offset
2945*10680SMin.Xu@Sun.COM  *
2946*10680SMin.Xu@Sun.COM  * Acquires semaphore, if necessary, then writes the data to PHY register
2947*10680SMin.Xu@Sun.COM  * at the offset.  Release any acquired semaphores before exiting.
2948*10680SMin.Xu@Sun.COM  */
2949*10680SMin.Xu@Sun.COM s32
2950*10680SMin.Xu@Sun.COM e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
2951*10680SMin.Xu@Sun.COM {
2952*10680SMin.Xu@Sun.COM 	s32 ret_val;
2953*10680SMin.Xu@Sun.COM 	u16 page = BM_PHY_REG_PAGE(offset);
2954*10680SMin.Xu@Sun.COM 	u16 reg = BM_PHY_REG_NUM(offset);
2955*10680SMin.Xu@Sun.COM 	bool in_slow_mode = false;
2956*10680SMin.Xu@Sun.COM 
2957*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_write_phy_reg_hv");
2958*10680SMin.Xu@Sun.COM 
2959*10680SMin.Xu@Sun.COM 	/* Workaround failure in MDIO access while cable is disconnected */
2960*10680SMin.Xu@Sun.COM 	if ((hw->phy.type == e1000_phy_82577) &&
2961*10680SMin.Xu@Sun.COM 	    !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
2962*10680SMin.Xu@Sun.COM 		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
2963*10680SMin.Xu@Sun.COM 		if (ret_val)
2964*10680SMin.Xu@Sun.COM 			goto out;
2965*10680SMin.Xu@Sun.COM 
2966*10680SMin.Xu@Sun.COM 		in_slow_mode = true;
2967*10680SMin.Xu@Sun.COM 	}
2968*10680SMin.Xu@Sun.COM 
2969*10680SMin.Xu@Sun.COM 	/* Page 800 works differently than the rest so it has its own func */
2970*10680SMin.Xu@Sun.COM 	if (page == BM_WUC_PAGE) {
2971*10680SMin.Xu@Sun.COM 		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
2972*10680SMin.Xu@Sun.COM 		    &data, false);
2973*10680SMin.Xu@Sun.COM 		goto out;
2974*10680SMin.Xu@Sun.COM 	}
2975*10680SMin.Xu@Sun.COM 
2976*10680SMin.Xu@Sun.COM 	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
2977*10680SMin.Xu@Sun.COM 		ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
2978*10680SMin.Xu@Sun.COM 		    &data, false);
2979*10680SMin.Xu@Sun.COM 		goto out;
2980*10680SMin.Xu@Sun.COM 	}
2981*10680SMin.Xu@Sun.COM 
2982*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
2983*10680SMin.Xu@Sun.COM 	if (ret_val)
2984*10680SMin.Xu@Sun.COM 		goto out;
2985*10680SMin.Xu@Sun.COM 
2986*10680SMin.Xu@Sun.COM 	hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
2987*10680SMin.Xu@Sun.COM 
2988*10680SMin.Xu@Sun.COM 	if (page == HV_INTC_FC_PAGE_START)
2989*10680SMin.Xu@Sun.COM 		page = 0;
2990*10680SMin.Xu@Sun.COM 
2991*10680SMin.Xu@Sun.COM 	/*
2992*10680SMin.Xu@Sun.COM 	 * Workaround MDIO accesses being disabled after entering IEEE Power
2993*10680SMin.Xu@Sun.COM 	 * Down (whenever bit 11 of the PHY Control register is set)
2994*10680SMin.Xu@Sun.COM 	 */
2995*10680SMin.Xu@Sun.COM 	if ((hw->phy.type == e1000_phy_82578) &&
2996*10680SMin.Xu@Sun.COM 	    (hw->phy.revision >= 1) &&
2997*10680SMin.Xu@Sun.COM 	    (hw->phy.addr == 2) &&
2998*10680SMin.Xu@Sun.COM 	    ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
2999*10680SMin.Xu@Sun.COM 	    (data & (1 << 11))) {
3000*10680SMin.Xu@Sun.COM 		u16 data2 = 0x7EFF;
3001*10680SMin.Xu@Sun.COM 		hw->phy.ops.release(hw);
3002*10680SMin.Xu@Sun.COM 		ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
3003*10680SMin.Xu@Sun.COM 		    &data2, false);
3004*10680SMin.Xu@Sun.COM 		if (ret_val)
3005*10680SMin.Xu@Sun.COM 			goto out;
3006*10680SMin.Xu@Sun.COM 
3007*10680SMin.Xu@Sun.COM 		ret_val = hw->phy.ops.acquire(hw);
3008*10680SMin.Xu@Sun.COM 		if (ret_val)
3009*10680SMin.Xu@Sun.COM 			goto out;
3010*10680SMin.Xu@Sun.COM 	}
3011*10680SMin.Xu@Sun.COM 
3012*10680SMin.Xu@Sun.COM 	if (reg > MAX_PHY_MULTI_PAGE_REG) {
3013*10680SMin.Xu@Sun.COM 		u32 phy_addr = hw->phy.addr;
3014*10680SMin.Xu@Sun.COM 		hw->phy.addr = 1;
3015*10680SMin.Xu@Sun.COM 
3016*10680SMin.Xu@Sun.COM 		/* Page is shifted left, PHY expects (page x 32) */
3017*10680SMin.Xu@Sun.COM 		ret_val = e1000_write_phy_reg_mdic(hw,
3018*10680SMin.Xu@Sun.COM 		    IGP01E1000_PHY_PAGE_SELECT,
3019*10680SMin.Xu@Sun.COM 		    (page << IGP_PAGE_SHIFT));
3020*10680SMin.Xu@Sun.COM 		hw->phy.addr = phy_addr;
3021*10680SMin.Xu@Sun.COM 
3022*10680SMin.Xu@Sun.COM 		if (ret_val) {
3023*10680SMin.Xu@Sun.COM 			hw->phy.ops.release(hw);
3024*10680SMin.Xu@Sun.COM 			goto out;
3025*10680SMin.Xu@Sun.COM 		}
3026*10680SMin.Xu@Sun.COM 	}
3027*10680SMin.Xu@Sun.COM 
3028*10680SMin.Xu@Sun.COM 	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
3029*10680SMin.Xu@Sun.COM 	    data);
3030*10680SMin.Xu@Sun.COM 	hw->phy.ops.release(hw);
3031*10680SMin.Xu@Sun.COM 
3032*10680SMin.Xu@Sun.COM out:
3033*10680SMin.Xu@Sun.COM 	/* Revert to MDIO fast mode, if applicable */
3034*10680SMin.Xu@Sun.COM 	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
3035*10680SMin.Xu@Sun.COM 		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
3036*10680SMin.Xu@Sun.COM 
3037*10680SMin.Xu@Sun.COM 	return (ret_val);
3038*10680SMin.Xu@Sun.COM }
3039*10680SMin.Xu@Sun.COM 
3040*10680SMin.Xu@Sun.COM /*
3041*10680SMin.Xu@Sun.COM  * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
3042*10680SMin.Xu@Sun.COM  * @page: page to be accessed
3043*10680SMin.Xu@Sun.COM  */
3044*10680SMin.Xu@Sun.COM static u32
3045*10680SMin.Xu@Sun.COM e1000_get_phy_addr_for_hv_page(u32 page)
3046*10680SMin.Xu@Sun.COM {
3047*10680SMin.Xu@Sun.COM 	u32 phy_addr = 2;
3048*10680SMin.Xu@Sun.COM 
3049*10680SMin.Xu@Sun.COM 	if (page >= HV_INTC_FC_PAGE_START)
3050*10680SMin.Xu@Sun.COM 		phy_addr = 1;
3051*10680SMin.Xu@Sun.COM 
3052*10680SMin.Xu@Sun.COM 	return (phy_addr);
3053*10680SMin.Xu@Sun.COM }
3054*10680SMin.Xu@Sun.COM 
3055*10680SMin.Xu@Sun.COM /*
3056*10680SMin.Xu@Sun.COM  * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
3057*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
3058*10680SMin.Xu@Sun.COM  * @offset: register offset to be read or written
3059*10680SMin.Xu@Sun.COM  * @data: pointer to the data to be read or written
3060*10680SMin.Xu@Sun.COM  * @read: determines if operation is read or written
3061*10680SMin.Xu@Sun.COM  *
3062*10680SMin.Xu@Sun.COM  * Acquires semaphore, if necessary, then reads the PHY register at offset
3063*10680SMin.Xu@Sun.COM  * and storing the retreived information in data.  Release any acquired
3064*10680SMin.Xu@Sun.COM  * semaphores before exiting.  Note that the procedure to read these regs
3065*10680SMin.Xu@Sun.COM  * uses the address port and data port to read/write.
3066*10680SMin.Xu@Sun.COM  */
3067*10680SMin.Xu@Sun.COM static s32
3068*10680SMin.Xu@Sun.COM e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
3069*10680SMin.Xu@Sun.COM     u16 *data, bool read)
3070*10680SMin.Xu@Sun.COM {
3071*10680SMin.Xu@Sun.COM 	s32 ret_val;
3072*10680SMin.Xu@Sun.COM 	u32 addr_reg = 0;
3073*10680SMin.Xu@Sun.COM 	u32 data_reg = 0;
3074*10680SMin.Xu@Sun.COM 	u8  phy_acquired = 1;
3075*10680SMin.Xu@Sun.COM 
3076*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_access_phy_debug_regs_hv");
3077*10680SMin.Xu@Sun.COM 
3078*10680SMin.Xu@Sun.COM 	/* This takes care of the difference with desktop vs mobile phy */
3079*10680SMin.Xu@Sun.COM 	addr_reg = (hw->phy.type == e1000_phy_82578) ?
3080*10680SMin.Xu@Sun.COM 	    I82578_ADDR_REG : I82577_ADDR_REG;
3081*10680SMin.Xu@Sun.COM 	data_reg = addr_reg + 1;
3082*10680SMin.Xu@Sun.COM 
3083*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.acquire(hw);
3084*10680SMin.Xu@Sun.COM 	if (ret_val) {
3085*10680SMin.Xu@Sun.COM 		DEBUGOUT("Could not acquire PHY\n");
3086*10680SMin.Xu@Sun.COM 		phy_acquired = 0;
3087*10680SMin.Xu@Sun.COM 		goto out;
3088*10680SMin.Xu@Sun.COM 	}
3089*10680SMin.Xu@Sun.COM 
3090*10680SMin.Xu@Sun.COM 	/* All operations in this function are phy address 2 */
3091*10680SMin.Xu@Sun.COM 	hw->phy.addr = 2;
3092*10680SMin.Xu@Sun.COM 
3093*10680SMin.Xu@Sun.COM 	/* masking with 0x3F to remove the page from offset */
3094*10680SMin.Xu@Sun.COM 	ret_val = e1000_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F);
3095*10680SMin.Xu@Sun.COM 	if (ret_val) {
3096*10680SMin.Xu@Sun.COM 		DEBUGOUT("Could not write PHY the HV address register\n");
3097*10680SMin.Xu@Sun.COM 		goto out;
3098*10680SMin.Xu@Sun.COM 	}
3099*10680SMin.Xu@Sun.COM 
3100*10680SMin.Xu@Sun.COM 	/* Read or write the data value next */
3101*10680SMin.Xu@Sun.COM 	if (read)
3102*10680SMin.Xu@Sun.COM 		ret_val = e1000_read_phy_reg_mdic(hw, data_reg, data);
3103*10680SMin.Xu@Sun.COM 	else
3104*10680SMin.Xu@Sun.COM 		ret_val = e1000_write_phy_reg_mdic(hw, data_reg, *data);
3105*10680SMin.Xu@Sun.COM 
3106*10680SMin.Xu@Sun.COM 	if (ret_val) {
3107*10680SMin.Xu@Sun.COM 		DEBUGOUT("Could not read data value from HV data register\n");
3108*10680SMin.Xu@Sun.COM 		goto out;
3109*10680SMin.Xu@Sun.COM 	}
3110*10680SMin.Xu@Sun.COM 
3111*10680SMin.Xu@Sun.COM out:
3112*10680SMin.Xu@Sun.COM 	if (phy_acquired == 1)
3113*10680SMin.Xu@Sun.COM 		hw->phy.ops.release(hw);
3114*10680SMin.Xu@Sun.COM 	return (ret_val);
3115*10680SMin.Xu@Sun.COM }
3116*10680SMin.Xu@Sun.COM 
3117*10680SMin.Xu@Sun.COM /*
3118*10680SMin.Xu@Sun.COM  * e1000_link_stall_workaround_hv - Si workaround
3119*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
3120*10680SMin.Xu@Sun.COM  *
3121*10680SMin.Xu@Sun.COM  * This function works around a Si bug where the link partner can get
3122*10680SMin.Xu@Sun.COM  * a link up indication before the PHY does.  If small packets are sent
3123*10680SMin.Xu@Sun.COM  * by the link partner they can be placed in the packet buffer without
3124*10680SMin.Xu@Sun.COM  * being properly accounted for by the PHY and will stall preventing
3125*10680SMin.Xu@Sun.COM  * further packets from being received.  The workaround is to clear the
3126*10680SMin.Xu@Sun.COM  * packet buffer after the PHY detects link up.
3127*10680SMin.Xu@Sun.COM  */
3128*10680SMin.Xu@Sun.COM s32
3129*10680SMin.Xu@Sun.COM e1000_link_stall_workaround_hv(struct e1000_hw *hw)
3130*10680SMin.Xu@Sun.COM {
3131*10680SMin.Xu@Sun.COM 	s32 ret_val = E1000_SUCCESS;
3132*10680SMin.Xu@Sun.COM 	u16 data;
3133*10680SMin.Xu@Sun.COM 
3134*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_link_stall_workaround_hv");
3135*10680SMin.Xu@Sun.COM 
3136*10680SMin.Xu@Sun.COM 	if (hw->phy.type != e1000_phy_82578)
3137*10680SMin.Xu@Sun.COM 		goto out;
3138*10680SMin.Xu@Sun.COM 
3139*10680SMin.Xu@Sun.COM 	/* Do not apply workaround if in PHY loopback bit 14 set */
3140*10680SMin.Xu@Sun.COM 	hw->phy.ops.read_reg(hw, PHY_CONTROL, &data);
3141*10680SMin.Xu@Sun.COM 	if (data & PHY_CONTROL_LB)
3142*10680SMin.Xu@Sun.COM 		goto out;
3143*10680SMin.Xu@Sun.COM 
3144*10680SMin.Xu@Sun.COM 	/* check if link is up and at 1Gbps */
3145*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data);
3146*10680SMin.Xu@Sun.COM 	if (ret_val)
3147*10680SMin.Xu@Sun.COM 		goto out;
3148*10680SMin.Xu@Sun.COM 
3149*10680SMin.Xu@Sun.COM 	data &= BM_CS_STATUS_LINK_UP |
3150*10680SMin.Xu@Sun.COM 	    BM_CS_STATUS_RESOLVED |
3151*10680SMin.Xu@Sun.COM 	    BM_CS_STATUS_SPEED_MASK;
3152*10680SMin.Xu@Sun.COM 
3153*10680SMin.Xu@Sun.COM 	if (data != (BM_CS_STATUS_LINK_UP |
3154*10680SMin.Xu@Sun.COM 	    BM_CS_STATUS_RESOLVED |
3155*10680SMin.Xu@Sun.COM 	    BM_CS_STATUS_SPEED_1000))
3156*10680SMin.Xu@Sun.COM 		goto out;
3157*10680SMin.Xu@Sun.COM 
3158*10680SMin.Xu@Sun.COM 	msec_delay(200);
3159*10680SMin.Xu@Sun.COM 
3160*10680SMin.Xu@Sun.COM 	/* flush the packets in the fifo buffer */
3161*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
3162*10680SMin.Xu@Sun.COM 	    HV_MUX_DATA_CTRL_GEN_TO_MAC | HV_MUX_DATA_CTRL_FORCE_SPEED);
3163*10680SMin.Xu@Sun.COM 	if (ret_val)
3164*10680SMin.Xu@Sun.COM 		goto out;
3165*10680SMin.Xu@Sun.COM 
3166*10680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
3167*10680SMin.Xu@Sun.COM 	    HV_MUX_DATA_CTRL_GEN_TO_MAC);
3168*10680SMin.Xu@Sun.COM 
3169*10680SMin.Xu@Sun.COM out:
3170*10680SMin.Xu@Sun.COM 	return (ret_val);
3171*10680SMin.Xu@Sun.COM }
3172*10680SMin.Xu@Sun.COM 
3173*10680SMin.Xu@Sun.COM /*
3174*10680SMin.Xu@Sun.COM  * e1000_check_polarity_82577 - Checks the polarity.
3175*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
3176*10680SMin.Xu@Sun.COM  *
3177*10680SMin.Xu@Sun.COM  * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
3178*10680SMin.Xu@Sun.COM  *
3179*10680SMin.Xu@Sun.COM  * Polarity is determined based on the PHY specific status register.
3180*10680SMin.Xu@Sun.COM  */
3181*10680SMin.Xu@Sun.COM s32
3182*10680SMin.Xu@Sun.COM e1000_check_polarity_82577(struct e1000_hw *hw)
3183*10680SMin.Xu@Sun.COM {
3184*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
3185*10680SMin.Xu@Sun.COM 	s32 ret_val;
3186*10680SMin.Xu@Sun.COM 	u16 data;
3187*10680SMin.Xu@Sun.COM 
3188*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_check_polarity_82577");
3189*10680SMin.Xu@Sun.COM 
3190*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
3191*10680SMin.Xu@Sun.COM 
3192*10680SMin.Xu@Sun.COM 	if (!ret_val)
3193*10680SMin.Xu@Sun.COM 		phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
3194*10680SMin.Xu@Sun.COM 		    ? e1000_rev_polarity_reversed
3195*10680SMin.Xu@Sun.COM 		    : e1000_rev_polarity_normal;
3196*10680SMin.Xu@Sun.COM 
3197*10680SMin.Xu@Sun.COM 	return (ret_val);
3198*10680SMin.Xu@Sun.COM }
3199*10680SMin.Xu@Sun.COM 
3200*10680SMin.Xu@Sun.COM /*
3201*10680SMin.Xu@Sun.COM  * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
3202*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
3203*10680SMin.Xu@Sun.COM  *
3204*10680SMin.Xu@Sun.COM  * Calls the PHY setup function to force speed and duplex.  Clears the
3205*10680SMin.Xu@Sun.COM  * auto-crossover to force MDI manually.  Waits for link and returns
3206*10680SMin.Xu@Sun.COM  * successful if link up is successful, else -E1000_ERR_PHY (-2).
3207*10680SMin.Xu@Sun.COM  */
3208*10680SMin.Xu@Sun.COM s32
3209*10680SMin.Xu@Sun.COM e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
3210*10680SMin.Xu@Sun.COM {
3211*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
3212*10680SMin.Xu@Sun.COM 	s32 ret_val;
3213*10680SMin.Xu@Sun.COM 	u16 phy_data;
3214*10680SMin.Xu@Sun.COM 	bool link;
3215*10680SMin.Xu@Sun.COM 
3216*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_phy_force_speed_duplex_82577");
3217*10680SMin.Xu@Sun.COM 
3218*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
3219*10680SMin.Xu@Sun.COM 	if (ret_val)
3220*10680SMin.Xu@Sun.COM 		goto out;
3221*10680SMin.Xu@Sun.COM 
3222*10680SMin.Xu@Sun.COM 	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
3223*10680SMin.Xu@Sun.COM 
3224*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
3225*10680SMin.Xu@Sun.COM 	if (ret_val)
3226*10680SMin.Xu@Sun.COM 		goto out;
3227*10680SMin.Xu@Sun.COM 
3228*10680SMin.Xu@Sun.COM 	/*
3229*10680SMin.Xu@Sun.COM 	 * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
3230*10680SMin.Xu@Sun.COM 	 * forced whenever speed and duplex are forced.
3231*10680SMin.Xu@Sun.COM 	 */
3232*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data);
3233*10680SMin.Xu@Sun.COM 	if (ret_val)
3234*10680SMin.Xu@Sun.COM 		goto out;
3235*10680SMin.Xu@Sun.COM 
3236*10680SMin.Xu@Sun.COM 	phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
3237*10680SMin.Xu@Sun.COM 	phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
3238*10680SMin.Xu@Sun.COM 
3239*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data);
3240*10680SMin.Xu@Sun.COM 	if (ret_val)
3241*10680SMin.Xu@Sun.COM 		goto out;
3242*10680SMin.Xu@Sun.COM 
3243*10680SMin.Xu@Sun.COM 	DEBUGOUT1("I82577_PHY_CTRL_2: %X\n", phy_data);
3244*10680SMin.Xu@Sun.COM 
3245*10680SMin.Xu@Sun.COM 	usec_delay(1);
3246*10680SMin.Xu@Sun.COM 
3247*10680SMin.Xu@Sun.COM 	if (phy->autoneg_wait_to_complete) {
3248*10680SMin.Xu@Sun.COM 		DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n");
3249*10680SMin.Xu@Sun.COM 
3250*10680SMin.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
3251*10680SMin.Xu@Sun.COM 		    PHY_FORCE_LIMIT, 100000, &link);
3252*10680SMin.Xu@Sun.COM 		if (ret_val)
3253*10680SMin.Xu@Sun.COM 			goto out;
3254*10680SMin.Xu@Sun.COM 
3255*10680SMin.Xu@Sun.COM 		if (!link)
3256*10680SMin.Xu@Sun.COM 			DEBUGOUT("Link taking longer than expected.\n");
3257*10680SMin.Xu@Sun.COM 
3258*10680SMin.Xu@Sun.COM 		/* Try once more */
3259*10680SMin.Xu@Sun.COM 		ret_val = e1000_phy_has_link_generic(hw,
3260*10680SMin.Xu@Sun.COM 		    PHY_FORCE_LIMIT, 100000, &link);
3261*10680SMin.Xu@Sun.COM 		if (ret_val)
3262*10680SMin.Xu@Sun.COM 			goto out;
3263*10680SMin.Xu@Sun.COM 	}
3264*10680SMin.Xu@Sun.COM 
3265*10680SMin.Xu@Sun.COM out:
3266*10680SMin.Xu@Sun.COM 	return (ret_val);
3267*10680SMin.Xu@Sun.COM }
3268*10680SMin.Xu@Sun.COM 
3269*10680SMin.Xu@Sun.COM /*
3270*10680SMin.Xu@Sun.COM  * e1000_get_phy_info_82577 - Retrieve I82577 PHY information
3271*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
3272*10680SMin.Xu@Sun.COM  *
3273*10680SMin.Xu@Sun.COM  * Read PHY status to determine if link is up.  If link is up, then
3274*10680SMin.Xu@Sun.COM  * set/determine 10base-T extended distance and polarity correction.  Read
3275*10680SMin.Xu@Sun.COM  * PHY port status to determine MDI/MDIx and speed.  Based on the speed,
3276*10680SMin.Xu@Sun.COM  * determine on the cable length, local and remote receiver.
3277*10680SMin.Xu@Sun.COM  */
3278*10680SMin.Xu@Sun.COM s32
3279*10680SMin.Xu@Sun.COM e1000_get_phy_info_82577(struct e1000_hw *hw)
3280*10680SMin.Xu@Sun.COM {
3281*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
3282*10680SMin.Xu@Sun.COM 	s32 ret_val;
3283*10680SMin.Xu@Sun.COM 	u16 data;
3284*10680SMin.Xu@Sun.COM 	bool link;
3285*10680SMin.Xu@Sun.COM 
3286*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_get_phy_info_82577");
3287*10680SMin.Xu@Sun.COM 
3288*10680SMin.Xu@Sun.COM 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
3289*10680SMin.Xu@Sun.COM 	if (ret_val)
3290*10680SMin.Xu@Sun.COM 		goto out;
3291*10680SMin.Xu@Sun.COM 
3292*10680SMin.Xu@Sun.COM 	if (!link) {
3293*10680SMin.Xu@Sun.COM 		DEBUGOUT("Phy info is only valid if link is up\n");
3294*10680SMin.Xu@Sun.COM 		ret_val = -E1000_ERR_CONFIG;
3295*10680SMin.Xu@Sun.COM 		goto out;
3296*10680SMin.Xu@Sun.COM 	}
3297*10680SMin.Xu@Sun.COM 
3298*10680SMin.Xu@Sun.COM 	phy->polarity_correction = true;
3299*10680SMin.Xu@Sun.COM 
3300*10680SMin.Xu@Sun.COM 	ret_val = e1000_check_polarity_82577(hw);
3301*10680SMin.Xu@Sun.COM 	if (ret_val)
3302*10680SMin.Xu@Sun.COM 		goto out;
3303*10680SMin.Xu@Sun.COM 
3304*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
3305*10680SMin.Xu@Sun.COM 	if (ret_val)
3306*10680SMin.Xu@Sun.COM 		goto out;
3307*10680SMin.Xu@Sun.COM 
3308*10680SMin.Xu@Sun.COM 	phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
3309*10680SMin.Xu@Sun.COM 
3310*10680SMin.Xu@Sun.COM 	if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
3311*10680SMin.Xu@Sun.COM 	    I82577_PHY_STATUS2_SPEED_1000MBPS) {
3312*10680SMin.Xu@Sun.COM 		ret_val = hw->phy.ops.get_cable_length(hw);
3313*10680SMin.Xu@Sun.COM 		if (ret_val)
3314*10680SMin.Xu@Sun.COM 			goto out;
3315*10680SMin.Xu@Sun.COM 
3316*10680SMin.Xu@Sun.COM 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
3317*10680SMin.Xu@Sun.COM 		if (ret_val)
3318*10680SMin.Xu@Sun.COM 			goto out;
3319*10680SMin.Xu@Sun.COM 
3320*10680SMin.Xu@Sun.COM 		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
3321*10680SMin.Xu@Sun.COM 		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
3322*10680SMin.Xu@Sun.COM 
3323*10680SMin.Xu@Sun.COM 		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
3324*10680SMin.Xu@Sun.COM 		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
3325*10680SMin.Xu@Sun.COM 	} else {
3326*10680SMin.Xu@Sun.COM 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
3327*10680SMin.Xu@Sun.COM 		phy->local_rx = e1000_1000t_rx_status_undefined;
3328*10680SMin.Xu@Sun.COM 		phy->remote_rx = e1000_1000t_rx_status_undefined;
3329*10680SMin.Xu@Sun.COM 	}
3330*10680SMin.Xu@Sun.COM 
3331*10680SMin.Xu@Sun.COM out:
3332*10680SMin.Xu@Sun.COM 	return (ret_val);
3333*10680SMin.Xu@Sun.COM }
3334*10680SMin.Xu@Sun.COM 
3335*10680SMin.Xu@Sun.COM /*
3336*10680SMin.Xu@Sun.COM  * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
3337*10680SMin.Xu@Sun.COM  * @hw: pointer to the HW structure
3338*10680SMin.Xu@Sun.COM  *
3339*10680SMin.Xu@Sun.COM  * Reads the diagnostic status register and verifies result is valid before
3340*10680SMin.Xu@Sun.COM  * placing it in the phy_cable_length field.
3341*10680SMin.Xu@Sun.COM  */
3342*10680SMin.Xu@Sun.COM s32
3343*10680SMin.Xu@Sun.COM e1000_get_cable_length_82577(struct e1000_hw *hw)
3344*10680SMin.Xu@Sun.COM {
3345*10680SMin.Xu@Sun.COM 	struct e1000_phy_info *phy = &hw->phy;
3346*10680SMin.Xu@Sun.COM 	s32 ret_val;
3347*10680SMin.Xu@Sun.COM 	u16 phy_data, length;
3348*10680SMin.Xu@Sun.COM 
3349*10680SMin.Xu@Sun.COM 	DEBUGFUNC("e1000_get_cable_length_82577");
3350*10680SMin.Xu@Sun.COM 
3351*10680SMin.Xu@Sun.COM 	ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
3352*10680SMin.Xu@Sun.COM 	if (ret_val)
3353*10680SMin.Xu@Sun.COM 		goto out;
3354*10680SMin.Xu@Sun.COM 
3355*10680SMin.Xu@Sun.COM 	length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
3356*10680SMin.Xu@Sun.COM 	    I82577_DSTATUS_CABLE_LENGTH_SHIFT;
3357*10680SMin.Xu@Sun.COM 
3358*10680SMin.Xu@Sun.COM 	if (length == E1000_CABLE_LENGTH_UNDEFINED)
3359*10680SMin.Xu@Sun.COM 		ret_val = E1000_ERR_PHY;
3360*10680SMin.Xu@Sun.COM 
3361*10680SMin.Xu@Sun.COM 	phy->cable_length = length;
3362*10680SMin.Xu@Sun.COM 
3363*10680SMin.Xu@Sun.COM out:
3364*10680SMin.Xu@Sun.COM 	return (ret_val);
3365*10680SMin.Xu@Sun.COM }
3366