15779Sxy150489 /* 25779Sxy150489 * CDDL HEADER START 35779Sxy150489 * 48571SChenlu.Chen@Sun.COM * Copyright(c) 2007-2009 Intel Corporation. All rights reserved. 55779Sxy150489 * The contents of this file are subject to the terms of the 65779Sxy150489 * Common Development and Distribution License (the "License"). 75779Sxy150489 * You may not use this file except in compliance with the License. 85779Sxy150489 * 95779Sxy150489 * You can obtain a copy of the license at: 105779Sxy150489 * http://www.opensolaris.org/os/licensing. 115779Sxy150489 * See the License for the specific language governing permissions 125779Sxy150489 * and limitations under the License. 135779Sxy150489 * 145779Sxy150489 * When using or redistributing this file, you may do so under the 155779Sxy150489 * License only. No other modification of this header is permitted. 165779Sxy150489 * 175779Sxy150489 * If applicable, add the following below this CDDL HEADER, with the 185779Sxy150489 * fields enclosed by brackets "[]" replaced with your own identifying 195779Sxy150489 * information: Portions Copyright [yyyy] [name of copyright owner] 205779Sxy150489 * 215779Sxy150489 * CDDL HEADER END 225779Sxy150489 */ 235779Sxy150489 245779Sxy150489 /* 258571SChenlu.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 265779Sxy150489 * Use is subject to license terms of the CDDL. 275779Sxy150489 */ 285779Sxy150489 29*10319SJason.Xu@Sun.COM /* IntelVersion: 1.140 v2-9-8_2009-6-12 */ 305779Sxy150489 315779Sxy150489 #include "igb_api.h" 325779Sxy150489 338571SChenlu.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 /* 588571SChenlu.Chen@Sun.COM * e1000_init_phy_ops_generic - Initialize PHY function pointers 598571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure 608571SChenlu.Chen@Sun.COM * 618571SChenlu.Chen@Sun.COM * Setups up the function pointers to no-op functions 628571SChenlu.Chen@Sun.COM */ 638571SChenlu.Chen@Sun.COM void 648571SChenlu.Chen@Sun.COM e1000_init_phy_ops_generic(struct e1000_hw *hw) 658571SChenlu.Chen@Sun.COM { 668571SChenlu.Chen@Sun.COM struct e1000_phy_info *phy = &hw->phy; 678571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_init_phy_ops_generic"); 688571SChenlu.Chen@Sun.COM 698571SChenlu.Chen@Sun.COM /* Initialize function pointers */ 708571SChenlu.Chen@Sun.COM phy->ops.init_params = e1000_null_ops_generic; 718571SChenlu.Chen@Sun.COM phy->ops.acquire = e1000_null_ops_generic; 728571SChenlu.Chen@Sun.COM phy->ops.check_polarity = e1000_null_ops_generic; 738571SChenlu.Chen@Sun.COM phy->ops.check_reset_block = e1000_null_ops_generic; 748571SChenlu.Chen@Sun.COM phy->ops.commit = e1000_null_ops_generic; 758571SChenlu.Chen@Sun.COM phy->ops.force_speed_duplex = e1000_null_ops_generic; 768571SChenlu.Chen@Sun.COM phy->ops.get_cfg_done = e1000_null_ops_generic; 778571SChenlu.Chen@Sun.COM phy->ops.get_cable_length = e1000_null_ops_generic; 788571SChenlu.Chen@Sun.COM phy->ops.get_info = e1000_null_ops_generic; 798571SChenlu.Chen@Sun.COM phy->ops.read_reg = e1000_null_read_reg; 808571SChenlu.Chen@Sun.COM phy->ops.release = e1000_null_phy_generic; 818571SChenlu.Chen@Sun.COM phy->ops.reset = e1000_null_ops_generic; 828571SChenlu.Chen@Sun.COM phy->ops.set_d0_lplu_state = e1000_null_lplu_state; 838571SChenlu.Chen@Sun.COM phy->ops.set_d3_lplu_state = e1000_null_lplu_state; 848571SChenlu.Chen@Sun.COM phy->ops.write_reg = e1000_null_write_reg; 858571SChenlu.Chen@Sun.COM phy->ops.power_up = e1000_null_phy_generic; 868571SChenlu.Chen@Sun.COM phy->ops.power_down = e1000_null_phy_generic; 878571SChenlu.Chen@Sun.COM } 888571SChenlu.Chen@Sun.COM 898571SChenlu.Chen@Sun.COM /* 908571SChenlu.Chen@Sun.COM * e1000_null_read_reg - No-op function, return 0 918571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure 928571SChenlu.Chen@Sun.COM */ 938571SChenlu.Chen@Sun.COM s32 948571SChenlu.Chen@Sun.COM e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data) 958571SChenlu.Chen@Sun.COM { 968571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_read_reg"); 978571SChenlu.Chen@Sun.COM UNREFERENCED_3PARAMETER(hw, offset, data); 988571SChenlu.Chen@Sun.COM return (E1000_SUCCESS); 998571SChenlu.Chen@Sun.COM } 1008571SChenlu.Chen@Sun.COM 1018571SChenlu.Chen@Sun.COM /* 1028571SChenlu.Chen@Sun.COM * e1000_null_phy_generic - No-op function, return void 1038571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure 1048571SChenlu.Chen@Sun.COM */ 1058571SChenlu.Chen@Sun.COM void 1068571SChenlu.Chen@Sun.COM e1000_null_phy_generic(struct e1000_hw *hw) 1078571SChenlu.Chen@Sun.COM { 1088571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_phy_generic"); 1098571SChenlu.Chen@Sun.COM UNREFERENCED_1PARAMETER(hw); 1108571SChenlu.Chen@Sun.COM } 1118571SChenlu.Chen@Sun.COM 1128571SChenlu.Chen@Sun.COM /* 1138571SChenlu.Chen@Sun.COM * e1000_null_lplu_state - No-op function, return 0 1148571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure 1158571SChenlu.Chen@Sun.COM */ 1168571SChenlu.Chen@Sun.COM s32 1178571SChenlu.Chen@Sun.COM e1000_null_lplu_state(struct e1000_hw *hw, bool active) 1188571SChenlu.Chen@Sun.COM { 1198571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_lplu_state"); 1208571SChenlu.Chen@Sun.COM UNREFERENCED_2PARAMETER(hw, active); 1218571SChenlu.Chen@Sun.COM return (E1000_SUCCESS); 1228571SChenlu.Chen@Sun.COM } 1238571SChenlu.Chen@Sun.COM 1248571SChenlu.Chen@Sun.COM /* 1258571SChenlu.Chen@Sun.COM * e1000_null_write_reg - No-op function, return 0 1268571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure 1278571SChenlu.Chen@Sun.COM */ 1288571SChenlu.Chen@Sun.COM s32 1298571SChenlu.Chen@Sun.COM e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data) 1308571SChenlu.Chen@Sun.COM { 1318571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_write_reg"); 1328571SChenlu.Chen@Sun.COM UNREFERENCED_3PARAMETER(hw, offset, data); 1338571SChenlu.Chen@Sun.COM return (E1000_SUCCESS); 1348571SChenlu.Chen@Sun.COM } 1358571SChenlu.Chen@Sun.COM 1368571SChenlu.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 1738571SChenlu.Chen@Sun.COM if (!(phy->ops.read_reg)) 1748571SChenlu.Chen@Sun.COM goto out; 1758571SChenlu.Chen@Sun.COM 1768571SChenlu.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); 1828571SChenlu.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 { 2028571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 2035779Sxy150489 2045779Sxy150489 DEBUGFUNC("e1000_phy_reset_dsp_generic"); 2055779Sxy150489 2068571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.write_reg)) 2078571SChenlu.Chen@Sun.COM goto out; 2088571SChenlu.Chen@Sun.COM 2098571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); 2105779Sxy150489 if (ret_val) 2115779Sxy150489 goto out; 2125779Sxy150489 2138571SChenlu.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 * 2258571SChenlu.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 { 3438571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 3445779Sxy150489 3455779Sxy150489 DEBUGFUNC("e1000_read_phy_reg_m88"); 3465779Sxy150489 3478571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire)) 3488571SChenlu.Chen@Sun.COM goto out; 3498571SChenlu.Chen@Sun.COM 3508571SChenlu.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 3578571SChenlu.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 { 3758571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 3765779Sxy150489 3775779Sxy150489 DEBUGFUNC("e1000_write_phy_reg_m88"); 3785779Sxy150489 3798571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire)) 3808571SChenlu.Chen@Sun.COM goto out; 3818571SChenlu.Chen@Sun.COM 3828571SChenlu.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 3898571SChenlu.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 { 4088571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 4095779Sxy150489 4105779Sxy150489 DEBUGFUNC("e1000_read_phy_reg_igp"); 4115779Sxy150489 4128571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire)) 4138571SChenlu.Chen@Sun.COM goto out; 4148571SChenlu.Chen@Sun.COM 4158571SChenlu.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) { 4238571SChenlu.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 4318571SChenlu.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 { 4498571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 4505779Sxy150489 4515779Sxy150489 DEBUGFUNC("e1000_write_phy_reg_igp"); 4525779Sxy150489 4538571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire)) 4548571SChenlu.Chen@Sun.COM goto out; 4558571SChenlu.Chen@Sun.COM 4568571SChenlu.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) { 4648571SChenlu.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 4728571SChenlu.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; 4928571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 4935779Sxy150489 4945779Sxy150489 DEBUGFUNC("e1000_read_kmrn_reg_generic"); 4955779Sxy150489 4968571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire)) 4978571SChenlu.Chen@Sun.COM goto out; 4988571SChenlu.Chen@Sun.COM 4998571SChenlu.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 5128571SChenlu.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; 5328571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 5335779Sxy150489 5345779Sxy150489 DEBUGFUNC("e1000_write_kmrn_reg_generic"); 5355779Sxy150489 5368571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire)) 5378571SChenlu.Chen@Sun.COM goto out; 5388571SChenlu.Chen@Sun.COM 5398571SChenlu.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); 5488571SChenlu.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. */ 5768571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); 5775779Sxy150489 if (ret_val) 5785779Sxy150489 goto out; 5795779Sxy150489 5808571SChenlu.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 6198571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); 6205779Sxy150489 if (ret_val) 6215779Sxy150489 goto out; 6225779Sxy150489 6238571SChenlu.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 */ 6288571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, 6298571SChenlu.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 } 6478571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, 6488571SChenlu.Chen@Sun.COM phy_data); 6495779Sxy150489 if (ret_val) 6505779Sxy150489 goto out; 6515779Sxy150489 } 6525779Sxy150489 6535779Sxy150489 /* Commit the changes. */ 6548571SChenlu.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 6858571SChenlu.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 6918571SChenlu.Chen@Sun.COM /* 6928571SChenlu.Chen@Sun.COM * Wait 100ms for MAC to configure PHY from NVM settings, to avoid 6938571SChenlu.Chen@Sun.COM * timeout issues when LFS is enabled. 6948571SChenlu.Chen@Sun.COM */ 6958571SChenlu.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 */ 7038571SChenlu.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 */ 7118571SChenlu.Chen@Sun.COM if (hw->phy.ops.set_d0_lplu_state) { 7128571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); 7138571SChenlu.Chen@Sun.COM if (ret_val) { 7148571SChenlu.Chen@Sun.COM DEBUGOUT("Error Disabling LPLU D0\n"); 7158571SChenlu.Chen@Sun.COM goto out; 7168571SChenlu.Chen@Sun.COM } 7175779Sxy150489 } 7185779Sxy150489 /* Configure mdi-mdix settings */ 7198571SChenlu.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 } 7378571SChenlu.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 */ 7508571SChenlu.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; 7568571SChenlu.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 */ 7628571SChenlu.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; 7678571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); 7685779Sxy150489 if (ret_val) 7695779Sxy150489 goto out; 7705779Sxy150489 } 7715779Sxy150489 7728571SChenlu.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 } 7968571SChenlu.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 */ 8488571SChenlu.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); 8538571SChenlu.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) { 8628571SChenlu.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 8708571SChenlu.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). */ 8988571SChenlu.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). */ 9048571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, 9058571SChenlu.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 */ 9568571SChenlu.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 */ 9838571SChenlu.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 10258571SChenlu.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) { 10328571SChenlu.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"); 10738571SChenlu.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 11218571SChenlu.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 11278571SChenlu.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 */ 11358571SChenlu.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 11428571SChenlu.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 11608571SChenlu.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 */ 12008571SChenlu.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; 12058571SChenlu.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 12118571SChenlu.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 12178571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); 12185779Sxy150489 if (ret_val) 12195779Sxy150489 goto out; 12205779Sxy150489 12218571SChenlu.Chen@Sun.COM /* Reset the phy to commit changes. */ 12228571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.commit(hw); 12238571SChenlu.Chen@Sun.COM if (ret_val) 12248571SChenlu.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 12298571SChenlu.Chen@Sun.COM ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, 12308571SChenlu.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 */ 12398571SChenlu.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 */ 12508571SChenlu.Chen@Sun.COM ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, 12518571SChenlu.Chen@Sun.COM 100000, &link); 12525779Sxy150489 if (ret_val) 12535779Sxy150489 goto out; 12545779Sxy150489 } 12555779Sxy150489 12568571SChenlu.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; 12668571SChenlu.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 */ 12748571SChenlu.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; 12798571SChenlu.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 /* 1286*10319SJason.Xu@Sun.COM * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex 1287*10319SJason.Xu@Sun.COM * @hw: pointer to the HW structure 1288*10319SJason.Xu@Sun.COM * 1289*10319SJason.Xu@Sun.COM * Forces the speed and duplex settings of the PHY. 1290*10319SJason.Xu@Sun.COM * This is a function pointer entry point only called by 1291*10319SJason.Xu@Sun.COM * PHY setup routines. 1292*10319SJason.Xu@Sun.COM */ 1293*10319SJason.Xu@Sun.COM s32 1294*10319SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw) 1295*10319SJason.Xu@Sun.COM { 1296*10319SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy; 1297*10319SJason.Xu@Sun.COM s32 ret_val; 1298*10319SJason.Xu@Sun.COM u16 data; 1299*10319SJason.Xu@Sun.COM bool link; 1300*10319SJason.Xu@Sun.COM 1301*10319SJason.Xu@Sun.COM DEBUGFUNC("e1000_phy_force_speed_duplex_ife"); 1302*10319SJason.Xu@Sun.COM 1303*10319SJason.Xu@Sun.COM if (phy->type != e1000_phy_ife) { 1304*10319SJason.Xu@Sun.COM ret_val = e1000_phy_force_speed_duplex_igp(hw); 1305*10319SJason.Xu@Sun.COM goto out; 1306*10319SJason.Xu@Sun.COM } 1307*10319SJason.Xu@Sun.COM 1308*10319SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); 1309*10319SJason.Xu@Sun.COM if (ret_val) 1310*10319SJason.Xu@Sun.COM goto out; 1311*10319SJason.Xu@Sun.COM 1312*10319SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_setup(hw, &data); 1313*10319SJason.Xu@Sun.COM 1314*10319SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); 1315*10319SJason.Xu@Sun.COM if (ret_val) 1316*10319SJason.Xu@Sun.COM goto out; 1317*10319SJason.Xu@Sun.COM 1318*10319SJason.Xu@Sun.COM /* Disable MDI-X support for 10/100 */ 1319*10319SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); 1320*10319SJason.Xu@Sun.COM if (ret_val) 1321*10319SJason.Xu@Sun.COM goto out; 1322*10319SJason.Xu@Sun.COM 1323*10319SJason.Xu@Sun.COM data &= ~IFE_PMC_AUTO_MDIX; 1324*10319SJason.Xu@Sun.COM data &= ~IFE_PMC_FORCE_MDIX; 1325*10319SJason.Xu@Sun.COM 1326*10319SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); 1327*10319SJason.Xu@Sun.COM if (ret_val) 1328*10319SJason.Xu@Sun.COM goto out; 1329*10319SJason.Xu@Sun.COM 1330*10319SJason.Xu@Sun.COM DEBUGOUT1("IFE PMC: %X\n", data); 1331*10319SJason.Xu@Sun.COM 1332*10319SJason.Xu@Sun.COM usec_delay(1); 1333*10319SJason.Xu@Sun.COM 1334*10319SJason.Xu@Sun.COM if (phy->autoneg_wait_to_complete) { 1335*10319SJason.Xu@Sun.COM DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); 1336*10319SJason.Xu@Sun.COM 1337*10319SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw, 1338*10319SJason.Xu@Sun.COM PHY_FORCE_LIMIT, 100000, &link); 1339*10319SJason.Xu@Sun.COM if (ret_val) 1340*10319SJason.Xu@Sun.COM goto out; 1341*10319SJason.Xu@Sun.COM 1342*10319SJason.Xu@Sun.COM if (!link) 1343*10319SJason.Xu@Sun.COM DEBUGOUT("Link taking longer than expected.\n"); 1344*10319SJason.Xu@Sun.COM 1345*10319SJason.Xu@Sun.COM /* Try once more */ 1346*10319SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw, 1347*10319SJason.Xu@Sun.COM PHY_FORCE_LIMIT, 100000, &link); 1348*10319SJason.Xu@Sun.COM if (ret_val) 1349*10319SJason.Xu@Sun.COM goto out; 1350*10319SJason.Xu@Sun.COM } 1351*10319SJason.Xu@Sun.COM 1352*10319SJason.Xu@Sun.COM out: 1353*10319SJason.Xu@Sun.COM return (ret_val); 1354*10319SJason.Xu@Sun.COM } 1355*10319SJason.Xu@Sun.COM /* 13565779Sxy150489 * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex 13575779Sxy150489 * @hw: pointer to the HW structure 13585779Sxy150489 * @phy_ctrl: pointer to current value of PHY_CONTROL 13595779Sxy150489 * 13605779Sxy150489 * Forces speed and duplex on the PHY by doing the following: disable flow 13615779Sxy150489 * control, force speed/duplex on the MAC, disable auto speed detection, 13625779Sxy150489 * disable auto-negotiation, configure duplex, configure speed, configure 13635779Sxy150489 * the collision distance, write configuration to CTRL register. The 13645779Sxy150489 * caller must write to the PHY_CONTROL register for these settings to 13655779Sxy150489 * take affect. 13665779Sxy150489 */ 13675779Sxy150489 void 13685779Sxy150489 e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) 13695779Sxy150489 { 13705779Sxy150489 struct e1000_mac_info *mac = &hw->mac; 13715779Sxy150489 u32 ctrl; 13725779Sxy150489 13735779Sxy150489 DEBUGFUNC("e1000_phy_force_speed_duplex_setup"); 13745779Sxy150489 13755779Sxy150489 /* Turn off flow control when forcing speed/duplex */ 13768571SChenlu.Chen@Sun.COM hw->fc.current_mode = e1000_fc_none; 13775779Sxy150489 13785779Sxy150489 /* Force speed/duplex on the mac */ 13795779Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 13805779Sxy150489 ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 13815779Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; 13825779Sxy150489 13835779Sxy150489 /* Disable Auto Speed Detection */ 13845779Sxy150489 ctrl &= ~E1000_CTRL_ASDE; 13855779Sxy150489 13865779Sxy150489 /* Disable autoneg on the phy */ 13875779Sxy150489 *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; 13885779Sxy150489 13895779Sxy150489 /* Forcing Full or Half Duplex? */ 13905779Sxy150489 if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { 13915779Sxy150489 ctrl &= ~E1000_CTRL_FD; 13925779Sxy150489 *phy_ctrl &= ~MII_CR_FULL_DUPLEX; 13935779Sxy150489 DEBUGOUT("Half Duplex\n"); 13945779Sxy150489 } else { 13955779Sxy150489 ctrl |= E1000_CTRL_FD; 13965779Sxy150489 *phy_ctrl |= MII_CR_FULL_DUPLEX; 13975779Sxy150489 DEBUGOUT("Full Duplex\n"); 13985779Sxy150489 } 13995779Sxy150489 14005779Sxy150489 /* Forcing 10mb or 100mb? */ 14015779Sxy150489 if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { 14025779Sxy150489 ctrl |= E1000_CTRL_SPD_100; 14035779Sxy150489 *phy_ctrl |= MII_CR_SPEED_100; 14045779Sxy150489 *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); 14055779Sxy150489 DEBUGOUT("Forcing 100mb\n"); 14065779Sxy150489 } else { 14075779Sxy150489 ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); 14085779Sxy150489 /* LINTED */ 14095779Sxy150489 *phy_ctrl |= MII_CR_SPEED_10; 14105779Sxy150489 *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); 14115779Sxy150489 DEBUGOUT("Forcing 10mb\n"); 14125779Sxy150489 } 14135779Sxy150489 14145779Sxy150489 e1000_config_collision_dist_generic(hw); 14155779Sxy150489 14165779Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 14175779Sxy150489 } 14185779Sxy150489 14195779Sxy150489 /* 14205779Sxy150489 * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3 14215779Sxy150489 * @hw: pointer to the HW structure 14225779Sxy150489 * @active: boolean used to enable/disable lplu 14235779Sxy150489 * 14245779Sxy150489 * Success returns 0, Failure returns 1 14255779Sxy150489 * 14265779Sxy150489 * The low power link up (lplu) state is set to the power management level D3 14275779Sxy150489 * and SmartSpeed is disabled when active is true, else clear lplu for D3 14285779Sxy150489 * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU 14295779Sxy150489 * is used during Dx states where the power conservation is most important. 14305779Sxy150489 * During driver activity, SmartSpeed should be enabled so performance is 14315779Sxy150489 * maintained. 14325779Sxy150489 */ 14335779Sxy150489 s32 14345779Sxy150489 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active) 14355779Sxy150489 { 14365779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 14378571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 14385779Sxy150489 u16 data; 14395779Sxy150489 14405779Sxy150489 DEBUGFUNC("e1000_set_d3_lplu_state_generic"); 14415779Sxy150489 14428571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg)) 14438571SChenlu.Chen@Sun.COM goto out; 14448571SChenlu.Chen@Sun.COM 14458571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); 14465779Sxy150489 if (ret_val) 14475779Sxy150489 goto out; 14485779Sxy150489 14495779Sxy150489 if (!active) { 14505779Sxy150489 data &= ~IGP02E1000_PM_D3_LPLU; 14518571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, 14525779Sxy150489 IGP02E1000_PHY_POWER_MGMT, 14535779Sxy150489 data); 14545779Sxy150489 if (ret_val) 14555779Sxy150489 goto out; 14565779Sxy150489 /* 14575779Sxy150489 * LPLU and SmartSpeed are mutually exclusive. LPLU is used 14585779Sxy150489 * during Dx states where the power conservation is most 14595779Sxy150489 * important. During driver activity we should enable 14605779Sxy150489 * SmartSpeed, so performance is maintained. 14615779Sxy150489 */ 14625779Sxy150489 if (phy->smart_speed == e1000_smart_speed_on) { 14638571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, 14645779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, 14655779Sxy150489 &data); 14665779Sxy150489 if (ret_val) 14675779Sxy150489 goto out; 14685779Sxy150489 14695779Sxy150489 data |= IGP01E1000_PSCFR_SMART_SPEED; 14708571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, 14715779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, 14725779Sxy150489 data); 14735779Sxy150489 if (ret_val) 14745779Sxy150489 goto out; 14755779Sxy150489 } else if (phy->smart_speed == e1000_smart_speed_off) { 14768571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, 14775779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, 14785779Sxy150489 &data); 14795779Sxy150489 if (ret_val) 14805779Sxy150489 goto out; 14815779Sxy150489 14825779Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED; 14838571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, 14845779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, 14855779Sxy150489 data); 14865779Sxy150489 if (ret_val) 14875779Sxy150489 goto out; 14885779Sxy150489 } 14895779Sxy150489 } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 14905779Sxy150489 (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 14915779Sxy150489 (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 14925779Sxy150489 data |= IGP02E1000_PM_D3_LPLU; 14938571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, 14945779Sxy150489 IGP02E1000_PHY_POWER_MGMT, 14955779Sxy150489 data); 14965779Sxy150489 if (ret_val) 14975779Sxy150489 goto out; 14985779Sxy150489 14995779Sxy150489 /* When LPLU is enabled, we should disable SmartSpeed */ 15008571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, 15015779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, 15025779Sxy150489 &data); 15035779Sxy150489 if (ret_val) 15045779Sxy150489 goto out; 15055779Sxy150489 15065779Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED; 15078571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, 15085779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, 15095779Sxy150489 data); 15105779Sxy150489 } 15115779Sxy150489 15125779Sxy150489 out: 15135779Sxy150489 return (ret_val); 15145779Sxy150489 } 15155779Sxy150489 15165779Sxy150489 /* 15178571SChenlu.Chen@Sun.COM * e1000_check_downshift_generic - Checks whether a downshift in speed occurred 15185779Sxy150489 * @hw: pointer to the HW structure 15195779Sxy150489 * 15205779Sxy150489 * Success returns 0, Failure returns 1 15215779Sxy150489 * 15225779Sxy150489 * A downshift is detected by querying the PHY link health. 15235779Sxy150489 */ 15245779Sxy150489 s32 15255779Sxy150489 e1000_check_downshift_generic(struct e1000_hw *hw) 15265779Sxy150489 { 15275779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 15285779Sxy150489 s32 ret_val; 15295779Sxy150489 u16 phy_data, offset, mask; 15305779Sxy150489 15315779Sxy150489 DEBUGFUNC("e1000_check_downshift_generic"); 15325779Sxy150489 15335779Sxy150489 switch (phy->type) { 15345779Sxy150489 case e1000_phy_m88: 15355779Sxy150489 case e1000_phy_gg82563: 15365779Sxy150489 offset = M88E1000_PHY_SPEC_STATUS; 15375779Sxy150489 mask = M88E1000_PSSR_DOWNSHIFT; 15385779Sxy150489 break; 15395779Sxy150489 case e1000_phy_igp_2: 15405779Sxy150489 case e1000_phy_igp: 15415779Sxy150489 case e1000_phy_igp_3: 15425779Sxy150489 offset = IGP01E1000_PHY_LINK_HEALTH; 15435779Sxy150489 mask = IGP01E1000_PLHR_SS_DOWNGRADE; 15445779Sxy150489 break; 15455779Sxy150489 default: 15465779Sxy150489 /* speed downshift not supported */ 15478571SChenlu.Chen@Sun.COM phy->speed_downgraded = false; 15485779Sxy150489 ret_val = E1000_SUCCESS; 15495779Sxy150489 goto out; 15505779Sxy150489 } 15515779Sxy150489 15528571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, offset, &phy_data); 15535779Sxy150489 15545779Sxy150489 if (!ret_val) 15558571SChenlu.Chen@Sun.COM phy->speed_downgraded = (phy_data & mask) ? true : false; 15565779Sxy150489 15575779Sxy150489 out: 15585779Sxy150489 return (ret_val); 15595779Sxy150489 } 15605779Sxy150489 15615779Sxy150489 /* 15625779Sxy150489 * e1000_check_polarity_m88 - Checks the polarity. 15635779Sxy150489 * @hw: pointer to the HW structure 15645779Sxy150489 * 15655779Sxy150489 * Success returns 0, Failure returns -E1000_ERR_PHY (-2) 15665779Sxy150489 * 15675779Sxy150489 * Polarity is determined based on the PHY specific status register. 15685779Sxy150489 */ 15695779Sxy150489 s32 15705779Sxy150489 e1000_check_polarity_m88(struct e1000_hw *hw) 15715779Sxy150489 { 15725779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 15735779Sxy150489 s32 ret_val; 15745779Sxy150489 u16 data; 15755779Sxy150489 15765779Sxy150489 DEBUGFUNC("e1000_check_polarity_m88"); 15775779Sxy150489 15788571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data); 15795779Sxy150489 15805779Sxy150489 if (!ret_val) 15815779Sxy150489 phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) 15825779Sxy150489 ? e1000_rev_polarity_reversed 15835779Sxy150489 : e1000_rev_polarity_normal; 15845779Sxy150489 15855779Sxy150489 return (ret_val); 15865779Sxy150489 } 15875779Sxy150489 15885779Sxy150489 /* 15895779Sxy150489 * e1000_check_polarity_igp - Checks the polarity. 15905779Sxy150489 * @hw: pointer to the HW structure 15915779Sxy150489 * 15925779Sxy150489 * Success returns 0, Failure returns -E1000_ERR_PHY (-2) 15935779Sxy150489 * 15945779Sxy150489 * Polarity is determined based on the PHY port status register, and the 15955779Sxy150489 * current speed (since there is no polarity at 100Mbps). 15965779Sxy150489 */ 15975779Sxy150489 s32 15985779Sxy150489 e1000_check_polarity_igp(struct e1000_hw *hw) 15995779Sxy150489 { 16005779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 16015779Sxy150489 s32 ret_val; 16025779Sxy150489 u16 data, offset, mask; 16035779Sxy150489 16045779Sxy150489 DEBUGFUNC("e1000_check_polarity_igp"); 16055779Sxy150489 16065779Sxy150489 /* 16075779Sxy150489 * Polarity is determined based on the speed of 16085779Sxy150489 * our connection. 16095779Sxy150489 */ 16108571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); 16115779Sxy150489 if (ret_val) 16125779Sxy150489 goto out; 16135779Sxy150489 16145779Sxy150489 if ((data & IGP01E1000_PSSR_SPEED_MASK) == 16155779Sxy150489 IGP01E1000_PSSR_SPEED_1000MBPS) { 16165779Sxy150489 offset = IGP01E1000_PHY_PCS_INIT_REG; 16175779Sxy150489 mask = IGP01E1000_PHY_POLARITY_MASK; 16185779Sxy150489 } else { 16195779Sxy150489 /* 16205779Sxy150489 * This really only applies to 10Mbps since 16215779Sxy150489 * there is no polarity for 100Mbps (always 0). 16225779Sxy150489 */ 16235779Sxy150489 offset = IGP01E1000_PHY_PORT_STATUS; 16245779Sxy150489 mask = IGP01E1000_PSSR_POLARITY_REVERSED; 16255779Sxy150489 } 16265779Sxy150489 16278571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, offset, &data); 16285779Sxy150489 16295779Sxy150489 if (!ret_val) 16305779Sxy150489 phy->cable_polarity = (data & mask) 16315779Sxy150489 ? e1000_rev_polarity_reversed 16325779Sxy150489 : e1000_rev_polarity_normal; 16335779Sxy150489 16345779Sxy150489 out: 16355779Sxy150489 return (ret_val); 16365779Sxy150489 } 16375779Sxy150489 16385779Sxy150489 /* 1639*10319SJason.Xu@Sun.COM * e1000_check_polarity_ife - Check cable polarity for IFE PHY 1640*10319SJason.Xu@Sun.COM * @hw: pointer to the HW structure 1641*10319SJason.Xu@Sun.COM * 1642*10319SJason.Xu@Sun.COM * Polarity is determined on the polarity reversal feature being enabled. 1643*10319SJason.Xu@Sun.COM */ 1644*10319SJason.Xu@Sun.COM s32 1645*10319SJason.Xu@Sun.COM e1000_check_polarity_ife(struct e1000_hw *hw) 1646*10319SJason.Xu@Sun.COM { 1647*10319SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy; 1648*10319SJason.Xu@Sun.COM s32 ret_val; 1649*10319SJason.Xu@Sun.COM u16 phy_data, offset, mask; 1650*10319SJason.Xu@Sun.COM 1651*10319SJason.Xu@Sun.COM DEBUGFUNC("e1000_check_polarity_ife"); 1652*10319SJason.Xu@Sun.COM 1653*10319SJason.Xu@Sun.COM /* 1654*10319SJason.Xu@Sun.COM * Polarity is determined based on the reversal feature being enabled. 1655*10319SJason.Xu@Sun.COM */ 1656*10319SJason.Xu@Sun.COM if (phy->polarity_correction) { 1657*10319SJason.Xu@Sun.COM offset = IFE_PHY_EXTENDED_STATUS_CONTROL; 1658*10319SJason.Xu@Sun.COM mask = IFE_PESC_POLARITY_REVERSED; 1659*10319SJason.Xu@Sun.COM } else { 1660*10319SJason.Xu@Sun.COM offset = IFE_PHY_SPECIAL_CONTROL; 1661*10319SJason.Xu@Sun.COM mask = IFE_PSC_FORCE_POLARITY; 1662*10319SJason.Xu@Sun.COM } 1663*10319SJason.Xu@Sun.COM 1664*10319SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, offset, &phy_data); 1665*10319SJason.Xu@Sun.COM 1666*10319SJason.Xu@Sun.COM if (!ret_val) 1667*10319SJason.Xu@Sun.COM phy->cable_polarity = (phy_data & mask) 1668*10319SJason.Xu@Sun.COM ? e1000_rev_polarity_reversed 1669*10319SJason.Xu@Sun.COM : e1000_rev_polarity_normal; 1670*10319SJason.Xu@Sun.COM 1671*10319SJason.Xu@Sun.COM return (ret_val); 1672*10319SJason.Xu@Sun.COM } 1673*10319SJason.Xu@Sun.COM /* 16748571SChenlu.Chen@Sun.COM * e1000_wait_autoneg_generic - Wait for auto-neg completion 16755779Sxy150489 * @hw: pointer to the HW structure 16765779Sxy150489 * 16775779Sxy150489 * Waits for auto-negotiation to complete or for the auto-negotiation time 16785779Sxy150489 * limit to expire, which ever happens first. 16795779Sxy150489 */ 16805779Sxy150489 s32 16815779Sxy150489 e1000_wait_autoneg_generic(struct e1000_hw *hw) 16825779Sxy150489 { 16835779Sxy150489 s32 ret_val = E1000_SUCCESS; 16845779Sxy150489 u16 i, phy_status; 16855779Sxy150489 16865779Sxy150489 DEBUGFUNC("e1000_wait_autoneg_generic"); 16875779Sxy150489 16888571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg)) 16898571SChenlu.Chen@Sun.COM return (E1000_SUCCESS); 16908571SChenlu.Chen@Sun.COM 16915779Sxy150489 /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ 16925779Sxy150489 for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { 16938571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); 16945779Sxy150489 if (ret_val) 16955779Sxy150489 break; 16968571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); 16975779Sxy150489 if (ret_val) 16985779Sxy150489 break; 16995779Sxy150489 if (phy_status & MII_SR_AUTONEG_COMPLETE) 17005779Sxy150489 break; 17015779Sxy150489 msec_delay(100); 17025779Sxy150489 } 17035779Sxy150489 17045779Sxy150489 /* 17055779Sxy150489 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation 17065779Sxy150489 * has completed. 17075779Sxy150489 */ 17085779Sxy150489 return (ret_val); 17095779Sxy150489 } 17105779Sxy150489 17115779Sxy150489 /* 17125779Sxy150489 * e1000_phy_has_link_generic - Polls PHY for link 17135779Sxy150489 * @hw: pointer to the HW structure 17145779Sxy150489 * @iterations: number of times to poll for link 17155779Sxy150489 * @usec_interval: delay between polling attempts 17165779Sxy150489 * @success: pointer to whether polling was successful or not 17175779Sxy150489 * 17185779Sxy150489 * Polls the PHY status register for link, 'iterations' number of times. 17195779Sxy150489 */ 17205779Sxy150489 s32 17215779Sxy150489 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, 17225779Sxy150489 u32 usec_interval, bool *success) 17235779Sxy150489 { 17245779Sxy150489 s32 ret_val = E1000_SUCCESS; 17255779Sxy150489 u16 i, phy_status; 17265779Sxy150489 17275779Sxy150489 DEBUGFUNC("e1000_phy_has_link_generic"); 17285779Sxy150489 17298571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg)) 17308571SChenlu.Chen@Sun.COM return (E1000_SUCCESS); 17318571SChenlu.Chen@Sun.COM 17325779Sxy150489 for (i = 0; i < iterations; i++) { 17335779Sxy150489 /* 17345779Sxy150489 * Some PHYs require the PHY_STATUS register to be read 17355779Sxy150489 * twice due to the link bit being sticky. No harm doing 17365779Sxy150489 * it across the board. 17375779Sxy150489 */ 17388571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); 1739*10319SJason.Xu@Sun.COM if (ret_val) { 1740*10319SJason.Xu@Sun.COM /* 1741*10319SJason.Xu@Sun.COM * If the first read fails, another entity may have 1742*10319SJason.Xu@Sun.COM * ownership of the resources, wait and try again to 1743*10319SJason.Xu@Sun.COM * see if they have relinquished the resources yet. 1744*10319SJason.Xu@Sun.COM */ 1745*10319SJason.Xu@Sun.COM usec_delay(usec_interval); 1746*10319SJason.Xu@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, 1747*10319SJason.Xu@Sun.COM &phy_status); 1748*10319SJason.Xu@Sun.COM } 17495779Sxy150489 if (ret_val) 17505779Sxy150489 break; 17515779Sxy150489 if (phy_status & MII_SR_LINK_STATUS) 17525779Sxy150489 break; 17535779Sxy150489 if (usec_interval >= 1000) 17545779Sxy150489 msec_delay_irq(usec_interval/1000); 17555779Sxy150489 else 17565779Sxy150489 usec_delay(usec_interval); 17575779Sxy150489 } 17585779Sxy150489 17598571SChenlu.Chen@Sun.COM *success = (i < iterations) ? true : false; 17605779Sxy150489 17615779Sxy150489 return (ret_val); 17625779Sxy150489 } 17635779Sxy150489 17645779Sxy150489 /* 17655779Sxy150489 * e1000_get_cable_length_m88 - Determine cable length for m88 PHY 17665779Sxy150489 * @hw: pointer to the HW structure 17675779Sxy150489 * 17685779Sxy150489 * Reads the PHY specific status register to retrieve the cable length 17695779Sxy150489 * information. The cable length is determined by averaging the minimum and 17705779Sxy150489 * maximum values to get the "average" cable length. The m88 PHY has four 17715779Sxy150489 * possible cable length values, which are: 17725779Sxy150489 * Register Value Cable Length 17735779Sxy150489 * 0 < 50 meters 17745779Sxy150489 * 1 50 - 80 meters 17755779Sxy150489 * 2 80 - 110 meters 17765779Sxy150489 * 3 110 - 140 meters 17775779Sxy150489 * 4 > 140 meters 17785779Sxy150489 */ 17795779Sxy150489 s32 17805779Sxy150489 e1000_get_cable_length_m88(struct e1000_hw *hw) 17815779Sxy150489 { 17825779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 17835779Sxy150489 s32 ret_val; 17845779Sxy150489 u16 phy_data, index; 17855779Sxy150489 17865779Sxy150489 DEBUGFUNC("e1000_get_cable_length_m88"); 17875779Sxy150489 17888571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); 17895779Sxy150489 if (ret_val) 17905779Sxy150489 goto out; 17915779Sxy150489 17925779Sxy150489 index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> 17935779Sxy150489 M88E1000_PSSR_CABLE_LENGTH_SHIFT; 17948571SChenlu.Chen@Sun.COM if (index < (M88E1000_CABLE_LENGTH_TABLE_SIZE + 1)) { 1795*10319SJason.Xu@Sun.COM ret_val = E1000_ERR_PHY; 1796*10319SJason.Xu@Sun.COM goto out; 1797*10319SJason.Xu@Sun.COM } 17985779Sxy150489 1799*10319SJason.Xu@Sun.COM phy->min_cable_length = e1000_m88_cable_length_table[index]; 1800*10319SJason.Xu@Sun.COM phy->max_cable_length = e1000_m88_cable_length_table[index+1]; 1801*10319SJason.Xu@Sun.COM 1802*10319SJason.Xu@Sun.COM phy->cable_length = (phy->min_cable_length + 1803*10319SJason.Xu@Sun.COM phy->max_cable_length) / 2; 18045779Sxy150489 18055779Sxy150489 out: 18065779Sxy150489 return (ret_val); 18075779Sxy150489 } 18085779Sxy150489 18095779Sxy150489 /* 18105779Sxy150489 * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY 18115779Sxy150489 * @hw: pointer to the HW structure 18125779Sxy150489 * 18135779Sxy150489 * The automatic gain control (agc) normalizes the amplitude of the 18145779Sxy150489 * received signal, adjusting for the attenuation produced by the 18158571SChenlu.Chen@Sun.COM * cable. By reading the AGC registers, which represent the 18168571SChenlu.Chen@Sun.COM * combination of coarse and fine gain value, the value can be put 18175779Sxy150489 * into a lookup table to obtain the approximate cable length 18185779Sxy150489 * for each channel. 18195779Sxy150489 */ 18205779Sxy150489 s32 18215779Sxy150489 e1000_get_cable_length_igp_2(struct e1000_hw *hw) 18225779Sxy150489 { 18235779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 18245779Sxy150489 s32 ret_val = E1000_SUCCESS; 18255779Sxy150489 u16 phy_data, i, agc_value = 0; 18265779Sxy150489 u16 cur_agc_index, max_agc_index = 0; 18275779Sxy150489 u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; 18285779Sxy150489 u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = 18295779Sxy150489 {IGP02E1000_PHY_AGC_A, 18305779Sxy150489 IGP02E1000_PHY_AGC_B, 18315779Sxy150489 IGP02E1000_PHY_AGC_C, 18325779Sxy150489 IGP02E1000_PHY_AGC_D}; 18335779Sxy150489 18345779Sxy150489 DEBUGFUNC("e1000_get_cable_length_igp_2"); 18355779Sxy150489 18365779Sxy150489 /* Read the AGC registers for all channels */ 18375779Sxy150489 for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { 18388571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data); 18395779Sxy150489 if (ret_val) 18405779Sxy150489 goto out; 18415779Sxy150489 18425779Sxy150489 /* 18435779Sxy150489 * Getting bits 15:9, which represent the combination of 18448571SChenlu.Chen@Sun.COM * coarse and fine gain values. The result is a number 18455779Sxy150489 * that can be put into the lookup table to obtain the 18465779Sxy150489 * approximate cable length. 18475779Sxy150489 */ 18485779Sxy150489 cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & 18495779Sxy150489 IGP02E1000_AGC_LENGTH_MASK; 18505779Sxy150489 18515779Sxy150489 /* Array index bound check. */ 18525779Sxy150489 if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || 18535779Sxy150489 (cur_agc_index == 0)) { 18545779Sxy150489 ret_val = -E1000_ERR_PHY; 18555779Sxy150489 goto out; 18565779Sxy150489 } 18575779Sxy150489 18585779Sxy150489 /* Remove min & max AGC values from calculation. */ 18595779Sxy150489 if (e1000_igp_2_cable_length_table[min_agc_index] > 18605779Sxy150489 e1000_igp_2_cable_length_table[cur_agc_index]) 18615779Sxy150489 min_agc_index = cur_agc_index; 18625779Sxy150489 if (e1000_igp_2_cable_length_table[max_agc_index] < 18635779Sxy150489 e1000_igp_2_cable_length_table[cur_agc_index]) 18645779Sxy150489 max_agc_index = cur_agc_index; 18655779Sxy150489 18665779Sxy150489 agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; 18675779Sxy150489 } 18685779Sxy150489 18695779Sxy150489 agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + 18705779Sxy150489 e1000_igp_2_cable_length_table[max_agc_index]); 18715779Sxy150489 agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); 18725779Sxy150489 18735779Sxy150489 /* Calculate cable length with the error range of +/- 10 meters. */ 18745779Sxy150489 phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? 18755779Sxy150489 (agc_value - IGP02E1000_AGC_RANGE) : 0; 18765779Sxy150489 phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; 18775779Sxy150489 18785779Sxy150489 phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; 18795779Sxy150489 18805779Sxy150489 out: 18815779Sxy150489 return (ret_val); 18825779Sxy150489 } 18835779Sxy150489 18845779Sxy150489 /* 18855779Sxy150489 * e1000_get_phy_info_m88 - Retrieve PHY information 18865779Sxy150489 * @hw: pointer to the HW structure 18875779Sxy150489 * 18885779Sxy150489 * Valid for only copper links. Read the PHY status register (sticky read) 18895779Sxy150489 * to verify that link is up. Read the PHY special control register to 18905779Sxy150489 * determine the polarity and 10base-T extended distance. Read the PHY 18915779Sxy150489 * special status register to determine MDI/MDIx and current speed. If 18925779Sxy150489 * speed is 1000, then determine cable length, local and remote receiver. 18935779Sxy150489 */ 18945779Sxy150489 s32 18955779Sxy150489 e1000_get_phy_info_m88(struct e1000_hw *hw) 18965779Sxy150489 { 18975779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 18985779Sxy150489 s32 ret_val; 18995779Sxy150489 u16 phy_data; 19005779Sxy150489 bool link; 19015779Sxy150489 19025779Sxy150489 DEBUGFUNC("e1000_get_phy_info_m88"); 19035779Sxy150489 19045779Sxy150489 if (hw->phy.media_type != e1000_media_type_copper) { 19055779Sxy150489 DEBUGOUT("Phy info is only valid for copper media\n"); 19065779Sxy150489 ret_val = -E1000_ERR_CONFIG; 19075779Sxy150489 goto out; 19085779Sxy150489 } 19095779Sxy150489 19105779Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 19115779Sxy150489 if (ret_val) 19125779Sxy150489 goto out; 19135779Sxy150489 19145779Sxy150489 if (!link) { 19155779Sxy150489 DEBUGOUT("Phy info is only valid if link is up\n"); 19165779Sxy150489 ret_val = -E1000_ERR_CONFIG; 19175779Sxy150489 goto out; 19185779Sxy150489 } 19195779Sxy150489 19208571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); 19215779Sxy150489 if (ret_val) 19225779Sxy150489 goto out; 19235779Sxy150489 19245779Sxy150489 phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) 19258571SChenlu.Chen@Sun.COM ? true : false; 19265779Sxy150489 19275779Sxy150489 ret_val = e1000_check_polarity_m88(hw); 19285779Sxy150489 if (ret_val) 19295779Sxy150489 goto out; 19305779Sxy150489 19318571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); 19325779Sxy150489 if (ret_val) 19335779Sxy150489 goto out; 19345779Sxy150489 19358571SChenlu.Chen@Sun.COM phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; 19365779Sxy150489 19375779Sxy150489 if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { 19388571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.get_cable_length(hw); 19395779Sxy150489 if (ret_val) 19405779Sxy150489 goto out; 19415779Sxy150489 19428571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); 19435779Sxy150489 if (ret_val) 19445779Sxy150489 goto out; 19455779Sxy150489 19465779Sxy150489 phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) 19475779Sxy150489 ? e1000_1000t_rx_status_ok 19485779Sxy150489 : e1000_1000t_rx_status_not_ok; 19495779Sxy150489 19505779Sxy150489 phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) 19515779Sxy150489 ? e1000_1000t_rx_status_ok 19525779Sxy150489 : e1000_1000t_rx_status_not_ok; 19535779Sxy150489 } else { 19545779Sxy150489 /* Set values to "undefined" */ 19555779Sxy150489 phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; 19565779Sxy150489 phy->local_rx = e1000_1000t_rx_status_undefined; 19575779Sxy150489 phy->remote_rx = e1000_1000t_rx_status_undefined; 19585779Sxy150489 } 19595779Sxy150489 19605779Sxy150489 out: 19615779Sxy150489 return (ret_val); 19625779Sxy150489 } 19635779Sxy150489 19645779Sxy150489 /* 19655779Sxy150489 * e1000_get_phy_info_igp - Retrieve igp PHY information 19665779Sxy150489 * @hw: pointer to the HW structure 19675779Sxy150489 * 19685779Sxy150489 * Read PHY status to determine if link is up. If link is up, then 19695779Sxy150489 * set/determine 10base-T extended distance and polarity correction. Read 19705779Sxy150489 * PHY port status to determine MDI/MDIx and speed. Based on the speed, 19715779Sxy150489 * determine on the cable length, local and remote receiver. 19725779Sxy150489 */ 19735779Sxy150489 s32 19745779Sxy150489 e1000_get_phy_info_igp(struct e1000_hw *hw) 19755779Sxy150489 { 19765779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 19775779Sxy150489 s32 ret_val; 19785779Sxy150489 u16 data; 19795779Sxy150489 bool link; 19805779Sxy150489 19815779Sxy150489 DEBUGFUNC("e1000_get_phy_info_igp"); 19825779Sxy150489 19835779Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 19845779Sxy150489 if (ret_val) 19855779Sxy150489 goto out; 19865779Sxy150489 19875779Sxy150489 if (!link) { 19885779Sxy150489 DEBUGOUT("Phy info is only valid if link is up\n"); 19895779Sxy150489 ret_val = -E1000_ERR_CONFIG; 19905779Sxy150489 goto out; 19915779Sxy150489 } 19925779Sxy150489 19938571SChenlu.Chen@Sun.COM phy->polarity_correction = true; 19945779Sxy150489 19955779Sxy150489 ret_val = e1000_check_polarity_igp(hw); 19965779Sxy150489 if (ret_val) 19975779Sxy150489 goto out; 19985779Sxy150489 19998571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); 20005779Sxy150489 if (ret_val) 20015779Sxy150489 goto out; 20025779Sxy150489 20038571SChenlu.Chen@Sun.COM phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; 20045779Sxy150489 20055779Sxy150489 if ((data & IGP01E1000_PSSR_SPEED_MASK) == 20065779Sxy150489 IGP01E1000_PSSR_SPEED_1000MBPS) { 20078571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.get_cable_length(hw); 20085779Sxy150489 if (ret_val) 20095779Sxy150489 goto out; 20105779Sxy150489 20118571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data); 20125779Sxy150489 if (ret_val) 20135779Sxy150489 goto out; 20145779Sxy150489 20155779Sxy150489 phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) 20165779Sxy150489 ? e1000_1000t_rx_status_ok 20175779Sxy150489 : e1000_1000t_rx_status_not_ok; 20185779Sxy150489 20195779Sxy150489 phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) 20205779Sxy150489 ? e1000_1000t_rx_status_ok 20215779Sxy150489 : e1000_1000t_rx_status_not_ok; 20225779Sxy150489 } else { 20235779Sxy150489 phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; 20245779Sxy150489 phy->local_rx = e1000_1000t_rx_status_undefined; 20255779Sxy150489 phy->remote_rx = e1000_1000t_rx_status_undefined; 20265779Sxy150489 } 20275779Sxy150489 20285779Sxy150489 out: 20295779Sxy150489 return (ret_val); 20305779Sxy150489 } 20315779Sxy150489 20325779Sxy150489 /* 20335779Sxy150489 * e1000_phy_sw_reset_generic - PHY software reset 20345779Sxy150489 * @hw: pointer to the HW structure 20355779Sxy150489 * 20365779Sxy150489 * Does a software reset of the PHY by reading the PHY control register and 20375779Sxy150489 * setting/write the control register reset bit to the PHY. 20385779Sxy150489 */ 20395779Sxy150489 s32 20405779Sxy150489 e1000_phy_sw_reset_generic(struct e1000_hw *hw) 20415779Sxy150489 { 20428571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 20435779Sxy150489 u16 phy_ctrl; 20445779Sxy150489 20455779Sxy150489 DEBUGFUNC("e1000_phy_sw_reset_generic"); 20465779Sxy150489 20478571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg)) 20488571SChenlu.Chen@Sun.COM goto out; 20498571SChenlu.Chen@Sun.COM 20508571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); 20515779Sxy150489 if (ret_val) 20525779Sxy150489 goto out; 20535779Sxy150489 20545779Sxy150489 phy_ctrl |= MII_CR_RESET; 20558571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl); 20565779Sxy150489 if (ret_val) 20575779Sxy150489 goto out; 20585779Sxy150489 20595779Sxy150489 usec_delay(1); 20605779Sxy150489 20615779Sxy150489 out: 20625779Sxy150489 return (ret_val); 20635779Sxy150489 } 20645779Sxy150489 20655779Sxy150489 /* 20665779Sxy150489 * e1000_phy_hw_reset_generic - PHY hardware reset 20675779Sxy150489 * @hw: pointer to the HW structure 20685779Sxy150489 * 20695779Sxy150489 * Verify the reset block is not blocking us from resetting. Acquire 20705779Sxy150489 * semaphore (if necessary) and read/set/write the device control reset 20715779Sxy150489 * bit in the PHY. Wait the appropriate delay time for the device to 20728571SChenlu.Chen@Sun.COM * reset and release the semaphore (if necessary). 20735779Sxy150489 */ 20745779Sxy150489 s32 20755779Sxy150489 e1000_phy_hw_reset_generic(struct e1000_hw *hw) 20765779Sxy150489 { 20775779Sxy150489 struct e1000_phy_info *phy = &hw->phy; 20788571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS; 20795779Sxy150489 u32 ctrl; 20805779Sxy150489 20815779Sxy150489 DEBUGFUNC("e1000_phy_hw_reset_generic"); 20825779Sxy150489 20838571SChenlu.Chen@Sun.COM ret_val = phy->ops.check_reset_block(hw); 20845779Sxy150489 if (ret_val) { 20855779Sxy150489 ret_val = E1000_SUCCESS; 20865779Sxy150489 goto out; 20875779Sxy150489 } 20885779Sxy150489 20898571SChenlu.Chen@Sun.COM ret_val = phy->ops.acquire(hw); 20905779Sxy150489 if (ret_val) 20915779Sxy150489 goto out; 20925779Sxy150489 20935779Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 20945779Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); 20955779Sxy150489 E1000_WRITE_FLUSH(hw); 20965779Sxy150489 20975779Sxy150489 usec_delay(phy->reset_delay_us); 20985779Sxy150489 20995779Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 21005779Sxy150489 E1000_WRITE_FLUSH(hw); 21015779Sxy150489 21025779Sxy150489 usec_delay(150); 21035779Sxy150489 21048571SChenlu.Chen@Sun.COM phy->ops.release(hw); 21055779Sxy150489 21068571SChenlu.Chen@Sun.COM ret_val = phy->ops.get_cfg_done(hw); 21075779Sxy150489 21085779Sxy150489 out: 21095779Sxy150489 return (ret_val); 21105779Sxy150489 } 21115779Sxy150489 21125779Sxy150489 /* 21135779Sxy150489 * e1000_get_cfg_done_generic - Generic configuration done 21145779Sxy150489 * @hw: pointer to the HW structure 21155779Sxy150489 * 21165779Sxy150489 * Generic function to wait 10 milli-seconds for configuration to complete 21175779Sxy150489 * and return success. 21185779Sxy150489 */ 21195779Sxy150489 s32 21205779Sxy150489 e1000_get_cfg_done_generic(struct e1000_hw *hw) 21215779Sxy150489 { 21225779Sxy150489 DEBUGFUNC("e1000_get_cfg_done_generic"); 21238571SChenlu.Chen@Sun.COM UNREFERENCED_1PARAMETER(hw); 21245779Sxy150489 21255779Sxy150489 msec_delay_irq(10); 21265779Sxy150489 21275779Sxy150489 return (E1000_SUCCESS); 21285779Sxy150489 } 21295779Sxy150489 21305779Sxy150489 /* 21315779Sxy150489 * e1000_phy_init_script_igp3 - Inits the IGP3 PHY 21325779Sxy150489 * @hw: pointer to the HW structure 21335779Sxy150489 * 21345779Sxy150489 * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. 21355779Sxy150489 */ 21365779Sxy150489 s32 21375779Sxy150489 e1000_phy_init_script_igp3(struct e1000_hw *hw) 21385779Sxy150489 { 21395779Sxy150489 DEBUGOUT("Running IGP 3 PHY init script\n"); 21405779Sxy150489 21415779Sxy150489 /* PHY init IGP 3 */ 21425779Sxy150489 /* Enable rise/fall, 10-mode work in class-A */ 21438571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018); 21445779Sxy150489 /* Remove all caps from Replica path filter */ 21458571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2F52, 0x0000); 21465779Sxy150489 /* Bias trimming for ADC, AFE and Driver (Default) */ 21478571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24); 21485779Sxy150489 /* Increase Hybrid poly bias */ 21498571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0); 21508571SChenlu.Chen@Sun.COM /* Add 4% to Tx amplitude in Gig mode */ 21518571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2010, 0x10B0); 21525779Sxy150489 /* Disable trimming (TTT) */ 21538571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2011, 0x0000); 21545779Sxy150489 /* Poly DC correction to 94.6% + 2% for all channels */ 21558571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x20DD, 0x249A); 21565779Sxy150489 /* ABS DC correction to 95.9% */ 21578571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3); 21585779Sxy150489 /* BG temp curve trim */ 21598571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE); 21605779Sxy150489 /* Increasing ADC OPAMP stage 1 currents to max */ 21618571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4); 21625779Sxy150489 /* Force 1000 ( required for enabling PHY regs configuration) */ 21638571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0000, 0x0140); 21645779Sxy150489 /* Set upd_freq to 6 */ 21658571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F30, 0x1606); 21665779Sxy150489 /* Disable NPDFE */ 21678571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F31, 0xB814); 21685779Sxy150489 /* Disable adaptive fixed FFE (Default) */ 21698571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F35, 0x002A); 21705779Sxy150489 /* Enable FFE hysteresis */ 21718571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067); 21725779Sxy150489 /* Fixed FFE for short cable lengths */ 21738571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F54, 0x0065); 21745779Sxy150489 /* Fixed FFE for medium cable lengths */ 21758571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F55, 0x002A); 21765779Sxy150489 /* Fixed FFE for long cable lengths */ 21778571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F56, 0x002A); 21785779Sxy150489 /* Enable Adaptive Clip Threshold */ 21798571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0); 21805779Sxy150489 /* AHT reset limit to 1 */ 21818571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF); 21825779Sxy150489 /* Set AHT master delay to 127 msec */ 21838571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC); 21845779Sxy150489 /* Set scan bits for AHT */ 21858571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF); 21865779Sxy150489 /* Set AHT Preset bits */ 21878571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F79, 0x0210); 21885779Sxy150489 /* Change integ_factor of channel A to 3 */ 21898571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1895, 0x0003); 21905779Sxy150489 /* Change prop_factor of channels BCD to 8 */ 21918571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1796, 0x0008); 21925779Sxy150489 /* Change cg_icount + enable integbp for channels BCD */ 21938571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1798, 0xD008); 21945779Sxy150489 /* 21955779Sxy150489 * Change cg_icount + enable integbp + change prop_factor_master 21965779Sxy150489 * to 8 for channel A 21975779Sxy150489 */ 21988571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1898, 0xD918); 21995779Sxy150489 /* Disable AHT in Slave mode on channel A */ 22008571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x187A, 0x0800); 22015779Sxy150489 /* 22025779Sxy150489 * Enable LPLU and disable AN to 1000 in non-D0a states, 22035779Sxy150489 * Enable SPD+B2B 22045779Sxy150489 */ 22058571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0019, 0x008D); 22065779Sxy150489 /* Enable restart AN on an1000_dis change */ 22078571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x001B, 0x2080); 22085779Sxy150489 /* Enable wh_fifo read clock in 10/100 modes */ 22098571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0014, 0x0045); 22105779Sxy150489 /* Restart AN, Speed selection is 1000 */ 22118571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0000, 0x1340); 22125779Sxy150489 22135779Sxy150489 return (E1000_SUCCESS); 22145779Sxy150489 } 22155779Sxy150489 22165779Sxy150489 /* 22175779Sxy150489 * e1000_get_phy_type_from_id - Get PHY type from id 22185779Sxy150489 * @phy_id: phy_id read from the phy 22195779Sxy150489 * 22205779Sxy150489 * Returns the phy type from the id. 22215779Sxy150489 */ 22228571SChenlu.Chen@Sun.COM enum e1000_phy_type 22235779Sxy150489 e1000_get_phy_type_from_id(u32 phy_id) 22245779Sxy150489 { 22258571SChenlu.Chen@Sun.COM enum e1000_phy_type phy_type = e1000_phy_unknown; 22265779Sxy150489 22275779Sxy150489 switch (phy_id) { 22285779Sxy150489 case M88E1000_I_PHY_ID: 22295779Sxy150489 case M88E1000_E_PHY_ID: 22305779Sxy150489 case M88E1111_I_PHY_ID: 22315779Sxy150489 case M88E1011_I_PHY_ID: 22325779Sxy150489 phy_type = e1000_phy_m88; 22335779Sxy150489 break; 22345779Sxy150489 case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ 22355779Sxy150489 phy_type = e1000_phy_igp_2; 22365779Sxy150489 break; 22375779Sxy150489 case GG82563_E_PHY_ID: 22385779Sxy150489 phy_type = e1000_phy_gg82563; 22395779Sxy150489 break; 22405779Sxy150489 case IGP03E1000_E_PHY_ID: 22415779Sxy150489 phy_type = e1000_phy_igp_3; 22425779Sxy150489 break; 22435779Sxy150489 case IFE_E_PHY_ID: 22445779Sxy150489 case IFE_PLUS_E_PHY_ID: 22455779Sxy150489 case IFE_C_E_PHY_ID: 22465779Sxy150489 phy_type = e1000_phy_ife; 22475779Sxy150489 break; 22485779Sxy150489 default: 22495779Sxy150489 phy_type = e1000_phy_unknown; 22505779Sxy150489 break; 22515779Sxy150489 } 22525779Sxy150489 return (phy_type); 22535779Sxy150489 } 22545779Sxy150489 22555779Sxy150489 /* 2256*10319SJason.Xu@Sun.COM * e1000_determine_phy_address - Determines PHY address. 2257*10319SJason.Xu@Sun.COM * @hw: pointer to the HW structure 2258*10319SJason.Xu@Sun.COM * 2259*10319SJason.Xu@Sun.COM * This uses a trial and error method to loop through possible PHY 2260*10319SJason.Xu@Sun.COM * addresses. It tests each by reading the PHY ID registers and 2261*10319SJason.Xu@Sun.COM * checking for a match. 2262*10319SJason.Xu@Sun.COM */ 2263*10319SJason.Xu@Sun.COM s32 2264*10319SJason.Xu@Sun.COM e1000_determine_phy_address(struct e1000_hw *hw) 2265*10319SJason.Xu@Sun.COM { 2266*10319SJason.Xu@Sun.COM s32 ret_val = -E1000_ERR_PHY_TYPE; 2267*10319SJason.Xu@Sun.COM u32 phy_addr = 0; 2268*10319SJason.Xu@Sun.COM u32 i; 2269*10319SJason.Xu@Sun.COM enum e1000_phy_type phy_type = e1000_phy_unknown; 2270*10319SJason.Xu@Sun.COM 2271*10319SJason.Xu@Sun.COM hw->phy.id = phy_type; 2272*10319SJason.Xu@Sun.COM 2273*10319SJason.Xu@Sun.COM for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { 2274*10319SJason.Xu@Sun.COM hw->phy.addr = phy_addr; 2275*10319SJason.Xu@Sun.COM i = 0; 2276*10319SJason.Xu@Sun.COM 2277*10319SJason.Xu@Sun.COM do { 2278*10319SJason.Xu@Sun.COM e1000_get_phy_id(hw); 2279*10319SJason.Xu@Sun.COM phy_type = e1000_get_phy_type_from_id(hw->phy.id); 2280*10319SJason.Xu@Sun.COM 2281*10319SJason.Xu@Sun.COM /* 2282*10319SJason.Xu@Sun.COM * If phy_type is valid, break - we found our 2283*10319SJason.Xu@Sun.COM * PHY address 2284*10319SJason.Xu@Sun.COM */ 2285*10319SJason.Xu@Sun.COM if (phy_type != e1000_phy_unknown) { 2286*10319SJason.Xu@Sun.COM ret_val = E1000_SUCCESS; 2287*10319SJason.Xu@Sun.COM goto out; 2288*10319SJason.Xu@Sun.COM } 2289*10319SJason.Xu@Sun.COM msec_delay(1); 2290*10319SJason.Xu@Sun.COM i++; 2291*10319SJason.Xu@Sun.COM } while (i < 10); 2292*10319SJason.Xu@Sun.COM } 2293*10319SJason.Xu@Sun.COM 2294*10319SJason.Xu@Sun.COM out: 2295*10319SJason.Xu@Sun.COM return (ret_val); 2296*10319SJason.Xu@Sun.COM } 2297*10319SJason.Xu@Sun.COM /* 22985779Sxy150489 * e1000_power_up_phy_copper - Restore copper link in case of PHY power down 22995779Sxy150489 * @hw: pointer to the HW structure 23005779Sxy150489 * 23015779Sxy150489 * In the case of a PHY power down to save power, or to turn off link during a 23025779Sxy150489 * driver unload, or wake on lan is not enabled, restore the link to previous 23035779Sxy150489 * settings. 23045779Sxy150489 */ 23055779Sxy150489 void 23065779Sxy150489 e1000_power_up_phy_copper(struct e1000_hw *hw) 23075779Sxy150489 { 23085779Sxy150489 u16 mii_reg = 0; 23095779Sxy150489 23105779Sxy150489 /* The PHY will retain its settings across a power down/up cycle */ 23118571SChenlu.Chen@Sun.COM (void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); 23125779Sxy150489 mii_reg &= ~MII_CR_POWER_DOWN; 23138571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); 23145779Sxy150489 } 23155779Sxy150489 23165779Sxy150489 /* 23175779Sxy150489 * e1000_power_down_phy_copper - Restore copper link in case of PHY power down 23185779Sxy150489 * @hw: pointer to the HW structure 23195779Sxy150489 * 23205779Sxy150489 * In the case of a PHY power down to save power, or to turn off link during a 23215779Sxy150489 * driver unload, or wake on lan is not enabled, restore the link to previous 23225779Sxy150489 * settings. 23235779Sxy150489 */ 23245779Sxy150489 void 23255779Sxy150489 e1000_power_down_phy_copper(struct e1000_hw *hw) 23265779Sxy150489 { 23275779Sxy150489 u16 mii_reg = 0; 23285779Sxy150489 23295779Sxy150489 /* The PHY will retain its settings across a power down/up cycle */ 23308571SChenlu.Chen@Sun.COM (void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); 23315779Sxy150489 mii_reg |= MII_CR_POWER_DOWN; 23328571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); 23335779Sxy150489 msec_delay(1); 23345779Sxy150489 } 2335