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