15779Sxy150489 /*
25779Sxy150489 * CDDL HEADER START
35779Sxy150489 *
45779Sxy150489 * The contents of this file are subject to the terms of the
55779Sxy150489 * Common Development and Distribution License (the "License").
65779Sxy150489 * You may not use this file except in compliance with the License.
75779Sxy150489 *
8*12111SGuoqing.Zhu@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12111SGuoqing.Zhu@Sun.COM * or http://www.opensolaris.org/os/licensing.
105779Sxy150489 * See the License for the specific language governing permissions
115779Sxy150489 * and limitations under the License.
125779Sxy150489 *
13*12111SGuoqing.Zhu@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*12111SGuoqing.Zhu@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155779Sxy150489 * If applicable, add the following below this CDDL HEADER, with the
165779Sxy150489 * fields enclosed by brackets "[]" replaced with your own identifying
175779Sxy150489 * information: Portions Copyright [yyyy] [name of copyright owner]
185779Sxy150489 *
195779Sxy150489 * CDDL HEADER END
205779Sxy150489 */
215779Sxy150489
225779Sxy150489 /*
23*12111SGuoqing.Zhu@Sun.COM * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
245779Sxy150489 */
255779Sxy150489
26*12111SGuoqing.Zhu@Sun.COM /*
27*12111SGuoqing.Zhu@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28*12111SGuoqing.Zhu@Sun.COM */
29*12111SGuoqing.Zhu@Sun.COM
30*12111SGuoqing.Zhu@Sun.COM /* IntelVersion: 1.161 v3_3_14_3_BHSW1 */
315779Sxy150489
325779Sxy150489 #include "igb_api.h"
335779Sxy150489
3411155SJason.Xu@Sun.COM static s32 e1000_copper_link_autoneg(struct e1000_hw *hw);
358571SChenlu.Chen@Sun.COM static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
365779Sxy150489
375779Sxy150489 /* Cable length tables */
385779Sxy150489 static const u16 e1000_m88_cable_length_table[] =
395779Sxy150489 { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
405779Sxy150489
415779Sxy150489 #define M88E1000_CABLE_LENGTH_TABLE_SIZE \
425779Sxy150489 (sizeof (e1000_m88_cable_length_table) / \
435779Sxy150489 sizeof (e1000_m88_cable_length_table[0]))
445779Sxy150489
455779Sxy150489 static const u16 e1000_igp_2_cable_length_table[] =
465779Sxy150489 { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
475779Sxy150489 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
485779Sxy150489 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
495779Sxy150489 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
505779Sxy150489 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
515779Sxy150489 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
525779Sxy150489 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
535779Sxy150489 104, 109, 114, 118, 121, 124};
545779Sxy150489
555779Sxy150489 #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
565779Sxy150489 (sizeof (e1000_igp_2_cable_length_table) / \
575779Sxy150489 sizeof (e1000_igp_2_cable_length_table[0]))
585779Sxy150489
595779Sxy150489 /*
608571SChenlu.Chen@Sun.COM * e1000_init_phy_ops_generic - Initialize PHY function pointers
618571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure
628571SChenlu.Chen@Sun.COM *
638571SChenlu.Chen@Sun.COM * Setups up the function pointers to no-op functions
648571SChenlu.Chen@Sun.COM */
658571SChenlu.Chen@Sun.COM void
e1000_init_phy_ops_generic(struct e1000_hw * hw)668571SChenlu.Chen@Sun.COM e1000_init_phy_ops_generic(struct e1000_hw *hw)
678571SChenlu.Chen@Sun.COM {
688571SChenlu.Chen@Sun.COM struct e1000_phy_info *phy = &hw->phy;
698571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_init_phy_ops_generic");
708571SChenlu.Chen@Sun.COM
718571SChenlu.Chen@Sun.COM /* Initialize function pointers */
728571SChenlu.Chen@Sun.COM phy->ops.init_params = e1000_null_ops_generic;
738571SChenlu.Chen@Sun.COM phy->ops.acquire = e1000_null_ops_generic;
748571SChenlu.Chen@Sun.COM phy->ops.check_polarity = e1000_null_ops_generic;
758571SChenlu.Chen@Sun.COM phy->ops.check_reset_block = e1000_null_ops_generic;
768571SChenlu.Chen@Sun.COM phy->ops.commit = e1000_null_ops_generic;
778571SChenlu.Chen@Sun.COM phy->ops.force_speed_duplex = e1000_null_ops_generic;
788571SChenlu.Chen@Sun.COM phy->ops.get_cfg_done = e1000_null_ops_generic;
798571SChenlu.Chen@Sun.COM phy->ops.get_cable_length = e1000_null_ops_generic;
808571SChenlu.Chen@Sun.COM phy->ops.get_info = e1000_null_ops_generic;
818571SChenlu.Chen@Sun.COM phy->ops.read_reg = e1000_null_read_reg;
8211155SJason.Xu@Sun.COM phy->ops.read_reg_locked = e1000_null_read_reg;
838571SChenlu.Chen@Sun.COM phy->ops.release = e1000_null_phy_generic;
848571SChenlu.Chen@Sun.COM phy->ops.reset = e1000_null_ops_generic;
858571SChenlu.Chen@Sun.COM phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
868571SChenlu.Chen@Sun.COM phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
878571SChenlu.Chen@Sun.COM phy->ops.write_reg = e1000_null_write_reg;
8811155SJason.Xu@Sun.COM phy->ops.write_reg_locked = e1000_null_write_reg;
898571SChenlu.Chen@Sun.COM phy->ops.power_up = e1000_null_phy_generic;
908571SChenlu.Chen@Sun.COM phy->ops.power_down = e1000_null_phy_generic;
918571SChenlu.Chen@Sun.COM }
928571SChenlu.Chen@Sun.COM
938571SChenlu.Chen@Sun.COM /*
948571SChenlu.Chen@Sun.COM * e1000_null_read_reg - No-op function, return 0
958571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure
968571SChenlu.Chen@Sun.COM */
978571SChenlu.Chen@Sun.COM s32
e1000_null_read_reg(struct e1000_hw * hw,u32 offset,u16 * data)988571SChenlu.Chen@Sun.COM e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data)
998571SChenlu.Chen@Sun.COM {
1008571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_read_reg");
1018571SChenlu.Chen@Sun.COM UNREFERENCED_3PARAMETER(hw, offset, data);
1028571SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
1038571SChenlu.Chen@Sun.COM }
1048571SChenlu.Chen@Sun.COM
1058571SChenlu.Chen@Sun.COM /*
1068571SChenlu.Chen@Sun.COM * e1000_null_phy_generic - No-op function, return void
1078571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure
1088571SChenlu.Chen@Sun.COM */
1098571SChenlu.Chen@Sun.COM void
e1000_null_phy_generic(struct e1000_hw * hw)1108571SChenlu.Chen@Sun.COM e1000_null_phy_generic(struct e1000_hw *hw)
1118571SChenlu.Chen@Sun.COM {
1128571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_phy_generic");
1138571SChenlu.Chen@Sun.COM UNREFERENCED_1PARAMETER(hw);
1148571SChenlu.Chen@Sun.COM }
1158571SChenlu.Chen@Sun.COM
1168571SChenlu.Chen@Sun.COM /*
1178571SChenlu.Chen@Sun.COM * e1000_null_lplu_state - No-op function, return 0
1188571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure
1198571SChenlu.Chen@Sun.COM */
1208571SChenlu.Chen@Sun.COM s32
e1000_null_lplu_state(struct e1000_hw * hw,bool active)1218571SChenlu.Chen@Sun.COM e1000_null_lplu_state(struct e1000_hw *hw, bool active)
1228571SChenlu.Chen@Sun.COM {
1238571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_lplu_state");
1248571SChenlu.Chen@Sun.COM UNREFERENCED_2PARAMETER(hw, active);
1258571SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
1268571SChenlu.Chen@Sun.COM }
1278571SChenlu.Chen@Sun.COM
1288571SChenlu.Chen@Sun.COM /*
1298571SChenlu.Chen@Sun.COM * e1000_null_write_reg - No-op function, return 0
1308571SChenlu.Chen@Sun.COM * @hw: pointer to the HW structure
1318571SChenlu.Chen@Sun.COM */
1328571SChenlu.Chen@Sun.COM s32
e1000_null_write_reg(struct e1000_hw * hw,u32 offset,u16 data)1338571SChenlu.Chen@Sun.COM e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
1348571SChenlu.Chen@Sun.COM {
1358571SChenlu.Chen@Sun.COM DEBUGFUNC("e1000_null_write_reg");
1368571SChenlu.Chen@Sun.COM UNREFERENCED_3PARAMETER(hw, offset, data);
1378571SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
1388571SChenlu.Chen@Sun.COM }
1398571SChenlu.Chen@Sun.COM
1408571SChenlu.Chen@Sun.COM /*
1415779Sxy150489 * e1000_check_reset_block_generic - Check if PHY reset is blocked
1425779Sxy150489 * @hw: pointer to the HW structure
1435779Sxy150489 *
1445779Sxy150489 * Read the PHY management control register and check whether a PHY reset
1455779Sxy150489 * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise
1465779Sxy150489 * return E1000_BLK_PHY_RESET (12).
1475779Sxy150489 */
1485779Sxy150489 s32
e1000_check_reset_block_generic(struct e1000_hw * hw)1495779Sxy150489 e1000_check_reset_block_generic(struct e1000_hw *hw)
1505779Sxy150489 {
1515779Sxy150489 u32 manc;
1525779Sxy150489
1535779Sxy150489 DEBUGFUNC("e1000_check_reset_block");
1545779Sxy150489
1555779Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC);
1565779Sxy150489
1575779Sxy150489 return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
1585779Sxy150489 E1000_BLK_PHY_RESET : E1000_SUCCESS;
1595779Sxy150489 }
1605779Sxy150489
1615779Sxy150489 /*
1625779Sxy150489 * e1000_get_phy_id - Retrieve the PHY ID and revision
1635779Sxy150489 * @hw: pointer to the HW structure
1645779Sxy150489 *
1655779Sxy150489 * Reads the PHY registers and stores the PHY ID and possibly the PHY
1665779Sxy150489 * revision in the hardware structure.
1675779Sxy150489 */
1685779Sxy150489 s32
e1000_get_phy_id(struct e1000_hw * hw)1695779Sxy150489 e1000_get_phy_id(struct e1000_hw *hw)
1705779Sxy150489 {
1715779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
1725779Sxy150489 s32 ret_val = E1000_SUCCESS;
1735779Sxy150489 u16 phy_id;
1745779Sxy150489
1755779Sxy150489 DEBUGFUNC("e1000_get_phy_id");
1765779Sxy150489
1778571SChenlu.Chen@Sun.COM if (!(phy->ops.read_reg))
1788571SChenlu.Chen@Sun.COM goto out;
1798571SChenlu.Chen@Sun.COM
1808571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
1815779Sxy150489 if (ret_val)
1825779Sxy150489 goto out;
1835779Sxy150489
1845779Sxy150489 phy->id = (u32)(phy_id << 16);
1855779Sxy150489 usec_delay(20);
1868571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
1875779Sxy150489 if (ret_val)
1885779Sxy150489 goto out;
1895779Sxy150489
1905779Sxy150489 phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
1915779Sxy150489 phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
1925779Sxy150489
1935779Sxy150489 out:
1945779Sxy150489 return (ret_val);
1955779Sxy150489 }
1965779Sxy150489
1975779Sxy150489 /*
1985779Sxy150489 * e1000_phy_reset_dsp_generic - Reset PHY DSP
1995779Sxy150489 * @hw: pointer to the HW structure
2005779Sxy150489 *
2015779Sxy150489 * Reset the digital signal processor.
2025779Sxy150489 */
2035779Sxy150489 s32
e1000_phy_reset_dsp_generic(struct e1000_hw * hw)2045779Sxy150489 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
2055779Sxy150489 {
2068571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
2075779Sxy150489
2085779Sxy150489 DEBUGFUNC("e1000_phy_reset_dsp_generic");
2095779Sxy150489
2108571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.write_reg))
2118571SChenlu.Chen@Sun.COM goto out;
2128571SChenlu.Chen@Sun.COM
2138571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
2145779Sxy150489 if (ret_val)
2155779Sxy150489 goto out;
2165779Sxy150489
2178571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
2185779Sxy150489
2195779Sxy150489 out:
2205779Sxy150489 return (ret_val);
2215779Sxy150489 }
2225779Sxy150489
2235779Sxy150489 /*
2245779Sxy150489 * e1000_read_phy_reg_mdic - Read MDI control register
2255779Sxy150489 * @hw: pointer to the HW structure
2265779Sxy150489 * @offset: register offset to be read
2275779Sxy150489 * @data: pointer to the read data
2285779Sxy150489 *
2298571SChenlu.Chen@Sun.COM * Reads the MDI control register in the PHY at offset and stores the
2305779Sxy150489 * information read to data.
2315779Sxy150489 */
2325779Sxy150489 s32
e1000_read_phy_reg_mdic(struct e1000_hw * hw,u32 offset,u16 * data)2335779Sxy150489 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
2345779Sxy150489 {
2355779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
2365779Sxy150489 u32 i, mdic = 0;
2375779Sxy150489 s32 ret_val = E1000_SUCCESS;
2385779Sxy150489
2395779Sxy150489 DEBUGFUNC("e1000_read_phy_reg_mdic");
2405779Sxy150489
2415779Sxy150489 /*
2425779Sxy150489 * Set up Op-code, Phy Address, and register offset in the MDI
2435779Sxy150489 * Control register. The MAC will take care of interfacing with the
2445779Sxy150489 * PHY to retrieve the desired data.
2455779Sxy150489 */
2465779Sxy150489 mdic = ((offset << E1000_MDIC_REG_SHIFT) |
2475779Sxy150489 (phy->addr << E1000_MDIC_PHY_SHIFT) |
2485779Sxy150489 (E1000_MDIC_OP_READ));
2495779Sxy150489
2505779Sxy150489 E1000_WRITE_REG(hw, E1000_MDIC, mdic);
2515779Sxy150489
2525779Sxy150489 /*
2535779Sxy150489 * Poll the ready bit to see if the MDI read completed
2545779Sxy150489 * Increasing the time out as testing showed failures with
2555779Sxy150489 * the lower time out
2565779Sxy150489 */
2575779Sxy150489 for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
2585779Sxy150489 usec_delay(50);
2595779Sxy150489 mdic = E1000_READ_REG(hw, E1000_MDIC);
2605779Sxy150489 if (mdic & E1000_MDIC_READY)
2615779Sxy150489 break;
2625779Sxy150489 }
2635779Sxy150489 if (!(mdic & E1000_MDIC_READY)) {
2645779Sxy150489 DEBUGOUT("MDI Read did not complete\n");
2655779Sxy150489 ret_val = -E1000_ERR_PHY;
2665779Sxy150489 goto out;
2675779Sxy150489 }
2685779Sxy150489 if (mdic & E1000_MDIC_ERROR) {
2695779Sxy150489 DEBUGOUT("MDI Error\n");
2705779Sxy150489 ret_val = -E1000_ERR_PHY;
2715779Sxy150489 goto out;
2725779Sxy150489 }
2735779Sxy150489 *data = (u16) mdic;
2745779Sxy150489
2755779Sxy150489 out:
2765779Sxy150489 return (ret_val);
2775779Sxy150489 }
2785779Sxy150489
2795779Sxy150489 /*
2805779Sxy150489 * e1000_write_phy_reg_mdic - Write MDI control register
2815779Sxy150489 * @hw: pointer to the HW structure
2825779Sxy150489 * @offset: register offset to write to
2835779Sxy150489 * @data: data to write to register at offset
2845779Sxy150489 *
2855779Sxy150489 * Writes data to MDI control register in the PHY at offset.
2865779Sxy150489 */
2875779Sxy150489 s32
e1000_write_phy_reg_mdic(struct e1000_hw * hw,u32 offset,u16 data)2885779Sxy150489 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
2895779Sxy150489 {
2905779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
2915779Sxy150489 u32 i, mdic = 0;
2925779Sxy150489 s32 ret_val = E1000_SUCCESS;
2935779Sxy150489
2945779Sxy150489 DEBUGFUNC("e1000_write_phy_reg_mdic");
2955779Sxy150489
2965779Sxy150489 /*
2975779Sxy150489 * Set up Op-code, Phy Address, and register offset in the MDI
2985779Sxy150489 * Control register. The MAC will take care of interfacing with the
2995779Sxy150489 * PHY to retrieve the desired data.
3005779Sxy150489 */
3015779Sxy150489 mdic = (((u32)data) |
3025779Sxy150489 (offset << E1000_MDIC_REG_SHIFT) |
3035779Sxy150489 (phy->addr << E1000_MDIC_PHY_SHIFT) |
3045779Sxy150489 (E1000_MDIC_OP_WRITE));
3055779Sxy150489
3065779Sxy150489 E1000_WRITE_REG(hw, E1000_MDIC, mdic);
3075779Sxy150489
3085779Sxy150489 /*
3095779Sxy150489 * Poll the ready bit to see if the MDI read completed
3105779Sxy150489 * Increasing the time out as testing showed failures with
3115779Sxy150489 * the lower time out
3125779Sxy150489 */
3135779Sxy150489 for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
3145779Sxy150489 usec_delay(50);
3155779Sxy150489 mdic = E1000_READ_REG(hw, E1000_MDIC);
3165779Sxy150489 if (mdic & E1000_MDIC_READY)
3175779Sxy150489 break;
3185779Sxy150489 }
3195779Sxy150489 if (!(mdic & E1000_MDIC_READY)) {
3205779Sxy150489 DEBUGOUT("MDI Write did not complete\n");
3215779Sxy150489 ret_val = -E1000_ERR_PHY;
3225779Sxy150489 goto out;
3235779Sxy150489 }
3245779Sxy150489 if (mdic & E1000_MDIC_ERROR) {
3255779Sxy150489 DEBUGOUT("MDI Error\n");
3265779Sxy150489 ret_val = -E1000_ERR_PHY;
3275779Sxy150489 goto out;
3285779Sxy150489 }
3295779Sxy150489
3305779Sxy150489 out:
3315779Sxy150489 return (ret_val);
3325779Sxy150489 }
3335779Sxy150489
3345779Sxy150489 /*
33511155SJason.Xu@Sun.COM * e1000_read_phy_reg_i2c - Read PHY register using i2c
33611155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
33711155SJason.Xu@Sun.COM * @offset: register offset to be read
33811155SJason.Xu@Sun.COM * @data: pointer to the read data
33911155SJason.Xu@Sun.COM *
34011155SJason.Xu@Sun.COM * Reads the PHY register at offset using the i2c interface and stores the
34111155SJason.Xu@Sun.COM * retrieved information in data.
34211155SJason.Xu@Sun.COM */
34311155SJason.Xu@Sun.COM s32
e1000_read_phy_reg_i2c(struct e1000_hw * hw,u32 offset,u16 * data)34411155SJason.Xu@Sun.COM e1000_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
34511155SJason.Xu@Sun.COM {
34611155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
34711155SJason.Xu@Sun.COM u32 i, i2ccmd = 0;
34811155SJason.Xu@Sun.COM
34911155SJason.Xu@Sun.COM DEBUGFUNC("e1000_read_phy_reg_i2c");
35011155SJason.Xu@Sun.COM
35111155SJason.Xu@Sun.COM /*
35211155SJason.Xu@Sun.COM * Set up Op-code, Phy Address, and register address in the I2CCMD
35311155SJason.Xu@Sun.COM * register. The MAC will take care of interfacing with the
35411155SJason.Xu@Sun.COM * PHY to retrieve the desired data.
35511155SJason.Xu@Sun.COM */
35611155SJason.Xu@Sun.COM i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
35711155SJason.Xu@Sun.COM (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
35811155SJason.Xu@Sun.COM (E1000_I2CCMD_OPCODE_READ));
35911155SJason.Xu@Sun.COM
36011155SJason.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
36111155SJason.Xu@Sun.COM
36211155SJason.Xu@Sun.COM /* Poll the ready bit to see if the I2C read completed */
36311155SJason.Xu@Sun.COM for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
36411155SJason.Xu@Sun.COM usec_delay(50);
36511155SJason.Xu@Sun.COM i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
36611155SJason.Xu@Sun.COM if (i2ccmd & E1000_I2CCMD_READY)
36711155SJason.Xu@Sun.COM break;
36811155SJason.Xu@Sun.COM }
36911155SJason.Xu@Sun.COM if (!(i2ccmd & E1000_I2CCMD_READY)) {
37011155SJason.Xu@Sun.COM DEBUGOUT("I2CCMD Read did not complete\n");
37111155SJason.Xu@Sun.COM return (-E1000_ERR_PHY);
37211155SJason.Xu@Sun.COM }
37311155SJason.Xu@Sun.COM if (i2ccmd & E1000_I2CCMD_ERROR) {
37411155SJason.Xu@Sun.COM DEBUGOUT("I2CCMD Error bit set\n");
37511155SJason.Xu@Sun.COM return (-E1000_ERR_PHY);
37611155SJason.Xu@Sun.COM }
37711155SJason.Xu@Sun.COM
37811155SJason.Xu@Sun.COM /* Need to byte-swap the 16-bit value. */
37911155SJason.Xu@Sun.COM *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
38011155SJason.Xu@Sun.COM
38111155SJason.Xu@Sun.COM return (E1000_SUCCESS);
38211155SJason.Xu@Sun.COM }
38311155SJason.Xu@Sun.COM
38411155SJason.Xu@Sun.COM /*
38511155SJason.Xu@Sun.COM * e1000_write_phy_reg_i2c - Write PHY register using i2c
38611155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
38711155SJason.Xu@Sun.COM * @offset: register offset to write to
38811155SJason.Xu@Sun.COM * @data: data to write at register offset
38911155SJason.Xu@Sun.COM *
39011155SJason.Xu@Sun.COM * Writes the data to PHY register at the offset using the i2c interface.
39111155SJason.Xu@Sun.COM */
39211155SJason.Xu@Sun.COM s32
e1000_write_phy_reg_i2c(struct e1000_hw * hw,u32 offset,u16 data)39311155SJason.Xu@Sun.COM e1000_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
39411155SJason.Xu@Sun.COM {
39511155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
39611155SJason.Xu@Sun.COM u32 i, i2ccmd = 0;
39711155SJason.Xu@Sun.COM u16 phy_data_swapped;
39811155SJason.Xu@Sun.COM
39911155SJason.Xu@Sun.COM DEBUGFUNC("e1000_write_phy_reg_i2c");
40011155SJason.Xu@Sun.COM
40111155SJason.Xu@Sun.COM /* Swap the data bytes for the I2C interface */
40211155SJason.Xu@Sun.COM phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
40311155SJason.Xu@Sun.COM
40411155SJason.Xu@Sun.COM /*
40511155SJason.Xu@Sun.COM * Set up Op-code, Phy Address, and register address in the I2CCMD
40611155SJason.Xu@Sun.COM * register. The MAC will take care of interfacing with the
40711155SJason.Xu@Sun.COM * PHY to retrieve the desired data.
40811155SJason.Xu@Sun.COM */
40911155SJason.Xu@Sun.COM i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
41011155SJason.Xu@Sun.COM (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
41111155SJason.Xu@Sun.COM E1000_I2CCMD_OPCODE_WRITE |
41211155SJason.Xu@Sun.COM phy_data_swapped);
41311155SJason.Xu@Sun.COM
41411155SJason.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
41511155SJason.Xu@Sun.COM
41611155SJason.Xu@Sun.COM /* Poll the ready bit to see if the I2C read completed */
41711155SJason.Xu@Sun.COM for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
41811155SJason.Xu@Sun.COM usec_delay(50);
41911155SJason.Xu@Sun.COM i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
42011155SJason.Xu@Sun.COM if (i2ccmd & E1000_I2CCMD_READY)
42111155SJason.Xu@Sun.COM break;
42211155SJason.Xu@Sun.COM }
42311155SJason.Xu@Sun.COM if (!(i2ccmd & E1000_I2CCMD_READY)) {
42411155SJason.Xu@Sun.COM DEBUGOUT("I2CCMD Write did not complete\n");
42511155SJason.Xu@Sun.COM return (-E1000_ERR_PHY);
42611155SJason.Xu@Sun.COM }
42711155SJason.Xu@Sun.COM if (i2ccmd & E1000_I2CCMD_ERROR) {
42811155SJason.Xu@Sun.COM DEBUGOUT("I2CCMD Error bit set\n");
42911155SJason.Xu@Sun.COM return (-E1000_ERR_PHY);
43011155SJason.Xu@Sun.COM }
43111155SJason.Xu@Sun.COM
43211155SJason.Xu@Sun.COM return (E1000_SUCCESS);
43311155SJason.Xu@Sun.COM }
43411155SJason.Xu@Sun.COM
43511155SJason.Xu@Sun.COM /*
4365779Sxy150489 * e1000_read_phy_reg_m88 - Read m88 PHY register
4375779Sxy150489 * @hw: pointer to the HW structure
4385779Sxy150489 * @offset: register offset to be read
4395779Sxy150489 * @data: pointer to the read data
4405779Sxy150489 *
4415779Sxy150489 * Acquires semaphore, if necessary, then reads the PHY register at offset
4425779Sxy150489 * and storing the retrieved information in data. Release any acquired
4435779Sxy150489 * semaphores before exiting.
4445779Sxy150489 */
4455779Sxy150489 s32
e1000_read_phy_reg_m88(struct e1000_hw * hw,u32 offset,u16 * data)4465779Sxy150489 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
4475779Sxy150489 {
4488571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
4495779Sxy150489
4505779Sxy150489 DEBUGFUNC("e1000_read_phy_reg_m88");
4515779Sxy150489
4528571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire))
4538571SChenlu.Chen@Sun.COM goto out;
4548571SChenlu.Chen@Sun.COM
4558571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.acquire(hw);
4565779Sxy150489 if (ret_val)
4575779Sxy150489 goto out;
4585779Sxy150489
4595779Sxy150489 ret_val = e1000_read_phy_reg_mdic(hw,
4605779Sxy150489 MAX_PHY_REG_ADDRESS & offset, data);
4615779Sxy150489
4628571SChenlu.Chen@Sun.COM hw->phy.ops.release(hw);
4635779Sxy150489
4645779Sxy150489 out:
4655779Sxy150489 return (ret_val);
4665779Sxy150489 }
4675779Sxy150489
4685779Sxy150489 /*
4695779Sxy150489 * e1000_write_phy_reg_m88 - Write m88 PHY register
4705779Sxy150489 * @hw: pointer to the HW structure
4715779Sxy150489 * @offset: register offset to write to
4725779Sxy150489 * @data: data to write at register offset
4735779Sxy150489 *
4745779Sxy150489 * Acquires semaphore, if necessary, then writes the data to PHY register
4755779Sxy150489 * at the offset. Release any acquired semaphores before exiting.
4765779Sxy150489 */
4775779Sxy150489 s32
e1000_write_phy_reg_m88(struct e1000_hw * hw,u32 offset,u16 data)4785779Sxy150489 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
4795779Sxy150489 {
4808571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
4815779Sxy150489
4825779Sxy150489 DEBUGFUNC("e1000_write_phy_reg_m88");
4835779Sxy150489
4848571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.acquire))
4858571SChenlu.Chen@Sun.COM goto out;
4868571SChenlu.Chen@Sun.COM
4878571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.acquire(hw);
4885779Sxy150489 if (ret_val)
4895779Sxy150489 goto out;
4905779Sxy150489
4915779Sxy150489 ret_val = e1000_write_phy_reg_mdic(hw,
4925779Sxy150489 MAX_PHY_REG_ADDRESS & offset, data);
4935779Sxy150489
4948571SChenlu.Chen@Sun.COM hw->phy.ops.release(hw);
4955779Sxy150489
4965779Sxy150489 out:
4975779Sxy150489 return (ret_val);
4985779Sxy150489 }
4995779Sxy150489
5005779Sxy150489 /*
50111155SJason.Xu@Sun.COM * __e1000_read_phy_reg_igp - Read igp PHY register
50211155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
50311155SJason.Xu@Sun.COM * @offset: register offset to be read
50411155SJason.Xu@Sun.COM * @data: pointer to the read data
50511155SJason.Xu@Sun.COM * @locked: semaphore has already been acquired or not
50611155SJason.Xu@Sun.COM *
50711155SJason.Xu@Sun.COM * Acquires semaphore, if necessary, then reads the PHY register at offset
50811155SJason.Xu@Sun.COM * and stores the retrieved information in data. Release any acquired
50911155SJason.Xu@Sun.COM * semaphores before exiting.
51011155SJason.Xu@Sun.COM */
51111155SJason.Xu@Sun.COM static s32
__e1000_read_phy_reg_igp(struct e1000_hw * hw,u32 offset,u16 * data,bool locked)51211155SJason.Xu@Sun.COM __e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
51311155SJason.Xu@Sun.COM bool locked)
51411155SJason.Xu@Sun.COM {
51511155SJason.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
51611155SJason.Xu@Sun.COM
51711155SJason.Xu@Sun.COM DEBUGFUNC("__e1000_read_phy_reg_igp");
51811155SJason.Xu@Sun.COM
51911155SJason.Xu@Sun.COM if (!locked) {
52011155SJason.Xu@Sun.COM if (!(hw->phy.ops.acquire))
52111155SJason.Xu@Sun.COM goto out;
52211155SJason.Xu@Sun.COM
52311155SJason.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
52411155SJason.Xu@Sun.COM if (ret_val)
52511155SJason.Xu@Sun.COM goto out;
52611155SJason.Xu@Sun.COM }
52711155SJason.Xu@Sun.COM
52811155SJason.Xu@Sun.COM if (offset > MAX_PHY_MULTI_PAGE_REG) {
52911155SJason.Xu@Sun.COM ret_val = e1000_write_phy_reg_mdic(hw,
53011155SJason.Xu@Sun.COM IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
53111155SJason.Xu@Sun.COM if (ret_val)
53211155SJason.Xu@Sun.COM goto release;
53311155SJason.Xu@Sun.COM }
53411155SJason.Xu@Sun.COM
53511155SJason.Xu@Sun.COM ret_val = e1000_read_phy_reg_mdic(hw,
53611155SJason.Xu@Sun.COM MAX_PHY_REG_ADDRESS & offset, data);
53711155SJason.Xu@Sun.COM
53811155SJason.Xu@Sun.COM release:
53911155SJason.Xu@Sun.COM if (!locked)
54011155SJason.Xu@Sun.COM hw->phy.ops.release(hw);
54111155SJason.Xu@Sun.COM
54211155SJason.Xu@Sun.COM out:
54311155SJason.Xu@Sun.COM return (ret_val);
54411155SJason.Xu@Sun.COM }
54511155SJason.Xu@Sun.COM
54611155SJason.Xu@Sun.COM /*
5475779Sxy150489 * e1000_read_phy_reg_igp - Read igp PHY register
5485779Sxy150489 * @hw: pointer to the HW structure
5495779Sxy150489 * @offset: register offset to be read
5505779Sxy150489 * @data: pointer to the read data
5515779Sxy150489 *
55211155SJason.Xu@Sun.COM * Acquires semaphore then reads the PHY register at offset and stores the
55311155SJason.Xu@Sun.COM * retrieved information in data.
55411155SJason.Xu@Sun.COM * Release the acquired semaphore before exiting.
5555779Sxy150489 */
5565779Sxy150489 s32
e1000_read_phy_reg_igp(struct e1000_hw * hw,u32 offset,u16 * data)5575779Sxy150489 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
5585779Sxy150489 {
55911155SJason.Xu@Sun.COM return (__e1000_read_phy_reg_igp(hw, offset, data, false));
56011155SJason.Xu@Sun.COM }
56111155SJason.Xu@Sun.COM
56211155SJason.Xu@Sun.COM /*
56311155SJason.Xu@Sun.COM * e1000_read_phy_reg_igp_locked - Read igp PHY register
56411155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
56511155SJason.Xu@Sun.COM * @offset: register offset to be read
56611155SJason.Xu@Sun.COM * @data: pointer to the read data
56711155SJason.Xu@Sun.COM *
56811155SJason.Xu@Sun.COM * Reads the PHY register at offset and stores the retrieved information
56911155SJason.Xu@Sun.COM * in data. Assumes semaphore already acquired.
57011155SJason.Xu@Sun.COM */
57111155SJason.Xu@Sun.COM s32
e1000_read_phy_reg_igp_locked(struct e1000_hw * hw,u32 offset,u16 * data)57211155SJason.Xu@Sun.COM e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
57311155SJason.Xu@Sun.COM {
57411155SJason.Xu@Sun.COM return (__e1000_read_phy_reg_igp(hw, offset, data, true));
57511155SJason.Xu@Sun.COM }
57611155SJason.Xu@Sun.COM
57711155SJason.Xu@Sun.COM /*
57811155SJason.Xu@Sun.COM * __e1000_write_phy_reg_igp - Write igp PHY register
57911155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
58011155SJason.Xu@Sun.COM * @offset: register offset to write to
58111155SJason.Xu@Sun.COM * @data: data to write at register offset
58211155SJason.Xu@Sun.COM * @locked: semaphore has already been acquired or not
58311155SJason.Xu@Sun.COM *
58411155SJason.Xu@Sun.COM * Acquires semaphore, if necessary, then writes the data to PHY register
58511155SJason.Xu@Sun.COM * at the offset. Release any acquired semaphores before exiting.
58611155SJason.Xu@Sun.COM */
58711155SJason.Xu@Sun.COM static s32
__e1000_write_phy_reg_igp(struct e1000_hw * hw,u32 offset,u16 data,bool locked)58811155SJason.Xu@Sun.COM __e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
58911155SJason.Xu@Sun.COM bool locked)
59011155SJason.Xu@Sun.COM {
5918571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
5925779Sxy150489
59311155SJason.Xu@Sun.COM DEBUGFUNC("__e1000_write_phy_reg_igp");
59411155SJason.Xu@Sun.COM
59511155SJason.Xu@Sun.COM if (!locked) {
59611155SJason.Xu@Sun.COM if (!(hw->phy.ops.acquire))
59711155SJason.Xu@Sun.COM goto out;
59811155SJason.Xu@Sun.COM
59911155SJason.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
60011155SJason.Xu@Sun.COM if (ret_val)
60111155SJason.Xu@Sun.COM goto out;
60211155SJason.Xu@Sun.COM }
6035779Sxy150489
6045779Sxy150489 if (offset > MAX_PHY_MULTI_PAGE_REG) {
6055779Sxy150489 ret_val = e1000_write_phy_reg_mdic(hw,
6065779Sxy150489 IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
60711155SJason.Xu@Sun.COM if (ret_val)
60811155SJason.Xu@Sun.COM goto release;
6095779Sxy150489 }
6105779Sxy150489
61111155SJason.Xu@Sun.COM ret_val = e1000_write_phy_reg_mdic(hw,
6125779Sxy150489 MAX_PHY_REG_ADDRESS & offset, data);
6135779Sxy150489
61411155SJason.Xu@Sun.COM release:
61511155SJason.Xu@Sun.COM if (!locked)
61611155SJason.Xu@Sun.COM hw->phy.ops.release(hw);
6175779Sxy150489
6185779Sxy150489 out:
6195779Sxy150489 return (ret_val);
6205779Sxy150489 }
6215779Sxy150489
6225779Sxy150489 /*
6235779Sxy150489 * e1000_write_phy_reg_igp - Write igp PHY register
6245779Sxy150489 * @hw: pointer to the HW structure
6255779Sxy150489 * @offset: register offset to write to
6265779Sxy150489 * @data: data to write at register offset
6275779Sxy150489 *
62811155SJason.Xu@Sun.COM * Acquires semaphore then writes the data to PHY register
6295779Sxy150489 * at the offset. Release any acquired semaphores before exiting.
6305779Sxy150489 */
6315779Sxy150489 s32
e1000_write_phy_reg_igp(struct e1000_hw * hw,u32 offset,u16 data)6325779Sxy150489 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
6335779Sxy150489 {
63411155SJason.Xu@Sun.COM return (__e1000_write_phy_reg_igp(hw, offset, data, false));
6355779Sxy150489 }
6365779Sxy150489
6375779Sxy150489 /*
63811155SJason.Xu@Sun.COM * e1000_write_phy_reg_igp_locked - Write igp PHY register
63911155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
64011155SJason.Xu@Sun.COM * @offset: register offset to write to
64111155SJason.Xu@Sun.COM * @data: data to write at register offset
64211155SJason.Xu@Sun.COM *
64311155SJason.Xu@Sun.COM * Writes the data to PHY register at the offset.
64411155SJason.Xu@Sun.COM * Assumes semaphore already acquired.
64511155SJason.Xu@Sun.COM */
64611155SJason.Xu@Sun.COM s32
e1000_write_phy_reg_igp_locked(struct e1000_hw * hw,u32 offset,u16 data)64711155SJason.Xu@Sun.COM e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
64811155SJason.Xu@Sun.COM {
64911155SJason.Xu@Sun.COM return (__e1000_write_phy_reg_igp(hw, offset, data, true));
65011155SJason.Xu@Sun.COM }
65111155SJason.Xu@Sun.COM
65211155SJason.Xu@Sun.COM /*
65311155SJason.Xu@Sun.COM * __e1000_read_kmrn_reg - Read kumeran register
6545779Sxy150489 * @hw: pointer to the HW structure
6555779Sxy150489 * @offset: register offset to be read
6565779Sxy150489 * @data: pointer to the read data
65711155SJason.Xu@Sun.COM * @locked: semaphore has already been acquired or not
6585779Sxy150489 *
6595779Sxy150489 * Acquires semaphore, if necessary. Then reads the PHY register at offset
6605779Sxy150489 * using the kumeran interface. The information retrieved is stored in data.
6615779Sxy150489 * Release any acquired semaphores before exiting.
6625779Sxy150489 */
66311155SJason.Xu@Sun.COM static s32
__e1000_read_kmrn_reg(struct e1000_hw * hw,u32 offset,u16 * data,bool locked)66411155SJason.Xu@Sun.COM __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, bool locked)
6655779Sxy150489 {
6665779Sxy150489 u32 kmrnctrlsta;
6678571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
6685779Sxy150489
66911155SJason.Xu@Sun.COM DEBUGFUNC("__e1000_read_kmrn_reg_generic");
67011155SJason.Xu@Sun.COM
67111155SJason.Xu@Sun.COM if (!locked) {
67211155SJason.Xu@Sun.COM if (!(hw->phy.ops.acquire))
67311155SJason.Xu@Sun.COM goto out;
67411155SJason.Xu@Sun.COM
67511155SJason.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
67611155SJason.Xu@Sun.COM if (ret_val)
67711155SJason.Xu@Sun.COM goto out;
67811155SJason.Xu@Sun.COM }
6795779Sxy150489
6805779Sxy150489 kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
6815779Sxy150489 E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
6825779Sxy150489 E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
6835779Sxy150489
6845779Sxy150489 usec_delay(2);
6855779Sxy150489
6865779Sxy150489 kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
6875779Sxy150489 *data = (u16)kmrnctrlsta;
6885779Sxy150489
68911155SJason.Xu@Sun.COM if (!locked)
69011155SJason.Xu@Sun.COM hw->phy.ops.release(hw);
6915779Sxy150489
6925779Sxy150489 out:
6935779Sxy150489 return (ret_val);
6945779Sxy150489 }
6955779Sxy150489
6965779Sxy150489 /*
69711155SJason.Xu@Sun.COM * e1000_read_kmrn_reg_generic - Read kumeran register
69811155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
69911155SJason.Xu@Sun.COM * @offset: register offset to be read
70011155SJason.Xu@Sun.COM * @data: pointer to the read data
70111155SJason.Xu@Sun.COM *
70211155SJason.Xu@Sun.COM * Acquires semaphore then reads the PHY register at offset using the
70311155SJason.Xu@Sun.COM * kumeran interface. The information retrieved is stored in data.
70411155SJason.Xu@Sun.COM * Release the acquired semaphore before exiting.
70511155SJason.Xu@Sun.COM */
70611155SJason.Xu@Sun.COM s32
e1000_read_kmrn_reg_generic(struct e1000_hw * hw,u32 offset,u16 * data)70711155SJason.Xu@Sun.COM e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
70811155SJason.Xu@Sun.COM {
70911155SJason.Xu@Sun.COM return (__e1000_read_kmrn_reg(hw, offset, data, false));
71011155SJason.Xu@Sun.COM }
71111155SJason.Xu@Sun.COM
71211155SJason.Xu@Sun.COM /*
71311155SJason.Xu@Sun.COM * e1000_read_kmrn_reg_locked - Read kumeran register
71411155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
71511155SJason.Xu@Sun.COM * @offset: register offset to be read
71611155SJason.Xu@Sun.COM * @data: pointer to the read data
71711155SJason.Xu@Sun.COM *
71811155SJason.Xu@Sun.COM * Reads the PHY register at offset using the kumeran interface. The
71911155SJason.Xu@Sun.COM * information retrieved is stored in data.
72011155SJason.Xu@Sun.COM * Assumes semaphore already acquired.
72111155SJason.Xu@Sun.COM */
72211155SJason.Xu@Sun.COM s32
e1000_read_kmrn_reg_locked(struct e1000_hw * hw,u32 offset,u16 * data)72311155SJason.Xu@Sun.COM e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
72411155SJason.Xu@Sun.COM {
72511155SJason.Xu@Sun.COM return (__e1000_read_kmrn_reg(hw, offset, data, true));
72611155SJason.Xu@Sun.COM }
72711155SJason.Xu@Sun.COM
72811155SJason.Xu@Sun.COM /*
72911155SJason.Xu@Sun.COM * __e1000_write_kmrn_reg - Write kumeran register
7305779Sxy150489 * @hw: pointer to the HW structure
7315779Sxy150489 * @offset: register offset to write to
7325779Sxy150489 * @data: data to write at register offset
73311155SJason.Xu@Sun.COM * @locked: semaphore has already been acquired or not
7345779Sxy150489 *
7355779Sxy150489 * Acquires semaphore, if necessary. Then write the data to PHY register
7365779Sxy150489 * at the offset using the kumeran interface. Release any acquired semaphores
7375779Sxy150489 * before exiting.
7385779Sxy150489 */
73911155SJason.Xu@Sun.COM static s32
__e1000_write_kmrn_reg(struct e1000_hw * hw,u32 offset,u16 data,bool locked)74011155SJason.Xu@Sun.COM __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, bool locked)
7415779Sxy150489 {
7425779Sxy150489 u32 kmrnctrlsta;
7438571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
7445779Sxy150489
7455779Sxy150489 DEBUGFUNC("e1000_write_kmrn_reg_generic");
7465779Sxy150489
74711155SJason.Xu@Sun.COM if (!locked) {
74811155SJason.Xu@Sun.COM if (!(hw->phy.ops.acquire))
74911155SJason.Xu@Sun.COM goto out;
75011155SJason.Xu@Sun.COM
75111155SJason.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
75211155SJason.Xu@Sun.COM if (ret_val)
75311155SJason.Xu@Sun.COM goto out;
75411155SJason.Xu@Sun.COM }
7555779Sxy150489
7565779Sxy150489 kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
7575779Sxy150489 E1000_KMRNCTRLSTA_OFFSET) | data;
7585779Sxy150489 E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
7595779Sxy150489
7605779Sxy150489 usec_delay(2);
76111155SJason.Xu@Sun.COM
76211155SJason.Xu@Sun.COM if (!locked)
76311155SJason.Xu@Sun.COM hw->phy.ops.release(hw);
76411155SJason.Xu@Sun.COM
76511155SJason.Xu@Sun.COM out:
76611155SJason.Xu@Sun.COM return (ret_val);
76711155SJason.Xu@Sun.COM }
76811155SJason.Xu@Sun.COM
76911155SJason.Xu@Sun.COM /*
77011155SJason.Xu@Sun.COM * e1000_write_kmrn_reg_generic - Write kumeran register
77111155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
77211155SJason.Xu@Sun.COM * @offset: register offset to write to
77311155SJason.Xu@Sun.COM * @data: data to write at register offset
77411155SJason.Xu@Sun.COM *
77511155SJason.Xu@Sun.COM * Acquires semaphore then writes the data to the PHY register at the offset
77611155SJason.Xu@Sun.COM * using the kumeran interface. Release the acquired semaphore before exiting.
77711155SJason.Xu@Sun.COM */
77811155SJason.Xu@Sun.COM s32
e1000_write_kmrn_reg_generic(struct e1000_hw * hw,u32 offset,u16 data)77911155SJason.Xu@Sun.COM e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
78011155SJason.Xu@Sun.COM {
78111155SJason.Xu@Sun.COM return (__e1000_write_kmrn_reg(hw, offset, data, false));
78211155SJason.Xu@Sun.COM }
78311155SJason.Xu@Sun.COM
78411155SJason.Xu@Sun.COM /*
78511155SJason.Xu@Sun.COM * e1000_write_kmrn_reg_locked - Write kumeran register
78611155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
78711155SJason.Xu@Sun.COM * @offset: register offset to write to
78811155SJason.Xu@Sun.COM * @data: data to write at register offset
78911155SJason.Xu@Sun.COM *
79011155SJason.Xu@Sun.COM * Write the data to PHY register at the offset using the kumeran interface.
79111155SJason.Xu@Sun.COM * Assumes semaphore already acquired.
79211155SJason.Xu@Sun.COM */
79311155SJason.Xu@Sun.COM s32
e1000_write_kmrn_reg_locked(struct e1000_hw * hw,u32 offset,u16 data)79411155SJason.Xu@Sun.COM e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
79511155SJason.Xu@Sun.COM {
79611155SJason.Xu@Sun.COM return (__e1000_write_kmrn_reg(hw, offset, data, true));
79711155SJason.Xu@Sun.COM }
79811155SJason.Xu@Sun.COM
79911155SJason.Xu@Sun.COM /*
80011155SJason.Xu@Sun.COM * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
80111155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
80211155SJason.Xu@Sun.COM *
80311155SJason.Xu@Sun.COM * Sets up Carrier-sense on Transmit and downshift values.
80411155SJason.Xu@Sun.COM */
80511155SJason.Xu@Sun.COM s32
e1000_copper_link_setup_82577(struct e1000_hw * hw)80611155SJason.Xu@Sun.COM e1000_copper_link_setup_82577(struct e1000_hw *hw)
80711155SJason.Xu@Sun.COM {
80811155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
80911155SJason.Xu@Sun.COM s32 ret_val;
81011155SJason.Xu@Sun.COM u16 phy_data;
81111155SJason.Xu@Sun.COM
81211155SJason.Xu@Sun.COM DEBUGFUNC("e1000_copper_link_setup_82577");
81311155SJason.Xu@Sun.COM
81411155SJason.Xu@Sun.COM if (phy->reset_disable) {
81511155SJason.Xu@Sun.COM ret_val = E1000_SUCCESS;
81611155SJason.Xu@Sun.COM goto out;
81711155SJason.Xu@Sun.COM }
81811155SJason.Xu@Sun.COM
81911155SJason.Xu@Sun.COM if (phy->type == e1000_phy_82580) {
82011155SJason.Xu@Sun.COM ret_val = hw->phy.ops.reset(hw);
82111155SJason.Xu@Sun.COM if (ret_val) {
82211155SJason.Xu@Sun.COM DEBUGOUT("Error resetting the PHY.\n");
82311155SJason.Xu@Sun.COM goto out;
82411155SJason.Xu@Sun.COM }
82511155SJason.Xu@Sun.COM }
82611155SJason.Xu@Sun.COM
82711155SJason.Xu@Sun.COM /* Enable CRS on TX. This must be set for half-duplex operation. */
82811155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data);
82911155SJason.Xu@Sun.COM if (ret_val)
83011155SJason.Xu@Sun.COM goto out;
83111155SJason.Xu@Sun.COM
83211155SJason.Xu@Sun.COM phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
83311155SJason.Xu@Sun.COM
83411155SJason.Xu@Sun.COM /* Enable downshift */
83511155SJason.Xu@Sun.COM phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
83611155SJason.Xu@Sun.COM
83711155SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data);
8385779Sxy150489
8395779Sxy150489 out:
8405779Sxy150489 return (ret_val);
8415779Sxy150489 }
8425779Sxy150489
8435779Sxy150489 /*
8445779Sxy150489 * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
8455779Sxy150489 * @hw: pointer to the HW structure
8465779Sxy150489 *
8475779Sxy150489 * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock
8485779Sxy150489 * and downshift values are set also.
8495779Sxy150489 */
8505779Sxy150489 s32
e1000_copper_link_setup_m88(struct e1000_hw * hw)8515779Sxy150489 e1000_copper_link_setup_m88(struct e1000_hw *hw)
8525779Sxy150489 {
8535779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
8545779Sxy150489 s32 ret_val;
8555779Sxy150489 u16 phy_data;
8565779Sxy150489
8575779Sxy150489 DEBUGFUNC("e1000_copper_link_setup_m88");
8585779Sxy150489
8595779Sxy150489 if (phy->reset_disable) {
8605779Sxy150489 ret_val = E1000_SUCCESS;
8615779Sxy150489 goto out;
8625779Sxy150489 }
8635779Sxy150489
8645779Sxy150489 /* Enable CRS on TX. This must be set for half-duplex operation. */
8658571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
8665779Sxy150489 if (ret_val)
8675779Sxy150489 goto out;
8685779Sxy150489
8698571SChenlu.Chen@Sun.COM phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
8705779Sxy150489
8715779Sxy150489 /*
8725779Sxy150489 * Options:
8735779Sxy150489 * MDI/MDI-X = 0 (default)
8745779Sxy150489 * 0 - Auto for all speeds
8755779Sxy150489 * 1 - MDI mode
8765779Sxy150489 * 2 - MDI-X mode
8775779Sxy150489 * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
8785779Sxy150489 */
8795779Sxy150489 phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
8805779Sxy150489
8815779Sxy150489 switch (phy->mdix) {
8825779Sxy150489 case 1:
8835779Sxy150489 phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
8845779Sxy150489 break;
8855779Sxy150489 case 2:
8865779Sxy150489 phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
8875779Sxy150489 break;
8885779Sxy150489 case 3:
8895779Sxy150489 phy_data |= M88E1000_PSCR_AUTO_X_1000T;
8905779Sxy150489 break;
8915779Sxy150489 case 0:
8925779Sxy150489 default:
8935779Sxy150489 phy_data |= M88E1000_PSCR_AUTO_X_MODE;
8945779Sxy150489 break;
8955779Sxy150489 }
8965779Sxy150489
8975779Sxy150489 /*
8985779Sxy150489 * Options:
8995779Sxy150489 * disable_polarity_correction = 0 (default)
9005779Sxy150489 * Automatic Correction for Reversed Cable Polarity
9015779Sxy150489 * 0 - Disabled
9025779Sxy150489 * 1 - Enabled
9035779Sxy150489 */
9045779Sxy150489 phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
9055779Sxy150489 if (phy->disable_polarity_correction == 1)
9065779Sxy150489 phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
9075779Sxy150489
9088571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
9095779Sxy150489 if (ret_val)
9105779Sxy150489 goto out;
9115779Sxy150489
9128571SChenlu.Chen@Sun.COM if (phy->revision < E1000_REVISION_4) {
9135779Sxy150489 /*
9145779Sxy150489 * Force TX_CLK in the Extended PHY Specific Control Register
9155779Sxy150489 * to 25MHz clock.
9165779Sxy150489 */
9178571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
9188571SChenlu.Chen@Sun.COM &phy_data);
9195779Sxy150489 if (ret_val)
9205779Sxy150489 goto out;
9215779Sxy150489
9225779Sxy150489 phy_data |= M88E1000_EPSCR_TX_CLK_25;
9235779Sxy150489
9245779Sxy150489 if ((phy->revision == E1000_REVISION_2) &&
9255779Sxy150489 (phy->id == M88E1111_I_PHY_ID)) {
9265779Sxy150489 /* 82573L PHY - set the downshift counter to 5x. */
9275779Sxy150489 phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
9285779Sxy150489 phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
9295779Sxy150489 } else {
9305779Sxy150489 /* Configure Master and Slave downshift values */
9315779Sxy150489 phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
9325779Sxy150489 M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
9335779Sxy150489 phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
9345779Sxy150489 M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
9355779Sxy150489 }
9368571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
9378571SChenlu.Chen@Sun.COM phy_data);
9385779Sxy150489 if (ret_val)
9395779Sxy150489 goto out;
9405779Sxy150489 }
9415779Sxy150489
9425779Sxy150489 /* Commit the changes. */
9438571SChenlu.Chen@Sun.COM ret_val = phy->ops.commit(hw);
9445779Sxy150489 if (ret_val) {
9455779Sxy150489 DEBUGOUT("Error committing the PHY changes\n");
9465779Sxy150489 goto out;
9475779Sxy150489 }
9485779Sxy150489
9495779Sxy150489 out:
9505779Sxy150489 return (ret_val);
9515779Sxy150489 }
9525779Sxy150489
9535779Sxy150489 /*
9545779Sxy150489 * e1000_copper_link_setup_igp - Setup igp PHY's for copper link
9555779Sxy150489 * @hw: pointer to the HW structure
9565779Sxy150489 *
9575779Sxy150489 * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
9585779Sxy150489 * igp PHY's.
9595779Sxy150489 */
9605779Sxy150489 s32
e1000_copper_link_setup_igp(struct e1000_hw * hw)9615779Sxy150489 e1000_copper_link_setup_igp(struct e1000_hw *hw)
9625779Sxy150489 {
9635779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
9645779Sxy150489 s32 ret_val;
9655779Sxy150489 u16 data;
9665779Sxy150489
9675779Sxy150489 DEBUGFUNC("e1000_copper_link_setup_igp");
9685779Sxy150489
9695779Sxy150489 if (phy->reset_disable) {
9705779Sxy150489 ret_val = E1000_SUCCESS;
9715779Sxy150489 goto out;
9725779Sxy150489 }
9735779Sxy150489
9748571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.reset(hw);
9755779Sxy150489 if (ret_val) {
9765779Sxy150489 DEBUGOUT("Error resetting the PHY.\n");
9775779Sxy150489 goto out;
9785779Sxy150489 }
9795779Sxy150489
9808571SChenlu.Chen@Sun.COM /*
9818571SChenlu.Chen@Sun.COM * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
9828571SChenlu.Chen@Sun.COM * timeout issues when LFS is enabled.
9838571SChenlu.Chen@Sun.COM */
9848571SChenlu.Chen@Sun.COM msec_delay(100);
9855779Sxy150489
9865779Sxy150489 /*
9875779Sxy150489 * The NVM settings will configure LPLU in D3 for
9885779Sxy150489 * non-IGP1 PHYs.
9895779Sxy150489 */
9905779Sxy150489 if (phy->type == e1000_phy_igp) {
9915779Sxy150489 /* disable lplu d3 during driver init */
9928571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
9935779Sxy150489 if (ret_val) {
9945779Sxy150489 DEBUGOUT("Error Disabling LPLU D3\n");
9955779Sxy150489 goto out;
9965779Sxy150489 }
9975779Sxy150489 }
9985779Sxy150489
9995779Sxy150489 /* disable lplu d0 during driver init */
10008571SChenlu.Chen@Sun.COM if (hw->phy.ops.set_d0_lplu_state) {
10018571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
10028571SChenlu.Chen@Sun.COM if (ret_val) {
10038571SChenlu.Chen@Sun.COM DEBUGOUT("Error Disabling LPLU D0\n");
10048571SChenlu.Chen@Sun.COM goto out;
10058571SChenlu.Chen@Sun.COM }
10065779Sxy150489 }
10075779Sxy150489 /* Configure mdi-mdix settings */
10088571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
10095779Sxy150489 if (ret_val)
10105779Sxy150489 goto out;
10115779Sxy150489
10125779Sxy150489 data &= ~IGP01E1000_PSCR_AUTO_MDIX;
10135779Sxy150489
10145779Sxy150489 switch (phy->mdix) {
10155779Sxy150489 case 1:
10165779Sxy150489 data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
10175779Sxy150489 break;
10185779Sxy150489 case 2:
10195779Sxy150489 data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
10205779Sxy150489 break;
10215779Sxy150489 case 0:
10225779Sxy150489 default:
10235779Sxy150489 data |= IGP01E1000_PSCR_AUTO_MDIX;
10245779Sxy150489 break;
10255779Sxy150489 }
10268571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
10275779Sxy150489 if (ret_val)
10285779Sxy150489 goto out;
10295779Sxy150489
10305779Sxy150489 /* set auto-master slave resolution settings */
10315779Sxy150489 if (hw->mac.autoneg) {
10325779Sxy150489 /*
10335779Sxy150489 * when autonegotiation advertisement is only 1000Mbps then we
10345779Sxy150489 * should disable SmartSpeed and enable Auto MasterSlave
10355779Sxy150489 * resolution as hardware default.
10365779Sxy150489 */
10375779Sxy150489 if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
10385779Sxy150489 /* Disable SmartSpeed */
10398571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw,
10405779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, &data);
10415779Sxy150489 if (ret_val)
10425779Sxy150489 goto out;
10435779Sxy150489
10445779Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10458571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
10465779Sxy150489 IGP01E1000_PHY_PORT_CONFIG, data);
10475779Sxy150489 if (ret_val)
10485779Sxy150489 goto out;
10495779Sxy150489
10505779Sxy150489 /* Set auto Master/Slave resolution process */
10518571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
10525779Sxy150489 if (ret_val)
10535779Sxy150489 goto out;
10545779Sxy150489
10555779Sxy150489 data &= ~CR_1000T_MS_ENABLE;
10568571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
10575779Sxy150489 if (ret_val)
10585779Sxy150489 goto out;
10595779Sxy150489 }
10605779Sxy150489
10618571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
10625779Sxy150489 if (ret_val)
10635779Sxy150489 goto out;
10645779Sxy150489
10655779Sxy150489 /* load defaults for future use */
10665779Sxy150489 phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
10675779Sxy150489 ((data & CR_1000T_MS_VALUE) ?
10685779Sxy150489 e1000_ms_force_master :
10695779Sxy150489 e1000_ms_force_slave) :
10705779Sxy150489 e1000_ms_auto;
10715779Sxy150489
10725779Sxy150489 switch (phy->ms_type) {
10735779Sxy150489 case e1000_ms_force_master:
10745779Sxy150489 data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
10755779Sxy150489 break;
10765779Sxy150489 case e1000_ms_force_slave:
10775779Sxy150489 data |= CR_1000T_MS_ENABLE;
10785779Sxy150489 data &= ~(CR_1000T_MS_VALUE);
10795779Sxy150489 break;
10805779Sxy150489 case e1000_ms_auto:
10815779Sxy150489 data &= ~CR_1000T_MS_ENABLE;
10825779Sxy150489 default:
10835779Sxy150489 break;
10845779Sxy150489 }
10858571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
10865779Sxy150489 if (ret_val)
10875779Sxy150489 goto out;
10885779Sxy150489 }
10895779Sxy150489
10905779Sxy150489 out:
10915779Sxy150489 return (ret_val);
10925779Sxy150489 }
10935779Sxy150489
10945779Sxy150489 /*
10955779Sxy150489 * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
10965779Sxy150489 * @hw: pointer to the HW structure
10975779Sxy150489 *
10985779Sxy150489 * Performs initial bounds checking on autoneg advertisement parameter, then
10995779Sxy150489 * configure to advertise the full capability. Setup the PHY to autoneg
11005779Sxy150489 * and restart the negotiation process between the link partner. If
11015779Sxy150489 * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
11025779Sxy150489 */
110311155SJason.Xu@Sun.COM static s32
e1000_copper_link_autoneg(struct e1000_hw * hw)11045779Sxy150489 e1000_copper_link_autoneg(struct e1000_hw *hw)
11055779Sxy150489 {
11065779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
11075779Sxy150489 s32 ret_val;
11085779Sxy150489 u16 phy_ctrl;
11095779Sxy150489
11105779Sxy150489 DEBUGFUNC("e1000_copper_link_autoneg");
11115779Sxy150489
11125779Sxy150489 /*
11135779Sxy150489 * Perform some bounds checking on the autoneg advertisement
11145779Sxy150489 * parameter.
11155779Sxy150489 */
11165779Sxy150489 phy->autoneg_advertised &= phy->autoneg_mask;
11175779Sxy150489
11185779Sxy150489 /*
11195779Sxy150489 * If autoneg_advertised is zero, we assume it was not defaulted
11205779Sxy150489 * by the calling code so we set to advertise full capability.
11215779Sxy150489 */
11225779Sxy150489 if (phy->autoneg_advertised == 0)
11235779Sxy150489 phy->autoneg_advertised = phy->autoneg_mask;
11245779Sxy150489
11255779Sxy150489 DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
11265779Sxy150489 ret_val = e1000_phy_setup_autoneg(hw);
11275779Sxy150489 if (ret_val) {
11285779Sxy150489 DEBUGOUT("Error Setting up Auto-Negotiation\n");
11295779Sxy150489 goto out;
11305779Sxy150489 }
11315779Sxy150489 DEBUGOUT("Restarting Auto-Neg\n");
11325779Sxy150489
11335779Sxy150489 /*
11345779Sxy150489 * Restart auto-negotiation by setting the Auto Neg Enable bit and
11355779Sxy150489 * the Auto Neg Restart bit in the PHY control register.
11365779Sxy150489 */
11378571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
11385779Sxy150489 if (ret_val)
11395779Sxy150489 goto out;
11405779Sxy150489
11415779Sxy150489 phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
11428571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
11435779Sxy150489 if (ret_val)
11445779Sxy150489 goto out;
11455779Sxy150489
11465779Sxy150489 /*
11475779Sxy150489 * Does the user want to wait for Auto-Neg to complete here, or
11485779Sxy150489 * check at a later time (for example, callback routine).
11495779Sxy150489 */
11505779Sxy150489 if (phy->autoneg_wait_to_complete) {
11518571SChenlu.Chen@Sun.COM ret_val = hw->mac.ops.wait_autoneg(hw);
11525779Sxy150489 if (ret_val) {
11535779Sxy150489 DEBUGOUT("Error while waiting for "
11545779Sxy150489 "autoneg to complete\n");
11555779Sxy150489 goto out;
11565779Sxy150489 }
11575779Sxy150489 }
11585779Sxy150489
11598571SChenlu.Chen@Sun.COM hw->mac.get_link_status = true;
11605779Sxy150489
11615779Sxy150489 out:
11625779Sxy150489 return (ret_val);
11635779Sxy150489 }
11645779Sxy150489
11655779Sxy150489 /*
11665779Sxy150489 * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
11675779Sxy150489 * @hw: pointer to the HW structure
11685779Sxy150489 *
11695779Sxy150489 * Reads the MII auto-neg advertisement register and/or the 1000T control
11705779Sxy150489 * register and if the PHY is already setup for auto-negotiation, then
11715779Sxy150489 * return successful. Otherwise, setup advertisement and flow control to
11725779Sxy150489 * the appropriate values for the wanted auto-negotiation.
11735779Sxy150489 */
1174*12111SGuoqing.Zhu@Sun.COM static s32
e1000_phy_setup_autoneg(struct e1000_hw * hw)11755779Sxy150489 e1000_phy_setup_autoneg(struct e1000_hw *hw)
11765779Sxy150489 {
11775779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
11785779Sxy150489 s32 ret_val;
11795779Sxy150489 u16 mii_autoneg_adv_reg;
11805779Sxy150489 u16 mii_1000t_ctrl_reg = 0;
11815779Sxy150489
11825779Sxy150489 DEBUGFUNC("e1000_phy_setup_autoneg");
11835779Sxy150489
11845779Sxy150489 phy->autoneg_advertised &= phy->autoneg_mask;
11855779Sxy150489
11865779Sxy150489 /* Read the MII Auto-Neg Advertisement Register (Address 4). */
11878571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
11885779Sxy150489 if (ret_val)
11895779Sxy150489 goto out;
11905779Sxy150489
11915779Sxy150489 if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
11925779Sxy150489 /* Read the MII 1000Base-T Control Register (Address 9). */
11938571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
11948571SChenlu.Chen@Sun.COM &mii_1000t_ctrl_reg);
11955779Sxy150489 if (ret_val)
11965779Sxy150489 goto out;
11975779Sxy150489 }
11985779Sxy150489
11995779Sxy150489 /*
12005779Sxy150489 * Need to parse both autoneg_advertised and fc and set up
12015779Sxy150489 * the appropriate PHY registers. First we will parse for
12025779Sxy150489 * autoneg_advertised software override. Since we can advertise
12035779Sxy150489 * a plethora of combinations, we need to check each bit
12045779Sxy150489 * individually.
12055779Sxy150489 */
12065779Sxy150489
12075779Sxy150489 /*
12085779Sxy150489 * First we clear all the 10/100 mb speed bits in the Auto-Neg
12095779Sxy150489 * Advertisement Register (Address 4) and the 1000 mb speed bits in
12105779Sxy150489 * the 1000Base-T Control Register (Address 9).
12115779Sxy150489 */
12125779Sxy150489 mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
12135779Sxy150489 NWAY_AR_100TX_HD_CAPS |
12145779Sxy150489 NWAY_AR_10T_FD_CAPS |
12155779Sxy150489 NWAY_AR_10T_HD_CAPS);
12165779Sxy150489 mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
12175779Sxy150489
12185779Sxy150489 DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
12195779Sxy150489
12205779Sxy150489 /* Do we want to advertise 10 Mb Half Duplex? */
12215779Sxy150489 if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
12225779Sxy150489 DEBUGOUT("Advertise 10mb Half duplex\n");
12235779Sxy150489 mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
12245779Sxy150489 }
12255779Sxy150489
12265779Sxy150489 /* Do we want to advertise 10 Mb Full Duplex? */
12275779Sxy150489 if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
12285779Sxy150489 DEBUGOUT("Advertise 10mb Full duplex\n");
12295779Sxy150489 mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
12305779Sxy150489 }
12315779Sxy150489
12325779Sxy150489 /* Do we want to advertise 100 Mb Half Duplex? */
12335779Sxy150489 if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
12345779Sxy150489 DEBUGOUT("Advertise 100mb Half duplex\n");
12355779Sxy150489 mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
12365779Sxy150489 }
12375779Sxy150489
12385779Sxy150489 /* Do we want to advertise 100 Mb Full Duplex? */
12395779Sxy150489 if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
12405779Sxy150489 DEBUGOUT("Advertise 100mb Full duplex\n");
12415779Sxy150489 mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
12425779Sxy150489 }
12435779Sxy150489
12445779Sxy150489 /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
12458571SChenlu.Chen@Sun.COM if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
12465779Sxy150489 DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
12475779Sxy150489
12485779Sxy150489 /* Do we want to advertise 1000 Mb Full Duplex? */
12495779Sxy150489 if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
12505779Sxy150489 DEBUGOUT("Advertise 1000mb Full duplex\n");
12515779Sxy150489 mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
12525779Sxy150489 }
12535779Sxy150489
12545779Sxy150489 /*
12555779Sxy150489 * Check for a software override of the flow control settings, and
12565779Sxy150489 * setup the PHY advertisement registers accordingly. If
12575779Sxy150489 * auto-negotiation is enabled, then software will have to set the
12585779Sxy150489 * "PAUSE" bits to the correct value in the Auto-Negotiation
12595779Sxy150489 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
12605779Sxy150489 * negotiation.
12615779Sxy150489 *
12625779Sxy150489 * The possible values of the "fc" parameter are:
12635779Sxy150489 * 0: Flow control is completely disabled
12645779Sxy150489 * 1: Rx flow control is enabled (we can receive pause frames
12655779Sxy150489 * but not send pause frames).
12665779Sxy150489 * 2: Tx flow control is enabled (we can send pause frames
12675779Sxy150489 * but we do not support receiving pause frames).
12685779Sxy150489 * 3: Both Rx and Tx flow control (symmetric) are enabled.
12695779Sxy150489 * other: No software override. The flow control configuration
12705779Sxy150489 * in the EEPROM is used.
12715779Sxy150489 */
12728571SChenlu.Chen@Sun.COM switch (hw->fc.current_mode) {
12735779Sxy150489 case e1000_fc_none:
12745779Sxy150489 /*
12755779Sxy150489 * Flow control (Rx & Tx) is completely disabled by a
12765779Sxy150489 * software over-ride.
12775779Sxy150489 */
12785779Sxy150489 mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
12795779Sxy150489 break;
12805779Sxy150489 case e1000_fc_rx_pause:
12815779Sxy150489 /*
12825779Sxy150489 * Rx Flow control is enabled, and Tx Flow control is
12835779Sxy150489 * disabled, by a software over-ride.
12845779Sxy150489 *
12855779Sxy150489 * Since there really isn't a way to advertise that we are
12865779Sxy150489 * capable of Rx Pause ONLY, we will advertise that we
12875779Sxy150489 * support both symmetric and asymmetric Rx PAUSE. Later
12885779Sxy150489 * (in e1000_config_fc_after_link_up) we will disable the
12895779Sxy150489 * hw's ability to send PAUSE frames.
12905779Sxy150489 */
12915779Sxy150489 mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
12925779Sxy150489 break;
12935779Sxy150489 case e1000_fc_tx_pause:
12945779Sxy150489 /*
12955779Sxy150489 * Tx Flow control is enabled, and Rx Flow control is
12965779Sxy150489 * disabled, by a software over-ride.
12975779Sxy150489 */
12985779Sxy150489 mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
12995779Sxy150489 mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
13005779Sxy150489 break;
13015779Sxy150489 case e1000_fc_full:
13025779Sxy150489 /*
13035779Sxy150489 * Flow control (both Rx and Tx) is enabled by a software
13045779Sxy150489 * over-ride.
13055779Sxy150489 */
13065779Sxy150489 mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
13075779Sxy150489 break;
13085779Sxy150489 default:
13095779Sxy150489 DEBUGOUT("Flow control param set incorrectly\n");
13105779Sxy150489 ret_val = -E1000_ERR_CONFIG;
13115779Sxy150489 goto out;
13125779Sxy150489 }
13135779Sxy150489
13148571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
13155779Sxy150489 if (ret_val)
13165779Sxy150489 goto out;
13175779Sxy150489
13185779Sxy150489 DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
13195779Sxy150489
13205779Sxy150489 if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
13218571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
13225779Sxy150489 PHY_1000T_CTRL, mii_1000t_ctrl_reg);
13235779Sxy150489 if (ret_val)
13245779Sxy150489 goto out;
13255779Sxy150489 }
13265779Sxy150489
13275779Sxy150489 out:
13285779Sxy150489 return (ret_val);
13295779Sxy150489 }
13305779Sxy150489
13315779Sxy150489 /*
13325779Sxy150489 * e1000_setup_copper_link_generic - Configure copper link settings
13335779Sxy150489 * @hw: pointer to the HW structure
13345779Sxy150489 *
13355779Sxy150489 * Calls the appropriate function to configure the link for auto-neg or forced
13365779Sxy150489 * speed and duplex. Then we check for link, once link is established calls
13375779Sxy150489 * to configure collision distance and flow control are called. If link is
13385779Sxy150489 * not established, we return -E1000_ERR_PHY (-2).
13395779Sxy150489 */
13405779Sxy150489 s32
e1000_setup_copper_link_generic(struct e1000_hw * hw)13415779Sxy150489 e1000_setup_copper_link_generic(struct e1000_hw *hw)
13425779Sxy150489 {
13435779Sxy150489 s32 ret_val;
13445779Sxy150489 bool link;
13455779Sxy150489
13465779Sxy150489 DEBUGFUNC("e1000_setup_copper_link_generic");
13475779Sxy150489
13485779Sxy150489 if (hw->mac.autoneg) {
13495779Sxy150489 /*
13505779Sxy150489 * Setup autoneg and flow control advertisement and perform
13515779Sxy150489 * autonegotiation.
13525779Sxy150489 */
13535779Sxy150489 ret_val = e1000_copper_link_autoneg(hw);
13545779Sxy150489 if (ret_val)
13555779Sxy150489 goto out;
13565779Sxy150489 } else {
13575779Sxy150489 /*
13585779Sxy150489 * PHY will be set to 10H, 10F, 100H or 100F
13595779Sxy150489 * depending on user settings.
13605779Sxy150489 */
13615779Sxy150489 DEBUGOUT("Forcing Speed and Duplex\n");
13628571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.force_speed_duplex(hw);
13635779Sxy150489 if (ret_val) {
13645779Sxy150489 DEBUGOUT("Error Forcing Speed and Duplex\n");
13655779Sxy150489 goto out;
13665779Sxy150489 }
13675779Sxy150489 }
13685779Sxy150489
13695779Sxy150489 /*
13705779Sxy150489 * Check link status. Wait up to 100 microseconds for link to become
13715779Sxy150489 * valid.
13725779Sxy150489 */
13735779Sxy150489 ret_val = e1000_phy_has_link_generic(hw,
13745779Sxy150489 COPPER_LINK_UP_LIMIT,
13755779Sxy150489 10,
13765779Sxy150489 &link);
13775779Sxy150489 if (ret_val)
13785779Sxy150489 goto out;
13795779Sxy150489
13805779Sxy150489 if (link) {
13815779Sxy150489 DEBUGOUT("Valid link established!!!\n");
13825779Sxy150489 e1000_config_collision_dist_generic(hw);
13835779Sxy150489 ret_val = e1000_config_fc_after_link_up_generic(hw);
13845779Sxy150489 } else {
13855779Sxy150489 DEBUGOUT("Unable to establish link!!!\n");
13865779Sxy150489 }
13875779Sxy150489
13885779Sxy150489 out:
13895779Sxy150489 return (ret_val);
13905779Sxy150489 }
13915779Sxy150489
13925779Sxy150489 /*
13935779Sxy150489 * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
13945779Sxy150489 * @hw: pointer to the HW structure
13955779Sxy150489 *
13965779Sxy150489 * Calls the PHY setup function to force speed and duplex. Clears the
13975779Sxy150489 * auto-crossover to force MDI manually. Waits for link and returns
13985779Sxy150489 * successful if link up is successful, else -E1000_ERR_PHY (-2).
13995779Sxy150489 */
14005779Sxy150489 s32
e1000_phy_force_speed_duplex_igp(struct e1000_hw * hw)14015779Sxy150489 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
14025779Sxy150489 {
14035779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
14045779Sxy150489 s32 ret_val;
14055779Sxy150489 u16 phy_data;
14065779Sxy150489 bool link;
14075779Sxy150489
14085779Sxy150489 DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
14095779Sxy150489
14108571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
14115779Sxy150489 if (ret_val)
14125779Sxy150489 goto out;
14135779Sxy150489
14145779Sxy150489 e1000_phy_force_speed_duplex_setup(hw, &phy_data);
14155779Sxy150489
14168571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
14175779Sxy150489 if (ret_val)
14185779Sxy150489 goto out;
14195779Sxy150489
14205779Sxy150489 /*
14215779Sxy150489 * Clear Auto-Crossover to force MDI manually. IGP requires MDI
14225779Sxy150489 * forced whenever speed and duplex are forced.
14235779Sxy150489 */
14248571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
14255779Sxy150489 if (ret_val)
14265779Sxy150489 goto out;
14275779Sxy150489
14285779Sxy150489 phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
14295779Sxy150489 phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
14305779Sxy150489
14318571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
14325779Sxy150489 if (ret_val)
14335779Sxy150489 goto out;
14345779Sxy150489
14355779Sxy150489 DEBUGOUT1("IGP PSCR: %X\n", phy_data);
14365779Sxy150489
14375779Sxy150489 usec_delay(1);
14385779Sxy150489
14395779Sxy150489 if (phy->autoneg_wait_to_complete) {
14405779Sxy150489 DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
14415779Sxy150489
14425779Sxy150489 ret_val = e1000_phy_has_link_generic(hw,
14435779Sxy150489 PHY_FORCE_LIMIT,
14445779Sxy150489 100000,
14455779Sxy150489 &link);
14465779Sxy150489 if (ret_val)
14475779Sxy150489 goto out;
14485779Sxy150489
14498571SChenlu.Chen@Sun.COM if (!link)
14505779Sxy150489 DEBUGOUT("Link taking longer than expected.\n");
14515779Sxy150489
14525779Sxy150489 /* Try once more */
14535779Sxy150489 ret_val = e1000_phy_has_link_generic(hw,
14545779Sxy150489 PHY_FORCE_LIMIT,
14555779Sxy150489 100000,
14565779Sxy150489 &link);
14575779Sxy150489 if (ret_val)
14585779Sxy150489 goto out;
14595779Sxy150489 }
14605779Sxy150489
14615779Sxy150489 out:
14625779Sxy150489 return (ret_val);
14635779Sxy150489 }
14645779Sxy150489
14655779Sxy150489 /*
14665779Sxy150489 * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
14675779Sxy150489 * @hw: pointer to the HW structure
14685779Sxy150489 *
14695779Sxy150489 * Calls the PHY setup function to force speed and duplex. Clears the
14705779Sxy150489 * auto-crossover to force MDI manually. Resets the PHY to commit the
14715779Sxy150489 * changes. If time expires while waiting for link up, we reset the DSP.
14725779Sxy150489 * After reset, TX_CLK and CRS on Tx must be set. Return successful upon
14735779Sxy150489 * successful completion, else return corresponding error code.
14745779Sxy150489 */
14755779Sxy150489 s32
e1000_phy_force_speed_duplex_m88(struct e1000_hw * hw)14765779Sxy150489 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
14775779Sxy150489 {
14785779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
14795779Sxy150489 s32 ret_val;
14805779Sxy150489 u16 phy_data;
14815779Sxy150489 bool link;
14825779Sxy150489
14835779Sxy150489 DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
14845779Sxy150489
14855779Sxy150489 /*
14865779Sxy150489 * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
14875779Sxy150489 * forced whenever speed and duplex are forced.
14885779Sxy150489 */
14898571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
14905779Sxy150489 if (ret_val)
14915779Sxy150489 goto out;
14925779Sxy150489
14935779Sxy150489 phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
14948571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
14955779Sxy150489 if (ret_val)
14965779Sxy150489 goto out;
14975779Sxy150489
14985779Sxy150489 DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
14995779Sxy150489
15008571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
15015779Sxy150489 if (ret_val)
15025779Sxy150489 goto out;
15035779Sxy150489
15045779Sxy150489 e1000_phy_force_speed_duplex_setup(hw, &phy_data);
15055779Sxy150489
15068571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
15075779Sxy150489 if (ret_val)
15085779Sxy150489 goto out;
15095779Sxy150489
15108571SChenlu.Chen@Sun.COM /* Reset the phy to commit changes. */
15118571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.commit(hw);
15128571SChenlu.Chen@Sun.COM if (ret_val)
15138571SChenlu.Chen@Sun.COM goto out;
15145779Sxy150489
15155779Sxy150489 if (phy->autoneg_wait_to_complete) {
15165779Sxy150489 DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
15175779Sxy150489
15188571SChenlu.Chen@Sun.COM ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
15198571SChenlu.Chen@Sun.COM 100000, &link);
15205779Sxy150489 if (ret_val)
15215779Sxy150489 goto out;
15225779Sxy150489
15235779Sxy150489 if (!link) {
15245779Sxy150489 /*
15255779Sxy150489 * We didn't get link.
15265779Sxy150489 * Reset the DSP and cross our fingers.
15275779Sxy150489 */
15288571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
15295779Sxy150489 M88E1000_PHY_PAGE_SELECT,
15305779Sxy150489 0x001d);
15315779Sxy150489 if (ret_val)
15325779Sxy150489 goto out;
15335779Sxy150489 ret_val = e1000_phy_reset_dsp_generic(hw);
15345779Sxy150489 if (ret_val)
15355779Sxy150489 goto out;
15365779Sxy150489 }
15375779Sxy150489
15385779Sxy150489 /* Try once more */
15398571SChenlu.Chen@Sun.COM ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
15408571SChenlu.Chen@Sun.COM 100000, &link);
15415779Sxy150489 if (ret_val)
15425779Sxy150489 goto out;
15435779Sxy150489 }
15445779Sxy150489
15458571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
15465779Sxy150489 if (ret_val)
15475779Sxy150489 goto out;
15485779Sxy150489
15495779Sxy150489 /*
15505779Sxy150489 * Resetting the phy means we need to re-force TX_CLK in the
15515779Sxy150489 * Extended PHY Specific Control Register to 25MHz clock from
15525779Sxy150489 * the reset value of 2.5MHz.
15535779Sxy150489 */
15545779Sxy150489 phy_data |= M88E1000_EPSCR_TX_CLK_25;
15558571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
15565779Sxy150489 if (ret_val)
15575779Sxy150489 goto out;
15585779Sxy150489
15595779Sxy150489 /*
15605779Sxy150489 * In addition, we must re-enable CRS on Tx for both half and full
15615779Sxy150489 * duplex.
15625779Sxy150489 */
15638571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
15645779Sxy150489 if (ret_val)
15655779Sxy150489 goto out;
15665779Sxy150489
15675779Sxy150489 phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
15688571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
15695779Sxy150489
15705779Sxy150489 out:
15715779Sxy150489 return (ret_val);
15725779Sxy150489 }
15735779Sxy150489
15745779Sxy150489 /*
157510319SJason.Xu@Sun.COM * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
157610319SJason.Xu@Sun.COM * @hw: pointer to the HW structure
157710319SJason.Xu@Sun.COM *
157810319SJason.Xu@Sun.COM * Forces the speed and duplex settings of the PHY.
157910319SJason.Xu@Sun.COM * This is a function pointer entry point only called by
158010319SJason.Xu@Sun.COM * PHY setup routines.
158110319SJason.Xu@Sun.COM */
158210319SJason.Xu@Sun.COM s32
e1000_phy_force_speed_duplex_ife(struct e1000_hw * hw)158310319SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
158410319SJason.Xu@Sun.COM {
158510319SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
158610319SJason.Xu@Sun.COM s32 ret_val;
158710319SJason.Xu@Sun.COM u16 data;
158810319SJason.Xu@Sun.COM bool link;
158910319SJason.Xu@Sun.COM
159010319SJason.Xu@Sun.COM DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
159110319SJason.Xu@Sun.COM
159210319SJason.Xu@Sun.COM if (phy->type != e1000_phy_ife) {
159310319SJason.Xu@Sun.COM ret_val = e1000_phy_force_speed_duplex_igp(hw);
159410319SJason.Xu@Sun.COM goto out;
159510319SJason.Xu@Sun.COM }
159610319SJason.Xu@Sun.COM
159710319SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
159810319SJason.Xu@Sun.COM if (ret_val)
159910319SJason.Xu@Sun.COM goto out;
160010319SJason.Xu@Sun.COM
160110319SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_setup(hw, &data);
160210319SJason.Xu@Sun.COM
160310319SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
160410319SJason.Xu@Sun.COM if (ret_val)
160510319SJason.Xu@Sun.COM goto out;
160610319SJason.Xu@Sun.COM
160710319SJason.Xu@Sun.COM /* Disable MDI-X support for 10/100 */
160810319SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
160910319SJason.Xu@Sun.COM if (ret_val)
161010319SJason.Xu@Sun.COM goto out;
161110319SJason.Xu@Sun.COM
161210319SJason.Xu@Sun.COM data &= ~IFE_PMC_AUTO_MDIX;
161310319SJason.Xu@Sun.COM data &= ~IFE_PMC_FORCE_MDIX;
161410319SJason.Xu@Sun.COM
161510319SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
161610319SJason.Xu@Sun.COM if (ret_val)
161710319SJason.Xu@Sun.COM goto out;
161810319SJason.Xu@Sun.COM
161910319SJason.Xu@Sun.COM DEBUGOUT1("IFE PMC: %X\n", data);
162010319SJason.Xu@Sun.COM
162110319SJason.Xu@Sun.COM usec_delay(1);
162210319SJason.Xu@Sun.COM
162310319SJason.Xu@Sun.COM if (phy->autoneg_wait_to_complete) {
162410319SJason.Xu@Sun.COM DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
162510319SJason.Xu@Sun.COM
162610319SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw,
162710319SJason.Xu@Sun.COM PHY_FORCE_LIMIT, 100000, &link);
162810319SJason.Xu@Sun.COM if (ret_val)
162910319SJason.Xu@Sun.COM goto out;
163010319SJason.Xu@Sun.COM
163110319SJason.Xu@Sun.COM if (!link)
163210319SJason.Xu@Sun.COM DEBUGOUT("Link taking longer than expected.\n");
163310319SJason.Xu@Sun.COM
163410319SJason.Xu@Sun.COM /* Try once more */
163510319SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw,
163610319SJason.Xu@Sun.COM PHY_FORCE_LIMIT, 100000, &link);
163710319SJason.Xu@Sun.COM if (ret_val)
163810319SJason.Xu@Sun.COM goto out;
163910319SJason.Xu@Sun.COM }
164010319SJason.Xu@Sun.COM
164110319SJason.Xu@Sun.COM out:
164210319SJason.Xu@Sun.COM return (ret_val);
164310319SJason.Xu@Sun.COM }
164410319SJason.Xu@Sun.COM /*
16455779Sxy150489 * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
16465779Sxy150489 * @hw: pointer to the HW structure
16475779Sxy150489 * @phy_ctrl: pointer to current value of PHY_CONTROL
16485779Sxy150489 *
16495779Sxy150489 * Forces speed and duplex on the PHY by doing the following: disable flow
16505779Sxy150489 * control, force speed/duplex on the MAC, disable auto speed detection,
16515779Sxy150489 * disable auto-negotiation, configure duplex, configure speed, configure
16525779Sxy150489 * the collision distance, write configuration to CTRL register. The
16535779Sxy150489 * caller must write to the PHY_CONTROL register for these settings to
16545779Sxy150489 * take affect.
16555779Sxy150489 */
16565779Sxy150489 void
e1000_phy_force_speed_duplex_setup(struct e1000_hw * hw,u16 * phy_ctrl)16575779Sxy150489 e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
16585779Sxy150489 {
16595779Sxy150489 struct e1000_mac_info *mac = &hw->mac;
16605779Sxy150489 u32 ctrl;
16615779Sxy150489
16625779Sxy150489 DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
16635779Sxy150489
16645779Sxy150489 /* Turn off flow control when forcing speed/duplex */
16658571SChenlu.Chen@Sun.COM hw->fc.current_mode = e1000_fc_none;
16665779Sxy150489
16675779Sxy150489 /* Force speed/duplex on the mac */
16685779Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
16695779Sxy150489 ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
16705779Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL;
16715779Sxy150489
16725779Sxy150489 /* Disable Auto Speed Detection */
16735779Sxy150489 ctrl &= ~E1000_CTRL_ASDE;
16745779Sxy150489
16755779Sxy150489 /* Disable autoneg on the phy */
16765779Sxy150489 *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
16775779Sxy150489
16785779Sxy150489 /* Forcing Full or Half Duplex? */
16795779Sxy150489 if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
16805779Sxy150489 ctrl &= ~E1000_CTRL_FD;
16815779Sxy150489 *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
16825779Sxy150489 DEBUGOUT("Half Duplex\n");
16835779Sxy150489 } else {
16845779Sxy150489 ctrl |= E1000_CTRL_FD;
16855779Sxy150489 *phy_ctrl |= MII_CR_FULL_DUPLEX;
16865779Sxy150489 DEBUGOUT("Full Duplex\n");
16875779Sxy150489 }
16885779Sxy150489
16895779Sxy150489 /* Forcing 10mb or 100mb? */
16905779Sxy150489 if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
16915779Sxy150489 ctrl |= E1000_CTRL_SPD_100;
16925779Sxy150489 *phy_ctrl |= MII_CR_SPEED_100;
16935779Sxy150489 *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
16945779Sxy150489 DEBUGOUT("Forcing 100mb\n");
16955779Sxy150489 } else {
16965779Sxy150489 ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
16975779Sxy150489 /* LINTED */
16985779Sxy150489 *phy_ctrl |= MII_CR_SPEED_10;
16995779Sxy150489 *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
17005779Sxy150489 DEBUGOUT("Forcing 10mb\n");
17015779Sxy150489 }
17025779Sxy150489
17035779Sxy150489 e1000_config_collision_dist_generic(hw);
17045779Sxy150489
17055779Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
17065779Sxy150489 }
17075779Sxy150489
17085779Sxy150489 /*
17095779Sxy150489 * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
17105779Sxy150489 * @hw: pointer to the HW structure
17115779Sxy150489 * @active: boolean used to enable/disable lplu
17125779Sxy150489 *
17135779Sxy150489 * Success returns 0, Failure returns 1
17145779Sxy150489 *
17155779Sxy150489 * The low power link up (lplu) state is set to the power management level D3
17165779Sxy150489 * and SmartSpeed is disabled when active is true, else clear lplu for D3
17175779Sxy150489 * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
17185779Sxy150489 * is used during Dx states where the power conservation is most important.
17195779Sxy150489 * During driver activity, SmartSpeed should be enabled so performance is
17205779Sxy150489 * maintained.
17215779Sxy150489 */
17225779Sxy150489 s32
e1000_set_d3_lplu_state_generic(struct e1000_hw * hw,bool active)17235779Sxy150489 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
17245779Sxy150489 {
17255779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
17268571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
17275779Sxy150489 u16 data;
17285779Sxy150489
17295779Sxy150489 DEBUGFUNC("e1000_set_d3_lplu_state_generic");
17305779Sxy150489
17318571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg))
17328571SChenlu.Chen@Sun.COM goto out;
17338571SChenlu.Chen@Sun.COM
17348571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
17355779Sxy150489 if (ret_val)
17365779Sxy150489 goto out;
17375779Sxy150489
17385779Sxy150489 if (!active) {
17395779Sxy150489 data &= ~IGP02E1000_PM_D3_LPLU;
17408571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
17415779Sxy150489 IGP02E1000_PHY_POWER_MGMT,
17425779Sxy150489 data);
17435779Sxy150489 if (ret_val)
17445779Sxy150489 goto out;
17455779Sxy150489 /*
17465779Sxy150489 * LPLU and SmartSpeed are mutually exclusive. LPLU is used
17475779Sxy150489 * during Dx states where the power conservation is most
17485779Sxy150489 * important. During driver activity we should enable
17495779Sxy150489 * SmartSpeed, so performance is maintained.
17505779Sxy150489 */
17515779Sxy150489 if (phy->smart_speed == e1000_smart_speed_on) {
17528571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw,
17535779Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
17545779Sxy150489 &data);
17555779Sxy150489 if (ret_val)
17565779Sxy150489 goto out;
17575779Sxy150489
17585779Sxy150489 data |= IGP01E1000_PSCFR_SMART_SPEED;
17598571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
17605779Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
17615779Sxy150489 data);
17625779Sxy150489 if (ret_val)
17635779Sxy150489 goto out;
17645779Sxy150489 } else if (phy->smart_speed == e1000_smart_speed_off) {
17658571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw,
17665779Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
17675779Sxy150489 &data);
17685779Sxy150489 if (ret_val)
17695779Sxy150489 goto out;
17705779Sxy150489
17715779Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
17728571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
17735779Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
17745779Sxy150489 data);
17755779Sxy150489 if (ret_val)
17765779Sxy150489 goto out;
17775779Sxy150489 }
17785779Sxy150489 } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
17795779Sxy150489 (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
17805779Sxy150489 (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
17815779Sxy150489 data |= IGP02E1000_PM_D3_LPLU;
17828571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
17835779Sxy150489 IGP02E1000_PHY_POWER_MGMT,
17845779Sxy150489 data);
17855779Sxy150489 if (ret_val)
17865779Sxy150489 goto out;
17875779Sxy150489
17885779Sxy150489 /* When LPLU is enabled, we should disable SmartSpeed */
17898571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw,
17905779Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
17915779Sxy150489 &data);
17925779Sxy150489 if (ret_val)
17935779Sxy150489 goto out;
17945779Sxy150489
17955779Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
17968571SChenlu.Chen@Sun.COM ret_val = phy->ops.write_reg(hw,
17975779Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
17985779Sxy150489 data);
17995779Sxy150489 }
18005779Sxy150489
18015779Sxy150489 out:
18025779Sxy150489 return (ret_val);
18035779Sxy150489 }
18045779Sxy150489
18055779Sxy150489 /*
18068571SChenlu.Chen@Sun.COM * e1000_check_downshift_generic - Checks whether a downshift in speed occurred
18075779Sxy150489 * @hw: pointer to the HW structure
18085779Sxy150489 *
18095779Sxy150489 * Success returns 0, Failure returns 1
18105779Sxy150489 *
18115779Sxy150489 * A downshift is detected by querying the PHY link health.
18125779Sxy150489 */
18135779Sxy150489 s32
e1000_check_downshift_generic(struct e1000_hw * hw)18145779Sxy150489 e1000_check_downshift_generic(struct e1000_hw *hw)
18155779Sxy150489 {
18165779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
18175779Sxy150489 s32 ret_val;
18185779Sxy150489 u16 phy_data, offset, mask;
18195779Sxy150489
18205779Sxy150489 DEBUGFUNC("e1000_check_downshift_generic");
18215779Sxy150489
18225779Sxy150489 switch (phy->type) {
18235779Sxy150489 case e1000_phy_m88:
18245779Sxy150489 case e1000_phy_gg82563:
18255779Sxy150489 offset = M88E1000_PHY_SPEC_STATUS;
18265779Sxy150489 mask = M88E1000_PSSR_DOWNSHIFT;
18275779Sxy150489 break;
18285779Sxy150489 case e1000_phy_igp_2:
18295779Sxy150489 case e1000_phy_igp:
18305779Sxy150489 case e1000_phy_igp_3:
18315779Sxy150489 offset = IGP01E1000_PHY_LINK_HEALTH;
18325779Sxy150489 mask = IGP01E1000_PLHR_SS_DOWNGRADE;
18335779Sxy150489 break;
18345779Sxy150489 default:
18355779Sxy150489 /* speed downshift not supported */
18368571SChenlu.Chen@Sun.COM phy->speed_downgraded = false;
18375779Sxy150489 ret_val = E1000_SUCCESS;
18385779Sxy150489 goto out;
18395779Sxy150489 }
18405779Sxy150489
18418571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, offset, &phy_data);
18425779Sxy150489
18435779Sxy150489 if (!ret_val)
18448571SChenlu.Chen@Sun.COM phy->speed_downgraded = (phy_data & mask) ? true : false;
18455779Sxy150489
18465779Sxy150489 out:
18475779Sxy150489 return (ret_val);
18485779Sxy150489 }
18495779Sxy150489
18505779Sxy150489 /*
18515779Sxy150489 * e1000_check_polarity_m88 - Checks the polarity.
18525779Sxy150489 * @hw: pointer to the HW structure
18535779Sxy150489 *
18545779Sxy150489 * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
18555779Sxy150489 *
18565779Sxy150489 * Polarity is determined based on the PHY specific status register.
18575779Sxy150489 */
18585779Sxy150489 s32
e1000_check_polarity_m88(struct e1000_hw * hw)18595779Sxy150489 e1000_check_polarity_m88(struct e1000_hw *hw)
18605779Sxy150489 {
18615779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
18625779Sxy150489 s32 ret_val;
18635779Sxy150489 u16 data;
18645779Sxy150489
18655779Sxy150489 DEBUGFUNC("e1000_check_polarity_m88");
18665779Sxy150489
18678571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
18685779Sxy150489
18695779Sxy150489 if (!ret_val)
18705779Sxy150489 phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
18715779Sxy150489 ? e1000_rev_polarity_reversed
18725779Sxy150489 : e1000_rev_polarity_normal;
18735779Sxy150489
18745779Sxy150489 return (ret_val);
18755779Sxy150489 }
18765779Sxy150489
18775779Sxy150489 /*
18785779Sxy150489 * e1000_check_polarity_igp - Checks the polarity.
18795779Sxy150489 * @hw: pointer to the HW structure
18805779Sxy150489 *
18815779Sxy150489 * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
18825779Sxy150489 *
18835779Sxy150489 * Polarity is determined based on the PHY port status register, and the
18845779Sxy150489 * current speed (since there is no polarity at 100Mbps).
18855779Sxy150489 */
18865779Sxy150489 s32
e1000_check_polarity_igp(struct e1000_hw * hw)18875779Sxy150489 e1000_check_polarity_igp(struct e1000_hw *hw)
18885779Sxy150489 {
18895779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
18905779Sxy150489 s32 ret_val;
18915779Sxy150489 u16 data, offset, mask;
18925779Sxy150489
18935779Sxy150489 DEBUGFUNC("e1000_check_polarity_igp");
18945779Sxy150489
18955779Sxy150489 /*
18965779Sxy150489 * Polarity is determined based on the speed of
18975779Sxy150489 * our connection.
18985779Sxy150489 */
18998571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
19005779Sxy150489 if (ret_val)
19015779Sxy150489 goto out;
19025779Sxy150489
19035779Sxy150489 if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
19045779Sxy150489 IGP01E1000_PSSR_SPEED_1000MBPS) {
19055779Sxy150489 offset = IGP01E1000_PHY_PCS_INIT_REG;
19065779Sxy150489 mask = IGP01E1000_PHY_POLARITY_MASK;
19075779Sxy150489 } else {
19085779Sxy150489 /*
19095779Sxy150489 * This really only applies to 10Mbps since
19105779Sxy150489 * there is no polarity for 100Mbps (always 0).
19115779Sxy150489 */
19125779Sxy150489 offset = IGP01E1000_PHY_PORT_STATUS;
19135779Sxy150489 mask = IGP01E1000_PSSR_POLARITY_REVERSED;
19145779Sxy150489 }
19155779Sxy150489
19168571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, offset, &data);
19175779Sxy150489
19185779Sxy150489 if (!ret_val)
19195779Sxy150489 phy->cable_polarity = (data & mask)
19205779Sxy150489 ? e1000_rev_polarity_reversed
19215779Sxy150489 : e1000_rev_polarity_normal;
19225779Sxy150489
19235779Sxy150489 out:
19245779Sxy150489 return (ret_val);
19255779Sxy150489 }
19265779Sxy150489
19275779Sxy150489 /*
192810319SJason.Xu@Sun.COM * e1000_check_polarity_ife - Check cable polarity for IFE PHY
192910319SJason.Xu@Sun.COM * @hw: pointer to the HW structure
193010319SJason.Xu@Sun.COM *
193110319SJason.Xu@Sun.COM * Polarity is determined on the polarity reversal feature being enabled.
193210319SJason.Xu@Sun.COM */
193310319SJason.Xu@Sun.COM s32
e1000_check_polarity_ife(struct e1000_hw * hw)193410319SJason.Xu@Sun.COM e1000_check_polarity_ife(struct e1000_hw *hw)
193510319SJason.Xu@Sun.COM {
193610319SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
193710319SJason.Xu@Sun.COM s32 ret_val;
193810319SJason.Xu@Sun.COM u16 phy_data, offset, mask;
193910319SJason.Xu@Sun.COM
194010319SJason.Xu@Sun.COM DEBUGFUNC("e1000_check_polarity_ife");
194110319SJason.Xu@Sun.COM
194210319SJason.Xu@Sun.COM /*
194310319SJason.Xu@Sun.COM * Polarity is determined based on the reversal feature being enabled.
194410319SJason.Xu@Sun.COM */
194510319SJason.Xu@Sun.COM if (phy->polarity_correction) {
194610319SJason.Xu@Sun.COM offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
194710319SJason.Xu@Sun.COM mask = IFE_PESC_POLARITY_REVERSED;
194810319SJason.Xu@Sun.COM } else {
194910319SJason.Xu@Sun.COM offset = IFE_PHY_SPECIAL_CONTROL;
195010319SJason.Xu@Sun.COM mask = IFE_PSC_FORCE_POLARITY;
195110319SJason.Xu@Sun.COM }
195210319SJason.Xu@Sun.COM
195310319SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, offset, &phy_data);
195410319SJason.Xu@Sun.COM
195510319SJason.Xu@Sun.COM if (!ret_val)
195610319SJason.Xu@Sun.COM phy->cable_polarity = (phy_data & mask)
195710319SJason.Xu@Sun.COM ? e1000_rev_polarity_reversed
195810319SJason.Xu@Sun.COM : e1000_rev_polarity_normal;
195910319SJason.Xu@Sun.COM
196010319SJason.Xu@Sun.COM return (ret_val);
196110319SJason.Xu@Sun.COM }
196210319SJason.Xu@Sun.COM /*
19638571SChenlu.Chen@Sun.COM * e1000_wait_autoneg_generic - Wait for auto-neg completion
19645779Sxy150489 * @hw: pointer to the HW structure
19655779Sxy150489 *
19665779Sxy150489 * Waits for auto-negotiation to complete or for the auto-negotiation time
19675779Sxy150489 * limit to expire, which ever happens first.
19685779Sxy150489 */
19695779Sxy150489 s32
e1000_wait_autoneg_generic(struct e1000_hw * hw)19705779Sxy150489 e1000_wait_autoneg_generic(struct e1000_hw *hw)
19715779Sxy150489 {
19725779Sxy150489 s32 ret_val = E1000_SUCCESS;
19735779Sxy150489 u16 i, phy_status;
19745779Sxy150489
19755779Sxy150489 DEBUGFUNC("e1000_wait_autoneg_generic");
19765779Sxy150489
19778571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg))
19788571SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
19798571SChenlu.Chen@Sun.COM
19805779Sxy150489 /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
19815779Sxy150489 for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
19828571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
19835779Sxy150489 if (ret_val)
19845779Sxy150489 break;
19858571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
19865779Sxy150489 if (ret_val)
19875779Sxy150489 break;
19885779Sxy150489 if (phy_status & MII_SR_AUTONEG_COMPLETE)
19895779Sxy150489 break;
19905779Sxy150489 msec_delay(100);
19915779Sxy150489 }
19925779Sxy150489
19935779Sxy150489 /*
19945779Sxy150489 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
19955779Sxy150489 * has completed.
19965779Sxy150489 */
19975779Sxy150489 return (ret_val);
19985779Sxy150489 }
19995779Sxy150489
20005779Sxy150489 /*
20015779Sxy150489 * e1000_phy_has_link_generic - Polls PHY for link
20025779Sxy150489 * @hw: pointer to the HW structure
20035779Sxy150489 * @iterations: number of times to poll for link
20045779Sxy150489 * @usec_interval: delay between polling attempts
20055779Sxy150489 * @success: pointer to whether polling was successful or not
20065779Sxy150489 *
20075779Sxy150489 * Polls the PHY status register for link, 'iterations' number of times.
20085779Sxy150489 */
20095779Sxy150489 s32
e1000_phy_has_link_generic(struct e1000_hw * hw,u32 iterations,u32 usec_interval,bool * success)20105779Sxy150489 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
20115779Sxy150489 u32 usec_interval, bool *success)
20125779Sxy150489 {
20135779Sxy150489 s32 ret_val = E1000_SUCCESS;
20145779Sxy150489 u16 i, phy_status;
20155779Sxy150489
20165779Sxy150489 DEBUGFUNC("e1000_phy_has_link_generic");
20175779Sxy150489
20188571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg))
20198571SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
20208571SChenlu.Chen@Sun.COM
20215779Sxy150489 for (i = 0; i < iterations; i++) {
20225779Sxy150489 /*
20235779Sxy150489 * Some PHYs require the PHY_STATUS register to be read
20245779Sxy150489 * twice due to the link bit being sticky. No harm doing
20255779Sxy150489 * it across the board.
20265779Sxy150489 */
20278571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
202810319SJason.Xu@Sun.COM if (ret_val) {
202910319SJason.Xu@Sun.COM /*
203010319SJason.Xu@Sun.COM * If the first read fails, another entity may have
203110319SJason.Xu@Sun.COM * ownership of the resources, wait and try again to
203210319SJason.Xu@Sun.COM * see if they have relinquished the resources yet.
203310319SJason.Xu@Sun.COM */
203410319SJason.Xu@Sun.COM usec_delay(usec_interval);
203510319SJason.Xu@Sun.COM }
203611155SJason.Xu@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
20375779Sxy150489 if (ret_val)
20385779Sxy150489 break;
20395779Sxy150489 if (phy_status & MII_SR_LINK_STATUS)
20405779Sxy150489 break;
20415779Sxy150489 if (usec_interval >= 1000)
20425779Sxy150489 msec_delay_irq(usec_interval/1000);
20435779Sxy150489 else
20445779Sxy150489 usec_delay(usec_interval);
20455779Sxy150489 }
20465779Sxy150489
20478571SChenlu.Chen@Sun.COM *success = (i < iterations) ? true : false;
20485779Sxy150489
20495779Sxy150489 return (ret_val);
20505779Sxy150489 }
20515779Sxy150489
20525779Sxy150489 /*
20535779Sxy150489 * e1000_get_cable_length_m88 - Determine cable length for m88 PHY
20545779Sxy150489 * @hw: pointer to the HW structure
20555779Sxy150489 *
20565779Sxy150489 * Reads the PHY specific status register to retrieve the cable length
20575779Sxy150489 * information. The cable length is determined by averaging the minimum and
20585779Sxy150489 * maximum values to get the "average" cable length. The m88 PHY has four
20595779Sxy150489 * possible cable length values, which are:
20605779Sxy150489 * Register Value Cable Length
20615779Sxy150489 * 0 < 50 meters
20625779Sxy150489 * 1 50 - 80 meters
20635779Sxy150489 * 2 80 - 110 meters
20645779Sxy150489 * 3 110 - 140 meters
20655779Sxy150489 * 4 > 140 meters
20665779Sxy150489 */
20675779Sxy150489 s32
e1000_get_cable_length_m88(struct e1000_hw * hw)20685779Sxy150489 e1000_get_cable_length_m88(struct e1000_hw *hw)
20695779Sxy150489 {
20705779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
20715779Sxy150489 s32 ret_val;
20725779Sxy150489 u16 phy_data, index;
20735779Sxy150489
20745779Sxy150489 DEBUGFUNC("e1000_get_cable_length_m88");
20755779Sxy150489
20768571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
20775779Sxy150489 if (ret_val)
20785779Sxy150489 goto out;
20795779Sxy150489
20805779Sxy150489 index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
20815779Sxy150489 M88E1000_PSSR_CABLE_LENGTH_SHIFT;
208211155SJason.Xu@Sun.COM if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
208311155SJason.Xu@Sun.COM ret_val = -E1000_ERR_PHY;
208410319SJason.Xu@Sun.COM goto out;
208510319SJason.Xu@Sun.COM }
20865779Sxy150489
208710319SJason.Xu@Sun.COM phy->min_cable_length = e1000_m88_cable_length_table[index];
208811155SJason.Xu@Sun.COM phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
208910319SJason.Xu@Sun.COM
209010319SJason.Xu@Sun.COM phy->cable_length = (phy->min_cable_length +
209110319SJason.Xu@Sun.COM phy->max_cable_length) / 2;
20925779Sxy150489
20935779Sxy150489 out:
20945779Sxy150489 return (ret_val);
20955779Sxy150489 }
20965779Sxy150489
20975779Sxy150489 /*
20985779Sxy150489 * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
20995779Sxy150489 * @hw: pointer to the HW structure
21005779Sxy150489 *
21015779Sxy150489 * The automatic gain control (agc) normalizes the amplitude of the
21025779Sxy150489 * received signal, adjusting for the attenuation produced by the
21038571SChenlu.Chen@Sun.COM * cable. By reading the AGC registers, which represent the
21048571SChenlu.Chen@Sun.COM * combination of coarse and fine gain value, the value can be put
21055779Sxy150489 * into a lookup table to obtain the approximate cable length
21065779Sxy150489 * for each channel.
21075779Sxy150489 */
21085779Sxy150489 s32
e1000_get_cable_length_igp_2(struct e1000_hw * hw)21095779Sxy150489 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
21105779Sxy150489 {
21115779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
21125779Sxy150489 s32 ret_val = E1000_SUCCESS;
21135779Sxy150489 u16 phy_data, i, agc_value = 0;
21145779Sxy150489 u16 cur_agc_index, max_agc_index = 0;
21155779Sxy150489 u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
21165779Sxy150489 u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
21175779Sxy150489 {IGP02E1000_PHY_AGC_A,
21185779Sxy150489 IGP02E1000_PHY_AGC_B,
21195779Sxy150489 IGP02E1000_PHY_AGC_C,
21205779Sxy150489 IGP02E1000_PHY_AGC_D};
21215779Sxy150489
21225779Sxy150489 DEBUGFUNC("e1000_get_cable_length_igp_2");
21235779Sxy150489
21245779Sxy150489 /* Read the AGC registers for all channels */
21255779Sxy150489 for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
21268571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
21275779Sxy150489 if (ret_val)
21285779Sxy150489 goto out;
21295779Sxy150489
21305779Sxy150489 /*
21315779Sxy150489 * Getting bits 15:9, which represent the combination of
21328571SChenlu.Chen@Sun.COM * coarse and fine gain values. The result is a number
21335779Sxy150489 * that can be put into the lookup table to obtain the
21345779Sxy150489 * approximate cable length.
21355779Sxy150489 */
21365779Sxy150489 cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
21375779Sxy150489 IGP02E1000_AGC_LENGTH_MASK;
21385779Sxy150489
21395779Sxy150489 /* Array index bound check. */
21405779Sxy150489 if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
21415779Sxy150489 (cur_agc_index == 0)) {
21425779Sxy150489 ret_val = -E1000_ERR_PHY;
21435779Sxy150489 goto out;
21445779Sxy150489 }
21455779Sxy150489
21465779Sxy150489 /* Remove min & max AGC values from calculation. */
21475779Sxy150489 if (e1000_igp_2_cable_length_table[min_agc_index] >
21485779Sxy150489 e1000_igp_2_cable_length_table[cur_agc_index])
21495779Sxy150489 min_agc_index = cur_agc_index;
21505779Sxy150489 if (e1000_igp_2_cable_length_table[max_agc_index] <
21515779Sxy150489 e1000_igp_2_cable_length_table[cur_agc_index])
21525779Sxy150489 max_agc_index = cur_agc_index;
21535779Sxy150489
21545779Sxy150489 agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
21555779Sxy150489 }
21565779Sxy150489
21575779Sxy150489 agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
21585779Sxy150489 e1000_igp_2_cable_length_table[max_agc_index]);
21595779Sxy150489 agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
21605779Sxy150489
21615779Sxy150489 /* Calculate cable length with the error range of +/- 10 meters. */
21625779Sxy150489 phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
21635779Sxy150489 (agc_value - IGP02E1000_AGC_RANGE) : 0;
21645779Sxy150489 phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
21655779Sxy150489
21665779Sxy150489 phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
21675779Sxy150489
21685779Sxy150489 out:
21695779Sxy150489 return (ret_val);
21705779Sxy150489 }
21715779Sxy150489
21725779Sxy150489 /*
21735779Sxy150489 * e1000_get_phy_info_m88 - Retrieve PHY information
21745779Sxy150489 * @hw: pointer to the HW structure
21755779Sxy150489 *
21765779Sxy150489 * Valid for only copper links. Read the PHY status register (sticky read)
21775779Sxy150489 * to verify that link is up. Read the PHY special control register to
21785779Sxy150489 * determine the polarity and 10base-T extended distance. Read the PHY
21795779Sxy150489 * special status register to determine MDI/MDIx and current speed. If
21805779Sxy150489 * speed is 1000, then determine cable length, local and remote receiver.
21815779Sxy150489 */
21825779Sxy150489 s32
e1000_get_phy_info_m88(struct e1000_hw * hw)21835779Sxy150489 e1000_get_phy_info_m88(struct e1000_hw *hw)
21845779Sxy150489 {
21855779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
21865779Sxy150489 s32 ret_val;
21875779Sxy150489 u16 phy_data;
21885779Sxy150489 bool link;
21895779Sxy150489
21905779Sxy150489 DEBUGFUNC("e1000_get_phy_info_m88");
21915779Sxy150489
219211155SJason.Xu@Sun.COM if (phy->media_type != e1000_media_type_copper) {
21935779Sxy150489 DEBUGOUT("Phy info is only valid for copper media\n");
21945779Sxy150489 ret_val = -E1000_ERR_CONFIG;
21955779Sxy150489 goto out;
21965779Sxy150489 }
21975779Sxy150489
21985779Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
21995779Sxy150489 if (ret_val)
22005779Sxy150489 goto out;
22015779Sxy150489
22025779Sxy150489 if (!link) {
22035779Sxy150489 DEBUGOUT("Phy info is only valid if link is up\n");
22045779Sxy150489 ret_val = -E1000_ERR_CONFIG;
22055779Sxy150489 goto out;
22065779Sxy150489 }
22075779Sxy150489
22088571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
22095779Sxy150489 if (ret_val)
22105779Sxy150489 goto out;
22115779Sxy150489
22125779Sxy150489 phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
22138571SChenlu.Chen@Sun.COM ? true : false;
22145779Sxy150489
22155779Sxy150489 ret_val = e1000_check_polarity_m88(hw);
22165779Sxy150489 if (ret_val)
22175779Sxy150489 goto out;
22185779Sxy150489
22198571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
22205779Sxy150489 if (ret_val)
22215779Sxy150489 goto out;
22225779Sxy150489
22238571SChenlu.Chen@Sun.COM phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
22245779Sxy150489
22255779Sxy150489 if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
22268571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.get_cable_length(hw);
22275779Sxy150489 if (ret_val)
22285779Sxy150489 goto out;
22295779Sxy150489
22308571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
22315779Sxy150489 if (ret_val)
22325779Sxy150489 goto out;
22335779Sxy150489
22345779Sxy150489 phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
22355779Sxy150489 ? e1000_1000t_rx_status_ok
22365779Sxy150489 : e1000_1000t_rx_status_not_ok;
22375779Sxy150489
22385779Sxy150489 phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
22395779Sxy150489 ? e1000_1000t_rx_status_ok
22405779Sxy150489 : e1000_1000t_rx_status_not_ok;
22415779Sxy150489 } else {
22425779Sxy150489 /* Set values to "undefined" */
22435779Sxy150489 phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
22445779Sxy150489 phy->local_rx = e1000_1000t_rx_status_undefined;
22455779Sxy150489 phy->remote_rx = e1000_1000t_rx_status_undefined;
22465779Sxy150489 }
22475779Sxy150489
22485779Sxy150489 out:
22495779Sxy150489 return (ret_val);
22505779Sxy150489 }
22515779Sxy150489
22525779Sxy150489 /*
22535779Sxy150489 * e1000_get_phy_info_igp - Retrieve igp PHY information
22545779Sxy150489 * @hw: pointer to the HW structure
22555779Sxy150489 *
22565779Sxy150489 * Read PHY status to determine if link is up. If link is up, then
22575779Sxy150489 * set/determine 10base-T extended distance and polarity correction. Read
22585779Sxy150489 * PHY port status to determine MDI/MDIx and speed. Based on the speed,
22595779Sxy150489 * determine on the cable length, local and remote receiver.
22605779Sxy150489 */
22615779Sxy150489 s32
e1000_get_phy_info_igp(struct e1000_hw * hw)22625779Sxy150489 e1000_get_phy_info_igp(struct e1000_hw *hw)
22635779Sxy150489 {
22645779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
22655779Sxy150489 s32 ret_val;
22665779Sxy150489 u16 data;
22675779Sxy150489 bool link;
22685779Sxy150489
22695779Sxy150489 DEBUGFUNC("e1000_get_phy_info_igp");
22705779Sxy150489
22715779Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
22725779Sxy150489 if (ret_val)
22735779Sxy150489 goto out;
22745779Sxy150489
22755779Sxy150489 if (!link) {
22765779Sxy150489 DEBUGOUT("Phy info is only valid if link is up\n");
22775779Sxy150489 ret_val = -E1000_ERR_CONFIG;
22785779Sxy150489 goto out;
22795779Sxy150489 }
22805779Sxy150489
22818571SChenlu.Chen@Sun.COM phy->polarity_correction = true;
22825779Sxy150489
22835779Sxy150489 ret_val = e1000_check_polarity_igp(hw);
22845779Sxy150489 if (ret_val)
22855779Sxy150489 goto out;
22865779Sxy150489
22878571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
22885779Sxy150489 if (ret_val)
22895779Sxy150489 goto out;
22905779Sxy150489
22918571SChenlu.Chen@Sun.COM phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
22925779Sxy150489
22935779Sxy150489 if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
22945779Sxy150489 IGP01E1000_PSSR_SPEED_1000MBPS) {
229511155SJason.Xu@Sun.COM ret_val = phy->ops.get_cable_length(hw);
22965779Sxy150489 if (ret_val)
22975779Sxy150489 goto out;
22985779Sxy150489
22998571SChenlu.Chen@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
23005779Sxy150489 if (ret_val)
23015779Sxy150489 goto out;
23025779Sxy150489
23035779Sxy150489 phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
23045779Sxy150489 ? e1000_1000t_rx_status_ok
23055779Sxy150489 : e1000_1000t_rx_status_not_ok;
23065779Sxy150489
23075779Sxy150489 phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
23085779Sxy150489 ? e1000_1000t_rx_status_ok
23095779Sxy150489 : e1000_1000t_rx_status_not_ok;
23105779Sxy150489 } else {
23115779Sxy150489 phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
23125779Sxy150489 phy->local_rx = e1000_1000t_rx_status_undefined;
23135779Sxy150489 phy->remote_rx = e1000_1000t_rx_status_undefined;
23145779Sxy150489 }
23155779Sxy150489
23165779Sxy150489 out:
23175779Sxy150489 return (ret_val);
23185779Sxy150489 }
23195779Sxy150489
23205779Sxy150489 /*
23215779Sxy150489 * e1000_phy_sw_reset_generic - PHY software reset
23225779Sxy150489 * @hw: pointer to the HW structure
23235779Sxy150489 *
23245779Sxy150489 * Does a software reset of the PHY by reading the PHY control register and
23255779Sxy150489 * setting/write the control register reset bit to the PHY.
23265779Sxy150489 */
23275779Sxy150489 s32
e1000_phy_sw_reset_generic(struct e1000_hw * hw)23285779Sxy150489 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
23295779Sxy150489 {
23308571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
23315779Sxy150489 u16 phy_ctrl;
23325779Sxy150489
23335779Sxy150489 DEBUGFUNC("e1000_phy_sw_reset_generic");
23345779Sxy150489
23358571SChenlu.Chen@Sun.COM if (!(hw->phy.ops.read_reg))
23368571SChenlu.Chen@Sun.COM goto out;
23378571SChenlu.Chen@Sun.COM
23388571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
23395779Sxy150489 if (ret_val)
23405779Sxy150489 goto out;
23415779Sxy150489
23425779Sxy150489 phy_ctrl |= MII_CR_RESET;
23438571SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
23445779Sxy150489 if (ret_val)
23455779Sxy150489 goto out;
23465779Sxy150489
23475779Sxy150489 usec_delay(1);
23485779Sxy150489
23495779Sxy150489 out:
23505779Sxy150489 return (ret_val);
23515779Sxy150489 }
23525779Sxy150489
23535779Sxy150489 /*
23545779Sxy150489 * e1000_phy_hw_reset_generic - PHY hardware reset
23555779Sxy150489 * @hw: pointer to the HW structure
23565779Sxy150489 *
23575779Sxy150489 * Verify the reset block is not blocking us from resetting. Acquire
23585779Sxy150489 * semaphore (if necessary) and read/set/write the device control reset
23595779Sxy150489 * bit in the PHY. Wait the appropriate delay time for the device to
23608571SChenlu.Chen@Sun.COM * reset and release the semaphore (if necessary).
23615779Sxy150489 */
23625779Sxy150489 s32
e1000_phy_hw_reset_generic(struct e1000_hw * hw)23635779Sxy150489 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
23645779Sxy150489 {
23655779Sxy150489 struct e1000_phy_info *phy = &hw->phy;
23668571SChenlu.Chen@Sun.COM s32 ret_val = E1000_SUCCESS;
23675779Sxy150489 u32 ctrl;
23685779Sxy150489
23695779Sxy150489 DEBUGFUNC("e1000_phy_hw_reset_generic");
23705779Sxy150489
23718571SChenlu.Chen@Sun.COM ret_val = phy->ops.check_reset_block(hw);
23725779Sxy150489 if (ret_val) {
23735779Sxy150489 ret_val = E1000_SUCCESS;
23745779Sxy150489 goto out;
23755779Sxy150489 }
23765779Sxy150489
23778571SChenlu.Chen@Sun.COM ret_val = phy->ops.acquire(hw);
23785779Sxy150489 if (ret_val)
23795779Sxy150489 goto out;
23805779Sxy150489
23815779Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
23825779Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
23835779Sxy150489 E1000_WRITE_FLUSH(hw);
23845779Sxy150489
23855779Sxy150489 usec_delay(phy->reset_delay_us);
23865779Sxy150489
23875779Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
23885779Sxy150489 E1000_WRITE_FLUSH(hw);
23895779Sxy150489
23905779Sxy150489 usec_delay(150);
23915779Sxy150489
23928571SChenlu.Chen@Sun.COM phy->ops.release(hw);
23935779Sxy150489
23948571SChenlu.Chen@Sun.COM ret_val = phy->ops.get_cfg_done(hw);
23955779Sxy150489
23965779Sxy150489 out:
23975779Sxy150489 return (ret_val);
23985779Sxy150489 }
23995779Sxy150489
24005779Sxy150489 /*
24015779Sxy150489 * e1000_get_cfg_done_generic - Generic configuration done
24025779Sxy150489 * @hw: pointer to the HW structure
24035779Sxy150489 *
24045779Sxy150489 * Generic function to wait 10 milli-seconds for configuration to complete
24055779Sxy150489 * and return success.
24065779Sxy150489 */
24075779Sxy150489 s32
e1000_get_cfg_done_generic(struct e1000_hw * hw)24085779Sxy150489 e1000_get_cfg_done_generic(struct e1000_hw *hw)
24095779Sxy150489 {
24105779Sxy150489 DEBUGFUNC("e1000_get_cfg_done_generic");
24118571SChenlu.Chen@Sun.COM UNREFERENCED_1PARAMETER(hw);
24125779Sxy150489
24135779Sxy150489 msec_delay_irq(10);
24145779Sxy150489
24155779Sxy150489 return (E1000_SUCCESS);
24165779Sxy150489 }
24175779Sxy150489
24185779Sxy150489 /*
24195779Sxy150489 * e1000_phy_init_script_igp3 - Inits the IGP3 PHY
24205779Sxy150489 * @hw: pointer to the HW structure
24215779Sxy150489 *
24225779Sxy150489 * Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
24235779Sxy150489 */
24245779Sxy150489 s32
e1000_phy_init_script_igp3(struct e1000_hw * hw)24255779Sxy150489 e1000_phy_init_script_igp3(struct e1000_hw *hw)
24265779Sxy150489 {
24275779Sxy150489 DEBUGOUT("Running IGP 3 PHY init script\n");
24285779Sxy150489
24295779Sxy150489 /* PHY init IGP 3 */
24305779Sxy150489 /* Enable rise/fall, 10-mode work in class-A */
24318571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
24325779Sxy150489 /* Remove all caps from Replica path filter */
24338571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
24345779Sxy150489 /* Bias trimming for ADC, AFE and Driver (Default) */
24358571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
24365779Sxy150489 /* Increase Hybrid poly bias */
24378571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
24388571SChenlu.Chen@Sun.COM /* Add 4% to Tx amplitude in Gig mode */
24398571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
24405779Sxy150489 /* Disable trimming (TTT) */
24418571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
24425779Sxy150489 /* Poly DC correction to 94.6% + 2% for all channels */
24438571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
24445779Sxy150489 /* ABS DC correction to 95.9% */
24458571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
24465779Sxy150489 /* BG temp curve trim */
24478571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
24485779Sxy150489 /* Increasing ADC OPAMP stage 1 currents to max */
24498571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
24505779Sxy150489 /* Force 1000 ( required for enabling PHY regs configuration) */
24518571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
24525779Sxy150489 /* Set upd_freq to 6 */
24538571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
24545779Sxy150489 /* Disable NPDFE */
24558571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
24565779Sxy150489 /* Disable adaptive fixed FFE (Default) */
24578571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
24585779Sxy150489 /* Enable FFE hysteresis */
24598571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
24605779Sxy150489 /* Fixed FFE for short cable lengths */
24618571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
24625779Sxy150489 /* Fixed FFE for medium cable lengths */
24638571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
24645779Sxy150489 /* Fixed FFE for long cable lengths */
24658571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
24665779Sxy150489 /* Enable Adaptive Clip Threshold */
24678571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
24685779Sxy150489 /* AHT reset limit to 1 */
24698571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
24705779Sxy150489 /* Set AHT master delay to 127 msec */
24718571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
24725779Sxy150489 /* Set scan bits for AHT */
24738571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
24745779Sxy150489 /* Set AHT Preset bits */
24758571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
24765779Sxy150489 /* Change integ_factor of channel A to 3 */
24778571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
24785779Sxy150489 /* Change prop_factor of channels BCD to 8 */
24798571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
24805779Sxy150489 /* Change cg_icount + enable integbp for channels BCD */
24818571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
24825779Sxy150489 /*
24835779Sxy150489 * Change cg_icount + enable integbp + change prop_factor_master
24845779Sxy150489 * to 8 for channel A
24855779Sxy150489 */
24868571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
24875779Sxy150489 /* Disable AHT in Slave mode on channel A */
24888571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
24895779Sxy150489 /*
24905779Sxy150489 * Enable LPLU and disable AN to 1000 in non-D0a states,
24915779Sxy150489 * Enable SPD+B2B
24925779Sxy150489 */
24938571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
24945779Sxy150489 /* Enable restart AN on an1000_dis change */
24958571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
24965779Sxy150489 /* Enable wh_fifo read clock in 10/100 modes */
24978571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
24985779Sxy150489 /* Restart AN, Speed selection is 1000 */
24998571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
25005779Sxy150489
25015779Sxy150489 return (E1000_SUCCESS);
25025779Sxy150489 }
25035779Sxy150489
25045779Sxy150489 /*
25055779Sxy150489 * e1000_get_phy_type_from_id - Get PHY type from id
25065779Sxy150489 * @phy_id: phy_id read from the phy
25075779Sxy150489 *
25085779Sxy150489 * Returns the phy type from the id.
25095779Sxy150489 */
25108571SChenlu.Chen@Sun.COM enum e1000_phy_type
e1000_get_phy_type_from_id(u32 phy_id)25115779Sxy150489 e1000_get_phy_type_from_id(u32 phy_id)
25125779Sxy150489 {
25138571SChenlu.Chen@Sun.COM enum e1000_phy_type phy_type = e1000_phy_unknown;
25145779Sxy150489
25155779Sxy150489 switch (phy_id) {
25165779Sxy150489 case M88E1000_I_PHY_ID:
25175779Sxy150489 case M88E1000_E_PHY_ID:
25185779Sxy150489 case M88E1111_I_PHY_ID:
25195779Sxy150489 case M88E1011_I_PHY_ID:
25205779Sxy150489 phy_type = e1000_phy_m88;
25215779Sxy150489 break;
25225779Sxy150489 case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
25235779Sxy150489 phy_type = e1000_phy_igp_2;
25245779Sxy150489 break;
25255779Sxy150489 case GG82563_E_PHY_ID:
25265779Sxy150489 phy_type = e1000_phy_gg82563;
25275779Sxy150489 break;
25285779Sxy150489 case IGP03E1000_E_PHY_ID:
25295779Sxy150489 phy_type = e1000_phy_igp_3;
25305779Sxy150489 break;
25315779Sxy150489 case IFE_E_PHY_ID:
25325779Sxy150489 case IFE_PLUS_E_PHY_ID:
25335779Sxy150489 case IFE_C_E_PHY_ID:
25345779Sxy150489 phy_type = e1000_phy_ife;
25355779Sxy150489 break;
253611155SJason.Xu@Sun.COM case I82580_I_PHY_ID:
253711155SJason.Xu@Sun.COM phy_type = e1000_phy_82580;
253811155SJason.Xu@Sun.COM break;
25395779Sxy150489 default:
25405779Sxy150489 phy_type = e1000_phy_unknown;
25415779Sxy150489 break;
25425779Sxy150489 }
25435779Sxy150489 return (phy_type);
25445779Sxy150489 }
25455779Sxy150489
25465779Sxy150489 /*
254710319SJason.Xu@Sun.COM * e1000_determine_phy_address - Determines PHY address.
254810319SJason.Xu@Sun.COM * @hw: pointer to the HW structure
254910319SJason.Xu@Sun.COM *
255010319SJason.Xu@Sun.COM * This uses a trial and error method to loop through possible PHY
255110319SJason.Xu@Sun.COM * addresses. It tests each by reading the PHY ID registers and
255210319SJason.Xu@Sun.COM * checking for a match.
255310319SJason.Xu@Sun.COM */
255410319SJason.Xu@Sun.COM s32
e1000_determine_phy_address(struct e1000_hw * hw)255510319SJason.Xu@Sun.COM e1000_determine_phy_address(struct e1000_hw *hw)
255610319SJason.Xu@Sun.COM {
255710319SJason.Xu@Sun.COM s32 ret_val = -E1000_ERR_PHY_TYPE;
255810319SJason.Xu@Sun.COM u32 phy_addr = 0;
255910319SJason.Xu@Sun.COM u32 i;
256010319SJason.Xu@Sun.COM enum e1000_phy_type phy_type = e1000_phy_unknown;
256110319SJason.Xu@Sun.COM
256210319SJason.Xu@Sun.COM hw->phy.id = phy_type;
256310319SJason.Xu@Sun.COM
256410319SJason.Xu@Sun.COM for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
256510319SJason.Xu@Sun.COM hw->phy.addr = phy_addr;
256610319SJason.Xu@Sun.COM i = 0;
256710319SJason.Xu@Sun.COM
256810319SJason.Xu@Sun.COM do {
256911155SJason.Xu@Sun.COM (void) e1000_get_phy_id(hw);
257010319SJason.Xu@Sun.COM phy_type = e1000_get_phy_type_from_id(hw->phy.id);
257110319SJason.Xu@Sun.COM
257210319SJason.Xu@Sun.COM /*
257310319SJason.Xu@Sun.COM * If phy_type is valid, break - we found our
257410319SJason.Xu@Sun.COM * PHY address
257510319SJason.Xu@Sun.COM */
257610319SJason.Xu@Sun.COM if (phy_type != e1000_phy_unknown) {
257710319SJason.Xu@Sun.COM ret_val = E1000_SUCCESS;
257810319SJason.Xu@Sun.COM goto out;
257910319SJason.Xu@Sun.COM }
258010319SJason.Xu@Sun.COM msec_delay(1);
258110319SJason.Xu@Sun.COM i++;
258210319SJason.Xu@Sun.COM } while (i < 10);
258310319SJason.Xu@Sun.COM }
258410319SJason.Xu@Sun.COM
258510319SJason.Xu@Sun.COM out:
258610319SJason.Xu@Sun.COM return (ret_val);
258710319SJason.Xu@Sun.COM }
258810319SJason.Xu@Sun.COM /*
25895779Sxy150489 * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
25905779Sxy150489 * @hw: pointer to the HW structure
25915779Sxy150489 *
25925779Sxy150489 * In the case of a PHY power down to save power, or to turn off link during a
25935779Sxy150489 * driver unload, or wake on lan is not enabled, restore the link to previous
25945779Sxy150489 * settings.
25955779Sxy150489 */
25965779Sxy150489 void
e1000_power_up_phy_copper(struct e1000_hw * hw)25975779Sxy150489 e1000_power_up_phy_copper(struct e1000_hw *hw)
25985779Sxy150489 {
25995779Sxy150489 u16 mii_reg = 0;
26005779Sxy150489
26015779Sxy150489 /* The PHY will retain its settings across a power down/up cycle */
26028571SChenlu.Chen@Sun.COM (void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
26035779Sxy150489 mii_reg &= ~MII_CR_POWER_DOWN;
26048571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
26055779Sxy150489 }
26065779Sxy150489
26075779Sxy150489 /*
26085779Sxy150489 * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
26095779Sxy150489 * @hw: pointer to the HW structure
26105779Sxy150489 *
26115779Sxy150489 * In the case of a PHY power down to save power, or to turn off link during a
26125779Sxy150489 * driver unload, or wake on lan is not enabled, restore the link to previous
26135779Sxy150489 * settings.
26145779Sxy150489 */
26155779Sxy150489 void
e1000_power_down_phy_copper(struct e1000_hw * hw)26165779Sxy150489 e1000_power_down_phy_copper(struct e1000_hw *hw)
26175779Sxy150489 {
26185779Sxy150489 u16 mii_reg = 0;
26195779Sxy150489
26205779Sxy150489 /* The PHY will retain its settings across a power down/up cycle */
26218571SChenlu.Chen@Sun.COM (void) hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
26225779Sxy150489 mii_reg |= MII_CR_POWER_DOWN;
26238571SChenlu.Chen@Sun.COM (void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
26245779Sxy150489 msec_delay(1);
26255779Sxy150489 }
262611155SJason.Xu@Sun.COM
262711155SJason.Xu@Sun.COM /*
262811155SJason.Xu@Sun.COM * e1000_check_polarity_82577 - Checks the polarity.
262911155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
263011155SJason.Xu@Sun.COM *
263111155SJason.Xu@Sun.COM * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
263211155SJason.Xu@Sun.COM *
263311155SJason.Xu@Sun.COM * Polarity is determined based on the PHY specific status register.
263411155SJason.Xu@Sun.COM */
263511155SJason.Xu@Sun.COM s32
e1000_check_polarity_82577(struct e1000_hw * hw)263611155SJason.Xu@Sun.COM e1000_check_polarity_82577(struct e1000_hw *hw)
263711155SJason.Xu@Sun.COM {
263811155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
263911155SJason.Xu@Sun.COM s32 ret_val;
264011155SJason.Xu@Sun.COM u16 data;
264111155SJason.Xu@Sun.COM
264211155SJason.Xu@Sun.COM DEBUGFUNC("e1000_check_polarity_82577");
264311155SJason.Xu@Sun.COM
264411155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
264511155SJason.Xu@Sun.COM
264611155SJason.Xu@Sun.COM if (!ret_val)
264711155SJason.Xu@Sun.COM phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
264811155SJason.Xu@Sun.COM ? e1000_rev_polarity_reversed
264911155SJason.Xu@Sun.COM : e1000_rev_polarity_normal;
265011155SJason.Xu@Sun.COM
265111155SJason.Xu@Sun.COM return (ret_val);
265211155SJason.Xu@Sun.COM }
265311155SJason.Xu@Sun.COM
265411155SJason.Xu@Sun.COM /*
265511155SJason.Xu@Sun.COM * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
265611155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
265711155SJason.Xu@Sun.COM *
265811155SJason.Xu@Sun.COM * Calls the PHY setup function to force speed and duplex. Clears the
265911155SJason.Xu@Sun.COM * auto-crossover to force MDI manually. Waits for link and returns
266011155SJason.Xu@Sun.COM * successful if link up is successful, else -E1000_ERR_PHY (-2).
266111155SJason.Xu@Sun.COM */
266211155SJason.Xu@Sun.COM s32
e1000_phy_force_speed_duplex_82577(struct e1000_hw * hw)266311155SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
266411155SJason.Xu@Sun.COM {
266511155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
266611155SJason.Xu@Sun.COM s32 ret_val;
266711155SJason.Xu@Sun.COM u16 phy_data;
266811155SJason.Xu@Sun.COM bool link;
266911155SJason.Xu@Sun.COM
267011155SJason.Xu@Sun.COM DEBUGFUNC("e1000_phy_force_speed_duplex_82577");
267111155SJason.Xu@Sun.COM
267211155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
267311155SJason.Xu@Sun.COM if (ret_val)
267411155SJason.Xu@Sun.COM goto out;
267511155SJason.Xu@Sun.COM
267611155SJason.Xu@Sun.COM e1000_phy_force_speed_duplex_setup(hw, &phy_data);
267711155SJason.Xu@Sun.COM
267811155SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
267911155SJason.Xu@Sun.COM if (ret_val)
268011155SJason.Xu@Sun.COM goto out;
268111155SJason.Xu@Sun.COM
268211155SJason.Xu@Sun.COM /*
268311155SJason.Xu@Sun.COM * Clear Auto-Crossover to force MDI manually. 82577 requires MDI
268411155SJason.Xu@Sun.COM * forced whenever speed and duplex are forced.
268511155SJason.Xu@Sun.COM */
268611155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data);
268711155SJason.Xu@Sun.COM if (ret_val)
268811155SJason.Xu@Sun.COM goto out;
268911155SJason.Xu@Sun.COM
269011155SJason.Xu@Sun.COM phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
269111155SJason.Xu@Sun.COM phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
269211155SJason.Xu@Sun.COM
269311155SJason.Xu@Sun.COM ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data);
269411155SJason.Xu@Sun.COM if (ret_val)
269511155SJason.Xu@Sun.COM goto out;
269611155SJason.Xu@Sun.COM
269711155SJason.Xu@Sun.COM DEBUGOUT1("I82577_PHY_CTRL_2: %X\n", phy_data);
269811155SJason.Xu@Sun.COM
269911155SJason.Xu@Sun.COM usec_delay(1);
270011155SJason.Xu@Sun.COM
270111155SJason.Xu@Sun.COM if (phy->autoneg_wait_to_complete) {
270211155SJason.Xu@Sun.COM DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n");
270311155SJason.Xu@Sun.COM
270411155SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw,
270511155SJason.Xu@Sun.COM PHY_FORCE_LIMIT,
270611155SJason.Xu@Sun.COM 100000,
270711155SJason.Xu@Sun.COM &link);
270811155SJason.Xu@Sun.COM if (ret_val)
270911155SJason.Xu@Sun.COM goto out;
271011155SJason.Xu@Sun.COM
271111155SJason.Xu@Sun.COM if (!link)
271211155SJason.Xu@Sun.COM DEBUGOUT("Link taking longer than expected.\n");
271311155SJason.Xu@Sun.COM
271411155SJason.Xu@Sun.COM /* Try once more */
271511155SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw,
271611155SJason.Xu@Sun.COM PHY_FORCE_LIMIT,
271711155SJason.Xu@Sun.COM 100000,
271811155SJason.Xu@Sun.COM &link);
271911155SJason.Xu@Sun.COM if (ret_val)
272011155SJason.Xu@Sun.COM goto out;
272111155SJason.Xu@Sun.COM }
272211155SJason.Xu@Sun.COM
272311155SJason.Xu@Sun.COM out:
272411155SJason.Xu@Sun.COM return (ret_val);
272511155SJason.Xu@Sun.COM }
272611155SJason.Xu@Sun.COM
272711155SJason.Xu@Sun.COM /*
272811155SJason.Xu@Sun.COM * e1000_get_phy_info_82577 - Retrieve I82577 PHY information
272911155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
273011155SJason.Xu@Sun.COM *
273111155SJason.Xu@Sun.COM * Read PHY status to determine if link is up. If link is up, then
273211155SJason.Xu@Sun.COM * set/determine 10base-T extended distance and polarity correction. Read
273311155SJason.Xu@Sun.COM * PHY port status to determine MDI/MDIx and speed. Based on the speed,
273411155SJason.Xu@Sun.COM * determine on the cable length, local and remote receiver.
273511155SJason.Xu@Sun.COM */
273611155SJason.Xu@Sun.COM s32
e1000_get_phy_info_82577(struct e1000_hw * hw)273711155SJason.Xu@Sun.COM e1000_get_phy_info_82577(struct e1000_hw *hw)
273811155SJason.Xu@Sun.COM {
273911155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
274011155SJason.Xu@Sun.COM s32 ret_val;
274111155SJason.Xu@Sun.COM u16 data;
274211155SJason.Xu@Sun.COM bool link;
274311155SJason.Xu@Sun.COM
274411155SJason.Xu@Sun.COM DEBUGFUNC("e1000_get_phy_info_82577");
274511155SJason.Xu@Sun.COM
274611155SJason.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
274711155SJason.Xu@Sun.COM if (ret_val)
274811155SJason.Xu@Sun.COM goto out;
274911155SJason.Xu@Sun.COM
275011155SJason.Xu@Sun.COM if (!link) {
275111155SJason.Xu@Sun.COM DEBUGOUT("Phy info is only valid if link is up\n");
275211155SJason.Xu@Sun.COM ret_val = -E1000_ERR_CONFIG;
275311155SJason.Xu@Sun.COM goto out;
275411155SJason.Xu@Sun.COM }
275511155SJason.Xu@Sun.COM
275611155SJason.Xu@Sun.COM phy->polarity_correction = true;
275711155SJason.Xu@Sun.COM
275811155SJason.Xu@Sun.COM ret_val = e1000_check_polarity_82577(hw);
275911155SJason.Xu@Sun.COM if (ret_val)
276011155SJason.Xu@Sun.COM goto out;
276111155SJason.Xu@Sun.COM
276211155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
276311155SJason.Xu@Sun.COM if (ret_val)
276411155SJason.Xu@Sun.COM goto out;
276511155SJason.Xu@Sun.COM
276611155SJason.Xu@Sun.COM phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
276711155SJason.Xu@Sun.COM
276811155SJason.Xu@Sun.COM if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
276911155SJason.Xu@Sun.COM I82577_PHY_STATUS2_SPEED_1000MBPS) {
277011155SJason.Xu@Sun.COM ret_val = hw->phy.ops.get_cable_length(hw);
277111155SJason.Xu@Sun.COM if (ret_val)
277211155SJason.Xu@Sun.COM goto out;
277311155SJason.Xu@Sun.COM
277411155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
277511155SJason.Xu@Sun.COM if (ret_val)
277611155SJason.Xu@Sun.COM goto out;
277711155SJason.Xu@Sun.COM
277811155SJason.Xu@Sun.COM phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
277911155SJason.Xu@Sun.COM ? e1000_1000t_rx_status_ok
278011155SJason.Xu@Sun.COM : e1000_1000t_rx_status_not_ok;
278111155SJason.Xu@Sun.COM
278211155SJason.Xu@Sun.COM phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
278311155SJason.Xu@Sun.COM ? e1000_1000t_rx_status_ok
278411155SJason.Xu@Sun.COM : e1000_1000t_rx_status_not_ok;
278511155SJason.Xu@Sun.COM } else {
278611155SJason.Xu@Sun.COM phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
278711155SJason.Xu@Sun.COM phy->local_rx = e1000_1000t_rx_status_undefined;
278811155SJason.Xu@Sun.COM phy->remote_rx = e1000_1000t_rx_status_undefined;
278911155SJason.Xu@Sun.COM }
279011155SJason.Xu@Sun.COM
279111155SJason.Xu@Sun.COM out:
279211155SJason.Xu@Sun.COM return (ret_val);
279311155SJason.Xu@Sun.COM }
279411155SJason.Xu@Sun.COM
279511155SJason.Xu@Sun.COM /*
279611155SJason.Xu@Sun.COM * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
279711155SJason.Xu@Sun.COM * @hw: pointer to the HW structure
279811155SJason.Xu@Sun.COM *
279911155SJason.Xu@Sun.COM * Reads the diagnostic status register and verifies result is valid before
280011155SJason.Xu@Sun.COM * placing it in the phy_cable_length field.
280111155SJason.Xu@Sun.COM */
280211155SJason.Xu@Sun.COM s32
e1000_get_cable_length_82577(struct e1000_hw * hw)280311155SJason.Xu@Sun.COM e1000_get_cable_length_82577(struct e1000_hw *hw)
280411155SJason.Xu@Sun.COM {
280511155SJason.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
280611155SJason.Xu@Sun.COM s32 ret_val;
280711155SJason.Xu@Sun.COM u16 phy_data, length;
280811155SJason.Xu@Sun.COM
280911155SJason.Xu@Sun.COM DEBUGFUNC("e1000_get_cable_length_82577");
281011155SJason.Xu@Sun.COM
281111155SJason.Xu@Sun.COM ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
281211155SJason.Xu@Sun.COM if (ret_val)
281311155SJason.Xu@Sun.COM goto out;
281411155SJason.Xu@Sun.COM
281511155SJason.Xu@Sun.COM length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
281611155SJason.Xu@Sun.COM I82577_DSTATUS_CABLE_LENGTH_SHIFT;
281711155SJason.Xu@Sun.COM
281811155SJason.Xu@Sun.COM if (length == E1000_CABLE_LENGTH_UNDEFINED)
281911155SJason.Xu@Sun.COM ret_val = -E1000_ERR_PHY;
282011155SJason.Xu@Sun.COM
282111155SJason.Xu@Sun.COM phy->cable_length = length;
282211155SJason.Xu@Sun.COM
282311155SJason.Xu@Sun.COM out:
282411155SJason.Xu@Sun.COM
282511155SJason.Xu@Sun.COM return (ret_val);
282611155SJason.Xu@Sun.COM }
2827