14919Sxy150489 /* 24919Sxy150489 * This file is provided under a CDDLv1 license. When using or 34919Sxy150489 * redistributing this file, you may do so under this license. 44919Sxy150489 * In redistributing this file this license must be included 54919Sxy150489 * and no other modification of this header file is permitted. 64919Sxy150489 * 74919Sxy150489 * CDDL LICENSE SUMMARY 84919Sxy150489 * 9*8479SChenlu.Chen@Sun.COM * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved. 104919Sxy150489 * 114919Sxy150489 * The contents of this file are subject to the terms of Version 124919Sxy150489 * 1.0 of the Common Development and Distribution License (the "License"). 134919Sxy150489 * 144919Sxy150489 * You should have received a copy of the License with this software. 154919Sxy150489 * You can obtain a copy of the License at 166735Scc210113 * http://www.opensolaris.org/os/licensing. 174919Sxy150489 * See the License for the specific language governing permissions 184919Sxy150489 * and limitations under the License. 194919Sxy150489 */ 204919Sxy150489 214919Sxy150489 /* 22*8479SChenlu.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 234919Sxy150489 * Use is subject to license terms of the CDDLv1. 244919Sxy150489 */ 254919Sxy150489 264919Sxy150489 /* 27*8479SChenlu.Chen@Sun.COM * IntelVersion: 1.54 sol_anvik_patch 284919Sxy150489 */ 296735Scc210113 304919Sxy150489 /* 31*8479SChenlu.Chen@Sun.COM * 82540EM Gigabit Ethernet Controller 32*8479SChenlu.Chen@Sun.COM * 82540EP Gigabit Ethernet Controller 33*8479SChenlu.Chen@Sun.COM * 82545EM Gigabit Ethernet Controller (Copper) 34*8479SChenlu.Chen@Sun.COM * 82545EM Gigabit Ethernet Controller (Fiber) 35*8479SChenlu.Chen@Sun.COM * 82545GM Gigabit Ethernet Controller 36*8479SChenlu.Chen@Sun.COM * 82546EB Gigabit Ethernet Controller (Copper) 37*8479SChenlu.Chen@Sun.COM * 82546EB Gigabit Ethernet Controller (Fiber) 38*8479SChenlu.Chen@Sun.COM * 82546GB Gigabit Ethernet Controller 394919Sxy150489 */ 404919Sxy150489 414919Sxy150489 #include "e1000_api.h" 424919Sxy150489 434919Sxy150489 static s32 e1000_init_phy_params_82540(struct e1000_hw *hw); 444919Sxy150489 static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw); 454919Sxy150489 static s32 e1000_init_mac_params_82540(struct e1000_hw *hw); 464919Sxy150489 static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw); 474919Sxy150489 static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw); 484919Sxy150489 static s32 e1000_init_hw_82540(struct e1000_hw *hw); 494919Sxy150489 static s32 e1000_reset_hw_82540(struct e1000_hw *hw); 504919Sxy150489 static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw); 514919Sxy150489 static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw); 524919Sxy150489 static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw); 534919Sxy150489 static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw); 546735Scc210113 static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw); 554919Sxy150489 564919Sxy150489 /* 574919Sxy150489 * e1000_init_phy_params_82540 - Init PHY func ptrs. 584919Sxy150489 * @hw: pointer to the HW structure 594919Sxy150489 */ 604919Sxy150489 static s32 614919Sxy150489 e1000_init_phy_params_82540(struct e1000_hw *hw) 624919Sxy150489 { 634919Sxy150489 struct e1000_phy_info *phy = &hw->phy; 644919Sxy150489 s32 ret_val = E1000_SUCCESS; 654919Sxy150489 664919Sxy150489 phy->addr = 1; 674919Sxy150489 phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 684919Sxy150489 phy->reset_delay_us = 10000; 694919Sxy150489 phy->type = e1000_phy_m88; 704919Sxy150489 714919Sxy150489 /* Function Pointers */ 726735Scc210113 phy->ops.check_polarity = e1000_check_polarity_m88; 736735Scc210113 phy->ops.commit = e1000_phy_sw_reset_generic; 746735Scc210113 phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 756735Scc210113 phy->ops.get_cable_length = e1000_get_cable_length_m88; 766735Scc210113 phy->ops.get_cfg_done = e1000_get_cfg_done_generic; 776735Scc210113 phy->ops.read_reg = e1000_read_phy_reg_m88; 786735Scc210113 phy->ops.reset = e1000_phy_hw_reset_generic; 796735Scc210113 phy->ops.write_reg = e1000_write_phy_reg_m88; 806735Scc210113 phy->ops.get_info = e1000_get_phy_info_m88; 816735Scc210113 phy->ops.power_up = e1000_power_up_phy_copper; 826735Scc210113 phy->ops.power_down = e1000_power_down_phy_copper_82540; 834919Sxy150489 844919Sxy150489 ret_val = e1000_get_phy_id(hw); 854919Sxy150489 if (ret_val) 864919Sxy150489 goto out; 874919Sxy150489 884919Sxy150489 /* Verify phy id */ 894919Sxy150489 switch (hw->mac.type) { 904919Sxy150489 case e1000_82540: 914919Sxy150489 case e1000_82545: 924919Sxy150489 case e1000_82545_rev_3: 934919Sxy150489 case e1000_82546: 944919Sxy150489 case e1000_82546_rev_3: 954919Sxy150489 if (phy->id == M88E1011_I_PHY_ID) 964919Sxy150489 break; 974919Sxy150489 /* Fall Through */ 984919Sxy150489 default: 994919Sxy150489 ret_val = -E1000_ERR_PHY; 1004919Sxy150489 goto out; 1014919Sxy150489 } 1024919Sxy150489 1034919Sxy150489 out: 1044919Sxy150489 return (ret_val); 1054919Sxy150489 } 1064919Sxy150489 1074919Sxy150489 /* 1084919Sxy150489 * e1000_init_nvm_params_82540 - Init NVM func ptrs. 1094919Sxy150489 * @hw: pointer to the HW structure 1104919Sxy150489 */ 1114919Sxy150489 static s32 1124919Sxy150489 e1000_init_nvm_params_82540(struct e1000_hw *hw) 1134919Sxy150489 { 1144919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm; 1154919Sxy150489 u32 eecd = E1000_READ_REG(hw, E1000_EECD); 1164919Sxy150489 1174919Sxy150489 DEBUGFUNC("e1000_init_nvm_params_82540"); 1184919Sxy150489 1194919Sxy150489 nvm->type = e1000_nvm_eeprom_microwire; 1204919Sxy150489 nvm->delay_usec = 50; 1214919Sxy150489 nvm->opcode_bits = 3; 1224919Sxy150489 switch (nvm->override) { 1234919Sxy150489 case e1000_nvm_override_microwire_large: 1244919Sxy150489 nvm->address_bits = 8; 1254919Sxy150489 nvm->word_size = 256; 1264919Sxy150489 break; 1274919Sxy150489 case e1000_nvm_override_microwire_small: 1284919Sxy150489 nvm->address_bits = 6; 1294919Sxy150489 nvm->word_size = 64; 1304919Sxy150489 break; 1314919Sxy150489 default: 1324919Sxy150489 nvm->address_bits = eecd & E1000_EECD_SIZE ? 8 : 6; 1334919Sxy150489 nvm->word_size = eecd & E1000_EECD_SIZE ? 256 : 64; 1344919Sxy150489 break; 1354919Sxy150489 } 1364919Sxy150489 1374919Sxy150489 /* Function Pointers */ 1386735Scc210113 nvm->ops.acquire = e1000_acquire_nvm_generic; 1396735Scc210113 nvm->ops.read = e1000_read_nvm_microwire; 1406735Scc210113 nvm->ops.release = e1000_release_nvm_generic; 1416735Scc210113 nvm->ops.update = e1000_update_nvm_checksum_generic; 1426735Scc210113 nvm->ops.valid_led_default = e1000_valid_led_default_generic; 1436735Scc210113 nvm->ops.validate = e1000_validate_nvm_checksum_generic; 1446735Scc210113 nvm->ops.write = e1000_write_nvm_microwire; 1454919Sxy150489 1464919Sxy150489 return (E1000_SUCCESS); 1474919Sxy150489 } 1484919Sxy150489 1494919Sxy150489 /* 1504919Sxy150489 * e1000_init_mac_params_82540 - Init MAC func ptrs. 1514919Sxy150489 * @hw: pointer to the HW structure 1524919Sxy150489 */ 1534919Sxy150489 static s32 1544919Sxy150489 e1000_init_mac_params_82540(struct e1000_hw *hw) 1554919Sxy150489 { 1564919Sxy150489 struct e1000_mac_info *mac = &hw->mac; 1574919Sxy150489 s32 ret_val = E1000_SUCCESS; 1584919Sxy150489 1594919Sxy150489 DEBUGFUNC("e1000_init_mac_params_82540"); 1604919Sxy150489 1614919Sxy150489 /* Set media type */ 1624919Sxy150489 switch (hw->device_id) { 1634919Sxy150489 case E1000_DEV_ID_82545EM_FIBER: 1644919Sxy150489 case E1000_DEV_ID_82545GM_FIBER: 1654919Sxy150489 case E1000_DEV_ID_82546EB_FIBER: 1664919Sxy150489 case E1000_DEV_ID_82546GB_FIBER: 1676735Scc210113 hw->phy.media_type = e1000_media_type_fiber; 1684919Sxy150489 break; 1694919Sxy150489 case E1000_DEV_ID_82545GM_SERDES: 1704919Sxy150489 case E1000_DEV_ID_82546GB_SERDES: 1716735Scc210113 hw->phy.media_type = e1000_media_type_internal_serdes; 1724919Sxy150489 break; 1734919Sxy150489 default: 1746735Scc210113 hw->phy.media_type = e1000_media_type_copper; 1754919Sxy150489 break; 1764919Sxy150489 } 1774919Sxy150489 1784919Sxy150489 /* Set mta register count */ 1794919Sxy150489 mac->mta_reg_count = 128; 1804919Sxy150489 /* Set rar entry count */ 1814919Sxy150489 mac->rar_entry_count = E1000_RAR_ENTRIES; 1824919Sxy150489 1834919Sxy150489 /* Function pointers */ 1844919Sxy150489 1854919Sxy150489 /* bus type/speed/width */ 1866735Scc210113 mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; 1874919Sxy150489 /* reset */ 1886735Scc210113 mac->ops.reset_hw = e1000_reset_hw_82540; 1894919Sxy150489 /* hw initialization */ 1906735Scc210113 mac->ops.init_hw = e1000_init_hw_82540; 1914919Sxy150489 /* link setup */ 1926735Scc210113 mac->ops.setup_link = e1000_setup_link_generic; 1934919Sxy150489 /* physical interface setup */ 1946735Scc210113 mac->ops.setup_physical_interface = 1956735Scc210113 (hw->phy.media_type == e1000_media_type_copper) 1964919Sxy150489 ? e1000_setup_copper_link_82540 1974919Sxy150489 : e1000_setup_fiber_serdes_link_82540; 1984919Sxy150489 /* check for link */ 1996735Scc210113 switch (hw->phy.media_type) { 2004919Sxy150489 case e1000_media_type_copper: 2016735Scc210113 mac->ops.check_for_link = e1000_check_for_copper_link_generic; 2024919Sxy150489 break; 2034919Sxy150489 case e1000_media_type_fiber: 2046735Scc210113 mac->ops.check_for_link = e1000_check_for_fiber_link_generic; 2054919Sxy150489 break; 2064919Sxy150489 case e1000_media_type_internal_serdes: 2076735Scc210113 mac->ops.check_for_link = e1000_check_for_serdes_link_generic; 2084919Sxy150489 break; 2094919Sxy150489 default: 2104919Sxy150489 ret_val = -E1000_ERR_CONFIG; 2114919Sxy150489 goto out; 2124919Sxy150489 } 2134919Sxy150489 /* link info */ 2146735Scc210113 mac->ops.get_link_up_info = 2156735Scc210113 (hw->phy.media_type == e1000_media_type_copper) 2164919Sxy150489 ? e1000_get_speed_and_duplex_copper_generic 2174919Sxy150489 : e1000_get_speed_and_duplex_fiber_serdes_generic; 2184919Sxy150489 /* multicast address update */ 2196735Scc210113 mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; 2204919Sxy150489 /* writing VFTA */ 2216735Scc210113 mac->ops.write_vfta = e1000_write_vfta_generic; 2224919Sxy150489 /* clearing VFTA */ 2236735Scc210113 mac->ops.clear_vfta = e1000_clear_vfta_generic; 2244919Sxy150489 /* setting MTA */ 2256735Scc210113 mac->ops.mta_set = e1000_mta_set_generic; 2264919Sxy150489 /* setup LED */ 2276735Scc210113 mac->ops.setup_led = e1000_setup_led_generic; 2284919Sxy150489 /* cleanup LED */ 2296735Scc210113 mac->ops.cleanup_led = e1000_cleanup_led_generic; 2304919Sxy150489 /* turn on/off LED */ 2316735Scc210113 mac->ops.led_on = e1000_led_on_generic; 2326735Scc210113 mac->ops.led_off = e1000_led_off_generic; 2334919Sxy150489 /* clear hardware counters */ 2346735Scc210113 mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82540; 2354919Sxy150489 2364919Sxy150489 out: 2374919Sxy150489 return (ret_val); 2384919Sxy150489 } 2394919Sxy150489 2404919Sxy150489 /* 2414919Sxy150489 * e1000_init_function_pointers_82540 - Init func ptrs. 2424919Sxy150489 * @hw: pointer to the HW structure 2434919Sxy150489 * 244*8479SChenlu.Chen@Sun.COM * Called to initialize all function pointers and parameters. 2454919Sxy150489 */ 2464919Sxy150489 void 2474919Sxy150489 e1000_init_function_pointers_82540(struct e1000_hw *hw) 2484919Sxy150489 { 2494919Sxy150489 DEBUGFUNC("e1000_init_function_pointers_82540"); 2504919Sxy150489 2516735Scc210113 hw->mac.ops.init_params = e1000_init_mac_params_82540; 2526735Scc210113 hw->nvm.ops.init_params = e1000_init_nvm_params_82540; 2536735Scc210113 hw->phy.ops.init_params = e1000_init_phy_params_82540; 2544919Sxy150489 } 2554919Sxy150489 2564919Sxy150489 /* 2576735Scc210113 * e1000_reset_hw_82540 - Reset hardware 2586735Scc210113 * @hw: pointer to the HW structure 2594919Sxy150489 * 260*8479SChenlu.Chen@Sun.COM * This resets the hardware into a known state. 2614919Sxy150489 */ 2624919Sxy150489 static s32 2634919Sxy150489 e1000_reset_hw_82540(struct e1000_hw *hw) 2644919Sxy150489 { 2657426SChenliang.Xu@Sun.COM u32 ctrl, manc; 2664919Sxy150489 s32 ret_val = E1000_SUCCESS; 2674919Sxy150489 2684919Sxy150489 DEBUGFUNC("e1000_reset_hw_82540"); 2694919Sxy150489 2704919Sxy150489 DEBUGOUT("Masking off all interrupts\n"); 2714919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); 2724919Sxy150489 2734919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0); 2744919Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); 2754919Sxy150489 E1000_WRITE_FLUSH(hw); 2764919Sxy150489 2774919Sxy150489 /* 2784919Sxy150489 * Delay to allow any outstanding PCI transactions to complete 2794919Sxy150489 * before resetting the device. 2804919Sxy150489 */ 2814919Sxy150489 msec_delay(10); 2824919Sxy150489 2834919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 2844919Sxy150489 2854919Sxy150489 DEBUGOUT("Issuing a global reset to 82540/82545/82546 MAC\n"); 2864919Sxy150489 switch (hw->mac.type) { 2874919Sxy150489 case e1000_82545_rev_3: 2884919Sxy150489 case e1000_82546_rev_3: 2894919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_DUP, ctrl | E1000_CTRL_RST); 2904919Sxy150489 break; 2914919Sxy150489 default: 2924919Sxy150489 /* 2934919Sxy150489 * These controllers can't ack the 64-bit write when 2944919Sxy150489 * issuing the reset, so we use IO-mapping as a 2954919Sxy150489 * workaround to issue the reset. 2964919Sxy150489 */ 2974919Sxy150489 E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); 2984919Sxy150489 break; 2994919Sxy150489 } 3004919Sxy150489 3014919Sxy150489 /* Wait for EEPROM reload */ 3024919Sxy150489 msec_delay(5); 3034919Sxy150489 3044919Sxy150489 /* Disable HW ARPs on ASF enabled adapters */ 3054919Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC); 3064919Sxy150489 manc &= ~E1000_MANC_ARP_EN; 3074919Sxy150489 E1000_WRITE_REG(hw, E1000_MANC, manc); 3084919Sxy150489 3094919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 3107426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ICR); 3114919Sxy150489 3124919Sxy150489 return (ret_val); 3134919Sxy150489 } 3144919Sxy150489 3154919Sxy150489 /* 3166735Scc210113 * e1000_init_hw_82540 - Initialize hardware 3176735Scc210113 * @hw: pointer to the HW structure 3184919Sxy150489 * 319*8479SChenlu.Chen@Sun.COM * This inits the hardware readying it for operation. 3204919Sxy150489 */ 3214919Sxy150489 static s32 3224919Sxy150489 e1000_init_hw_82540(struct e1000_hw *hw) 3234919Sxy150489 { 3244919Sxy150489 struct e1000_mac_info *mac = &hw->mac; 3254919Sxy150489 u32 txdctl, ctrl_ext; 3264919Sxy150489 s32 ret_val = E1000_SUCCESS; 3274919Sxy150489 u16 i; 3284919Sxy150489 3294919Sxy150489 DEBUGFUNC("e1000_init_hw_82540"); 3304919Sxy150489 3314919Sxy150489 /* Initialize identification LED */ 3324919Sxy150489 ret_val = e1000_id_led_init_generic(hw); 3334919Sxy150489 if (ret_val) { 3344919Sxy150489 DEBUGOUT("Error initializing identification LED\n"); 3356735Scc210113 /* This is not fatal and we should not stop init due to this */ 3364919Sxy150489 } 3374919Sxy150489 3384919Sxy150489 /* Disabling VLAN filtering */ 3394919Sxy150489 DEBUGOUT("Initializing the IEEE VLAN\n"); 3404919Sxy150489 if (mac->type < e1000_82545_rev_3) 3414919Sxy150489 E1000_WRITE_REG(hw, E1000_VET, 0); 3424919Sxy150489 3436735Scc210113 mac->ops.clear_vfta(hw); 3444919Sxy150489 3454919Sxy150489 /* Setup the receive address. */ 3464919Sxy150489 e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); 3474919Sxy150489 3484919Sxy150489 /* Zero out the Multicast HASH table */ 3494919Sxy150489 DEBUGOUT("Zeroing the MTA\n"); 3504919Sxy150489 for (i = 0; i < mac->mta_reg_count; i++) { 3514919Sxy150489 E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 3524919Sxy150489 /* 3534919Sxy150489 * Avoid back to back register writes by adding the register 3544919Sxy150489 * read (flush). This is to protect against some strange 3554919Sxy150489 * bridge configurations that may issue Memory Write Block 3564919Sxy150489 * (MWB) to our register space. The *_rev_3 hardware at 3574919Sxy150489 * least doesn't respond correctly to every other dword in an 3584919Sxy150489 * MWB to our register space. 3594919Sxy150489 */ 3604919Sxy150489 E1000_WRITE_FLUSH(hw); 3614919Sxy150489 } 3624919Sxy150489 3634919Sxy150489 if (mac->type < e1000_82545_rev_3) 3644919Sxy150489 e1000_pcix_mmrbc_workaround_generic(hw); 3654919Sxy150489 3664919Sxy150489 /* Setup link and flow control */ 3676735Scc210113 ret_val = mac->ops.setup_link(hw); 3684919Sxy150489 3696735Scc210113 txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); 3704919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | 3714919Sxy150489 E1000_TXDCTL_FULL_TX_DESC_WB; 3726735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); 3734919Sxy150489 3744919Sxy150489 /* 3754919Sxy150489 * Clear all of the statistics registers (clear on read). It is 3764919Sxy150489 * important that we do this after we have tried to establish link 3774919Sxy150489 * because the symbol error count will increment wildly if there 3784919Sxy150489 * is no link. 3794919Sxy150489 */ 3804919Sxy150489 e1000_clear_hw_cntrs_82540(hw); 3814919Sxy150489 3824919Sxy150489 if ((hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER) || 3834919Sxy150489 (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3)) { 3844919Sxy150489 ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 3854919Sxy150489 /* 3864919Sxy150489 * Relaxed ordering must be disabled to avoid a parity 3874919Sxy150489 * error crash in a PCI slot. 3884919Sxy150489 */ 3894919Sxy150489 ctrl_ext |= E1000_CTRL_EXT_RO_DIS; 3904919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 3914919Sxy150489 } 3924919Sxy150489 return (ret_val); 3934919Sxy150489 } 3944919Sxy150489 3954919Sxy150489 /* 3966735Scc210113 * e1000_setup_copper_link_82540 - Configure copper link settings 3976735Scc210113 * @hw: pointer to the HW structure 3984919Sxy150489 * 3996735Scc210113 * Calls the appropriate function to configure the link for auto-neg or forced 4006735Scc210113 * speed and duplex. Then we check for link, once link is established calls 4016735Scc210113 * to configure collision distance and flow control are called. If link is 402*8479SChenlu.Chen@Sun.COM * not established, we return -E1000_ERR_PHY (-2). 4034919Sxy150489 */ 4044919Sxy150489 static s32 4054919Sxy150489 e1000_setup_copper_link_82540(struct e1000_hw *hw) 4064919Sxy150489 { 4074919Sxy150489 u32 ctrl; 4084919Sxy150489 s32 ret_val = E1000_SUCCESS; 4094919Sxy150489 u16 data; 4104919Sxy150489 4114919Sxy150489 DEBUGFUNC("e1000_setup_copper_link_82540"); 4124919Sxy150489 4134919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 4144919Sxy150489 ctrl |= E1000_CTRL_SLU; 4154919Sxy150489 ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 4164919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 4174919Sxy150489 4184919Sxy150489 ret_val = e1000_set_phy_mode_82540(hw); 4194919Sxy150489 if (ret_val) 4204919Sxy150489 goto out; 4214919Sxy150489 4224919Sxy150489 if (hw->mac.type == e1000_82545_rev_3 || 4234919Sxy150489 hw->mac.type == e1000_82546_rev_3) { 4246735Scc210113 ret_val = 4256735Scc210113 hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &data); 4264919Sxy150489 if (ret_val) 4274919Sxy150489 goto out; 4284919Sxy150489 data |= 0x00000008; 4296735Scc210113 ret_val = 4306735Scc210113 hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, data); 4314919Sxy150489 if (ret_val) 4324919Sxy150489 goto out; 4334919Sxy150489 } 4344919Sxy150489 ret_val = e1000_copper_link_setup_m88(hw); 4354919Sxy150489 if (ret_val) 4364919Sxy150489 goto out; 4374919Sxy150489 4384919Sxy150489 ret_val = e1000_setup_copper_link_generic(hw); 4394919Sxy150489 4404919Sxy150489 out: 4414919Sxy150489 return (ret_val); 4424919Sxy150489 } 4434919Sxy150489 4444919Sxy150489 /* 4456735Scc210113 * e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes 4466735Scc210113 * @hw: pointer to the HW structure 4474919Sxy150489 * 4486735Scc210113 * Set the output amplitude to the value in the EEPROM and adjust the VCO 4496735Scc210113 * speed to improve Bit Error Rate (BER) performance. Configures collision 4506735Scc210113 * distance and flow control for fiber and serdes links. Upon successful 451*8479SChenlu.Chen@Sun.COM * setup, poll for link. 4524919Sxy150489 */ 4534919Sxy150489 static s32 4544919Sxy150489 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw) 4554919Sxy150489 { 4564919Sxy150489 struct e1000_mac_info *mac = &hw->mac; 4574919Sxy150489 s32 ret_val = E1000_SUCCESS; 4584919Sxy150489 4594919Sxy150489 DEBUGFUNC("e1000_setup_fiber_serdes_link_82540"); 4604919Sxy150489 4614919Sxy150489 switch (mac->type) { 4624919Sxy150489 case e1000_82545_rev_3: 4634919Sxy150489 case e1000_82546_rev_3: 4646735Scc210113 if (hw->phy.media_type == e1000_media_type_internal_serdes) { 4654919Sxy150489 /* 4664919Sxy150489 * If we're on serdes media, adjust the output 4674919Sxy150489 * amplitude to value set in the EEPROM. 4684919Sxy150489 */ 4694919Sxy150489 ret_val = e1000_adjust_serdes_amplitude_82540(hw); 4704919Sxy150489 if (ret_val) 4714919Sxy150489 goto out; 4724919Sxy150489 } 4734919Sxy150489 /* Adjust VCO speed to improve BER performance */ 4744919Sxy150489 ret_val = e1000_set_vco_speed_82540(hw); 4754919Sxy150489 if (ret_val) 4764919Sxy150489 goto out; 4774919Sxy150489 default: 4784919Sxy150489 break; 4794919Sxy150489 } 4804919Sxy150489 4814919Sxy150489 ret_val = e1000_setup_fiber_serdes_link_generic(hw); 4824919Sxy150489 4834919Sxy150489 out: 4844919Sxy150489 return (ret_val); 4854919Sxy150489 } 4864919Sxy150489 4874919Sxy150489 /* 4886735Scc210113 * e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM 4896735Scc210113 * @hw: pointer to the HW structure 4904919Sxy150489 * 4916735Scc210113 * Adjust the SERDES output amplitude based on the EEPROM settings. 4924919Sxy150489 */ 4934919Sxy150489 static s32 4944919Sxy150489 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw) 4954919Sxy150489 { 4964919Sxy150489 s32 ret_val = E1000_SUCCESS; 4974919Sxy150489 u16 nvm_data; 4984919Sxy150489 4994919Sxy150489 DEBUGFUNC("e1000_adjust_serdes_amplitude_82540"); 5004919Sxy150489 5016735Scc210113 ret_val = hw->nvm.ops.read(hw, NVM_SERDES_AMPLITUDE, 1, &nvm_data); 5024919Sxy150489 if (ret_val) 5034919Sxy150489 goto out; 5044919Sxy150489 5054919Sxy150489 if (nvm_data != NVM_RESERVED_WORD) { 5064919Sxy150489 /* Adjust serdes output amplitude only. */ 5074919Sxy150489 nvm_data &= NVM_SERDES_AMPLITUDE_MASK; 5086735Scc210113 ret_val = hw->phy.ops.write_reg(hw, 5094919Sxy150489 M88E1000_PHY_EXT_CTRL, 5104919Sxy150489 nvm_data); 5114919Sxy150489 if (ret_val) 5124919Sxy150489 goto out; 5134919Sxy150489 } 5144919Sxy150489 out: 5154919Sxy150489 return (ret_val); 5164919Sxy150489 } 5174919Sxy150489 5184919Sxy150489 /* 5196735Scc210113 * e1000_set_vco_speed_82540 - Set VCO speed for better performance 5206735Scc210113 * @hw: pointer to the HW structure 5214919Sxy150489 * 5226735Scc210113 * Set the VCO speed to improve Bit Error Rate (BER) performance. 5234919Sxy150489 */ 5244919Sxy150489 static s32 5254919Sxy150489 e1000_set_vco_speed_82540(struct e1000_hw *hw) 5264919Sxy150489 { 5274919Sxy150489 s32 ret_val = E1000_SUCCESS; 5284919Sxy150489 u16 default_page = 0; 5294919Sxy150489 u16 phy_data; 5304919Sxy150489 5314919Sxy150489 DEBUGFUNC("e1000_set_vco_speed_82540"); 5324919Sxy150489 5334919Sxy150489 /* Set PHY register 30, page 5, bit 8 to 0 */ 5344919Sxy150489 5356735Scc210113 ret_val = hw->phy.ops.read_reg(hw, 5364919Sxy150489 M88E1000_PHY_PAGE_SELECT, 5374919Sxy150489 &default_page); 5384919Sxy150489 if (ret_val) 5394919Sxy150489 goto out; 5404919Sxy150489 5416735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005); 5424919Sxy150489 if (ret_val) 5434919Sxy150489 goto out; 5444919Sxy150489 5456735Scc210113 ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data); 5464919Sxy150489 if (ret_val) 5474919Sxy150489 goto out; 5484919Sxy150489 5494919Sxy150489 phy_data &= ~M88E1000_PHY_VCO_REG_BIT8; 5506735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data); 5514919Sxy150489 if (ret_val) 5524919Sxy150489 goto out; 5534919Sxy150489 5544919Sxy150489 /* Set PHY register 30, page 4, bit 11 to 1 */ 5554919Sxy150489 5566735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004); 5574919Sxy150489 if (ret_val) 5584919Sxy150489 goto out; 5594919Sxy150489 5606735Scc210113 ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data); 5614919Sxy150489 if (ret_val) 5624919Sxy150489 goto out; 5634919Sxy150489 5644919Sxy150489 phy_data |= M88E1000_PHY_VCO_REG_BIT11; 5656735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data); 5664919Sxy150489 if (ret_val) 5674919Sxy150489 goto out; 5684919Sxy150489 5696735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 5704919Sxy150489 default_page); 5714919Sxy150489 5724919Sxy150489 out: 5734919Sxy150489 return (ret_val); 5744919Sxy150489 } 5754919Sxy150489 5764919Sxy150489 /* 5776735Scc210113 * e1000_set_phy_mode_82540 - Set PHY to class A mode 5786735Scc210113 * @hw: pointer to the HW structure 5794919Sxy150489 * 5806735Scc210113 * Sets the PHY to class A mode and assumes the following operations will 5816735Scc210113 * follow to enable the new class mode: 5826735Scc210113 * 1. Do a PHY soft reset. 5836735Scc210113 * 2. Restart auto-negotiation or force link. 5844919Sxy150489 */ 5854919Sxy150489 static s32 5864919Sxy150489 e1000_set_phy_mode_82540(struct e1000_hw *hw) 5874919Sxy150489 { 5884919Sxy150489 struct e1000_phy_info *phy = &hw->phy; 5894919Sxy150489 s32 ret_val = E1000_SUCCESS; 5904919Sxy150489 u16 nvm_data; 5914919Sxy150489 5924919Sxy150489 DEBUGFUNC("e1000_set_phy_mode_82540"); 5934919Sxy150489 5944919Sxy150489 if (hw->mac.type != e1000_82545_rev_3) 5954919Sxy150489 goto out; 5964919Sxy150489 5976735Scc210113 ret_val = hw->nvm.ops.read(hw, NVM_PHY_CLASS_WORD, 1, &nvm_data); 5984919Sxy150489 if (ret_val) { 5994919Sxy150489 ret_val = -E1000_ERR_PHY; 6004919Sxy150489 goto out; 6014919Sxy150489 } 6024919Sxy150489 6034919Sxy150489 if ((nvm_data != NVM_RESERVED_WORD) && (nvm_data & NVM_PHY_CLASS_A)) { 6046735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 6054919Sxy150489 0x000B); 6064919Sxy150489 if (ret_val) { 6074919Sxy150489 ret_val = -E1000_ERR_PHY; 6084919Sxy150489 goto out; 6094919Sxy150489 } 6106735Scc210113 ret_val = hw->phy.ops.write_reg(hw, 6114919Sxy150489 M88E1000_PHY_GEN_CONTROL, 6124919Sxy150489 0x8104); 6134919Sxy150489 if (ret_val) { 6144919Sxy150489 ret_val = -E1000_ERR_PHY; 6154919Sxy150489 goto out; 6164919Sxy150489 } 6174919Sxy150489 6187607STed.You@Sun.COM phy->reset_disable = false; 6194919Sxy150489 } 6204919Sxy150489 6214919Sxy150489 out: 6224919Sxy150489 return (ret_val); 6234919Sxy150489 } 6244919Sxy150489 6254919Sxy150489 /* 6266735Scc210113 * e1000_power_down_phy_copper_82540 - Remove link in case of PHY power down 6274919Sxy150489 * @hw: pointer to the HW structure 6284919Sxy150489 * 6296735Scc210113 * In the case of a PHY power down to save power, or to turn off link during a 6306735Scc210113 * driver unload, or wake on lan is not enabled, remove the link. 6316735Scc210113 */ 6326735Scc210113 static void 6336735Scc210113 e1000_power_down_phy_copper_82540(struct e1000_hw *hw) 6346735Scc210113 { 6356735Scc210113 /* If the management interface is not enabled, then power down */ 6366735Scc210113 if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN)) 6376735Scc210113 e1000_power_down_phy_copper(hw); 6386735Scc210113 } 6396735Scc210113 6406735Scc210113 /* 6416735Scc210113 * e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters 6426735Scc210113 * @hw: pointer to the HW structure 6436735Scc210113 * 6446735Scc210113 * Clears the hardware counters by reading the counter registers. 6454919Sxy150489 */ 6464919Sxy150489 static void 6474919Sxy150489 e1000_clear_hw_cntrs_82540(struct e1000_hw *hw) 6484919Sxy150489 { 6494919Sxy150489 DEBUGFUNC("e1000_clear_hw_cntrs_82540"); 6504919Sxy150489 6514919Sxy150489 e1000_clear_hw_cntrs_base_generic(hw); 6524919Sxy150489 6537426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC64); 6547426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC127); 6557426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC255); 6567426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC511); 6577426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC1023); 6587426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC1522); 6597426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC64); 6607426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC127); 6617426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC255); 6627426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC511); 6637426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC1023); 6647426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC1522); 6654919Sxy150489 6667426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ALGNERRC); 6677426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_RXERRC); 6687426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TNCRS); 6697426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_CEXTERR); 6707426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTC); 6717426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTFC); 6724919Sxy150489 6737426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPRC); 6747426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPDC); 6757426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPTC); 6764919Sxy150489 } 677