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