18cfa0ad2SJack F Vogel /****************************************************************************** 27282444bSPedro F. Giffuni SPDX-License-Identifier: BSD-3-Clause 38cfa0ad2SJack F Vogel 4702cac6cSKevin Bowling Copyright (c) 2001-2020, Intel Corporation 58cfa0ad2SJack F Vogel All rights reserved. 68cfa0ad2SJack F Vogel 78cfa0ad2SJack F Vogel Redistribution and use in source and binary forms, with or without 88cfa0ad2SJack F Vogel modification, are permitted provided that the following conditions are met: 98cfa0ad2SJack F Vogel 108cfa0ad2SJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 118cfa0ad2SJack F Vogel this list of conditions and the following disclaimer. 128cfa0ad2SJack F Vogel 138cfa0ad2SJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 148cfa0ad2SJack F Vogel notice, this list of conditions and the following disclaimer in the 158cfa0ad2SJack F Vogel documentation and/or other materials provided with the distribution. 168cfa0ad2SJack F Vogel 178cfa0ad2SJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 188cfa0ad2SJack F Vogel contributors may be used to endorse or promote products derived from 198cfa0ad2SJack F Vogel this software without specific prior written permission. 208cfa0ad2SJack F Vogel 218cfa0ad2SJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 228cfa0ad2SJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238cfa0ad2SJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248cfa0ad2SJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 258cfa0ad2SJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 268cfa0ad2SJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 278cfa0ad2SJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 288cfa0ad2SJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 298cfa0ad2SJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 308cfa0ad2SJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 318cfa0ad2SJack F Vogel POSSIBILITY OF SUCH DAMAGE. 328cfa0ad2SJack F Vogel 338cfa0ad2SJack F Vogel ******************************************************************************/ 348cfa0ad2SJack F Vogel /*$FreeBSD$*/ 358cfa0ad2SJack F Vogel 36daf9197cSJack F Vogel /* 37daf9197cSJack F Vogel * 82541EI Gigabit Ethernet Controller 38daf9197cSJack F Vogel * 82541ER Gigabit Ethernet Controller 39daf9197cSJack F Vogel * 82541GI Gigabit Ethernet Controller 40daf9197cSJack F Vogel * 82541PI Gigabit Ethernet Controller 41daf9197cSJack F Vogel * 82547EI Gigabit Ethernet Controller 42daf9197cSJack F Vogel * 82547GI Gigabit Ethernet Controller 438cfa0ad2SJack F Vogel */ 448cfa0ad2SJack F Vogel 458cfa0ad2SJack F Vogel #include "e1000_api.h" 468cfa0ad2SJack F Vogel 478cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_82541(struct e1000_hw *hw); 488cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw); 498cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_82541(struct e1000_hw *hw); 508cfa0ad2SJack F Vogel static s32 e1000_reset_hw_82541(struct e1000_hw *hw); 518cfa0ad2SJack F Vogel static s32 e1000_init_hw_82541(struct e1000_hw *hw); 528cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, 538cfa0ad2SJack F Vogel u16 *duplex); 548cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw); 558cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw); 568cfa0ad2SJack F Vogel static s32 e1000_check_for_link_82541(struct e1000_hw *hw); 578cfa0ad2SJack F Vogel static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw); 588cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, 598cfa0ad2SJack F Vogel bool active); 608cfa0ad2SJack F Vogel static s32 e1000_setup_led_82541(struct e1000_hw *hw); 618cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_82541(struct e1000_hw *hw); 628cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw); 634edd8523SJack F Vogel static s32 e1000_read_mac_addr_82541(struct e1000_hw *hw); 648cfa0ad2SJack F Vogel static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw, 658cfa0ad2SJack F Vogel bool link_up); 668cfa0ad2SJack F Vogel static s32 e1000_phy_init_script_82541(struct e1000_hw *hw); 678cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw); 688cfa0ad2SJack F Vogel 6948600901SSean Bruno static const u16 e1000_igp_cable_length_table[] = { 7048600901SSean Bruno 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 7148600901SSean Bruno 10, 10, 20, 20, 20, 20, 20, 25, 25, 25, 25, 25, 25, 25, 30, 30, 30, 30, 7248600901SSean Bruno 40, 40, 40, 40, 40, 40, 40, 40, 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 7348600901SSean Bruno 60, 60, 60, 60, 60, 60, 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 7448600901SSean Bruno 80, 90, 90, 90, 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 7548600901SSean Bruno 100, 100, 100, 100, 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 7648600901SSean Bruno 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 120, 120, 7748600901SSean Bruno 120, 120, 120, 120, 120, 120, 120, 120}; 788cfa0ad2SJack F Vogel #define IGP01E1000_AGC_LENGTH_TABLE_SIZE \ 798cfa0ad2SJack F Vogel (sizeof(e1000_igp_cable_length_table) / \ 808cfa0ad2SJack F Vogel sizeof(e1000_igp_cable_length_table[0])) 818cfa0ad2SJack F Vogel 828cfa0ad2SJack F Vogel /** 838cfa0ad2SJack F Vogel * e1000_init_phy_params_82541 - Init PHY func ptrs. 848cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 858cfa0ad2SJack F Vogel **/ 868cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_82541(struct e1000_hw *hw) 878cfa0ad2SJack F Vogel { 888cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 89c80429ceSEric Joyner s32 ret_val; 908cfa0ad2SJack F Vogel 918cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_phy_params_82541"); 928cfa0ad2SJack F Vogel 938cfa0ad2SJack F Vogel phy->addr = 1; 948cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 958cfa0ad2SJack F Vogel phy->reset_delay_us = 10000; 968cfa0ad2SJack F Vogel phy->type = e1000_phy_igp; 978cfa0ad2SJack F Vogel 988cfa0ad2SJack F Vogel /* Function Pointers */ 998cfa0ad2SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_igp; 1008cfa0ad2SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; 1018cfa0ad2SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_82541; 1028cfa0ad2SJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_generic; 1038cfa0ad2SJack F Vogel phy->ops.get_info = e1000_get_phy_info_igp; 1048cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_igp; 1058cfa0ad2SJack F Vogel phy->ops.reset = e1000_phy_hw_reset_82541; 1068cfa0ad2SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82541; 1078cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_igp; 1088cfa0ad2SJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 1098cfa0ad2SJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_82541; 1108cfa0ad2SJack F Vogel 1118cfa0ad2SJack F Vogel ret_val = e1000_get_phy_id(hw); 1128cfa0ad2SJack F Vogel if (ret_val) 1138cfa0ad2SJack F Vogel goto out; 1148cfa0ad2SJack F Vogel 1158cfa0ad2SJack F Vogel /* Verify phy id */ 1168cfa0ad2SJack F Vogel if (phy->id != IGP01E1000_I_PHY_ID) { 1178cfa0ad2SJack F Vogel ret_val = -E1000_ERR_PHY; 1188cfa0ad2SJack F Vogel goto out; 1198cfa0ad2SJack F Vogel } 1208cfa0ad2SJack F Vogel 1218cfa0ad2SJack F Vogel out: 1228cfa0ad2SJack F Vogel return ret_val; 1238cfa0ad2SJack F Vogel } 1248cfa0ad2SJack F Vogel 1258cfa0ad2SJack F Vogel /** 1268cfa0ad2SJack F Vogel * e1000_init_nvm_params_82541 - Init NVM func ptrs. 1278cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 1288cfa0ad2SJack F Vogel **/ 1298cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw) 1308cfa0ad2SJack F Vogel { 1318cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 1328cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 1338cfa0ad2SJack F Vogel u32 eecd = E1000_READ_REG(hw, E1000_EECD); 1348cfa0ad2SJack F Vogel u16 size; 1358cfa0ad2SJack F Vogel 1368cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_82541"); 1378cfa0ad2SJack F Vogel 1388cfa0ad2SJack F Vogel switch (nvm->override) { 1398cfa0ad2SJack F Vogel case e1000_nvm_override_spi_large: 1408cfa0ad2SJack F Vogel nvm->type = e1000_nvm_eeprom_spi; 1418cfa0ad2SJack F Vogel eecd |= E1000_EECD_ADDR_BITS; 1428cfa0ad2SJack F Vogel break; 1438cfa0ad2SJack F Vogel case e1000_nvm_override_spi_small: 1448cfa0ad2SJack F Vogel nvm->type = e1000_nvm_eeprom_spi; 1458cfa0ad2SJack F Vogel eecd &= ~E1000_EECD_ADDR_BITS; 1468cfa0ad2SJack F Vogel break; 1478cfa0ad2SJack F Vogel case e1000_nvm_override_microwire_large: 1488cfa0ad2SJack F Vogel nvm->type = e1000_nvm_eeprom_microwire; 1498cfa0ad2SJack F Vogel eecd |= E1000_EECD_SIZE; 1508cfa0ad2SJack F Vogel break; 1518cfa0ad2SJack F Vogel case e1000_nvm_override_microwire_small: 1528cfa0ad2SJack F Vogel nvm->type = e1000_nvm_eeprom_microwire; 1538cfa0ad2SJack F Vogel eecd &= ~E1000_EECD_SIZE; 1548cfa0ad2SJack F Vogel break; 1558cfa0ad2SJack F Vogel default: 15648600901SSean Bruno nvm->type = eecd & E1000_EECD_TYPE ? e1000_nvm_eeprom_spi 1578cfa0ad2SJack F Vogel : e1000_nvm_eeprom_microwire; 1588cfa0ad2SJack F Vogel break; 1598cfa0ad2SJack F Vogel } 1608cfa0ad2SJack F Vogel 1618cfa0ad2SJack F Vogel if (nvm->type == e1000_nvm_eeprom_spi) { 16248600901SSean Bruno nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS) ? 16 : 8; 1638cfa0ad2SJack F Vogel nvm->delay_usec = 1; 1648cfa0ad2SJack F Vogel nvm->opcode_bits = 8; 16548600901SSean Bruno nvm->page_size = (eecd & E1000_EECD_ADDR_BITS) ? 32 : 8; 1668cfa0ad2SJack F Vogel 1678cfa0ad2SJack F Vogel /* Function Pointers */ 1688cfa0ad2SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_generic; 1698cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_spi; 1708cfa0ad2SJack F Vogel nvm->ops.release = e1000_release_nvm_generic; 1718cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_generic; 1728cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_generic; 1738cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_generic; 1748cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_spi; 1758cfa0ad2SJack F Vogel 1768cfa0ad2SJack F Vogel /* 1778cfa0ad2SJack F Vogel * nvm->word_size must be discovered after the pointers 1788cfa0ad2SJack F Vogel * are set so we can verify the size from the nvm image 1798cfa0ad2SJack F Vogel * itself. Temporarily set it to a dummy value so the 1808cfa0ad2SJack F Vogel * read will work. 1818cfa0ad2SJack F Vogel */ 1828cfa0ad2SJack F Vogel nvm->word_size = 64; 1838cfa0ad2SJack F Vogel ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size); 1848cfa0ad2SJack F Vogel if (ret_val) 1858cfa0ad2SJack F Vogel goto out; 1868cfa0ad2SJack F Vogel size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT; 1878cfa0ad2SJack F Vogel /* 1888cfa0ad2SJack F Vogel * if size != 0, it can be added to a constant and become 1898cfa0ad2SJack F Vogel * the left-shift value to set the word_size. Otherwise, 1908cfa0ad2SJack F Vogel * word_size stays at 64. 1918cfa0ad2SJack F Vogel */ 1928cfa0ad2SJack F Vogel if (size) { 1938cfa0ad2SJack F Vogel size += NVM_WORD_SIZE_BASE_SHIFT_82541; 1948cfa0ad2SJack F Vogel nvm->word_size = 1 << size; 1958cfa0ad2SJack F Vogel } 1968cfa0ad2SJack F Vogel } else { 19748600901SSean Bruno nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS) ? 8 : 6; 1988cfa0ad2SJack F Vogel nvm->delay_usec = 50; 1998cfa0ad2SJack F Vogel nvm->opcode_bits = 3; 20048600901SSean Bruno nvm->word_size = (eecd & E1000_EECD_ADDR_BITS) ? 256 : 64; 2018cfa0ad2SJack F Vogel 2028cfa0ad2SJack F Vogel /* Function Pointers */ 2038cfa0ad2SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_generic; 2048cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_microwire; 2058cfa0ad2SJack F Vogel nvm->ops.release = e1000_release_nvm_generic; 2068cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_generic; 2078cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_generic; 2088cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_generic; 2098cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_microwire; 2108cfa0ad2SJack F Vogel } 2118cfa0ad2SJack F Vogel 2128cfa0ad2SJack F Vogel out: 2138cfa0ad2SJack F Vogel return ret_val; 2148cfa0ad2SJack F Vogel } 2158cfa0ad2SJack F Vogel 2168cfa0ad2SJack F Vogel /** 2178cfa0ad2SJack F Vogel * e1000_init_mac_params_82541 - Init MAC func ptrs. 2188cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 2198cfa0ad2SJack F Vogel **/ 2208cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_82541(struct e1000_hw *hw) 2218cfa0ad2SJack F Vogel { 2228cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 2238cfa0ad2SJack F Vogel 2248cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_mac_params_82541"); 2258cfa0ad2SJack F Vogel 2268cfa0ad2SJack F Vogel /* Set media type */ 2278cfa0ad2SJack F Vogel hw->phy.media_type = e1000_media_type_copper; 2288cfa0ad2SJack F Vogel /* Set mta register count */ 2298cfa0ad2SJack F Vogel mac->mta_reg_count = 128; 2308cfa0ad2SJack F Vogel /* Set rar entry count */ 2318cfa0ad2SJack F Vogel mac->rar_entry_count = E1000_RAR_ENTRIES; 2328cfa0ad2SJack F Vogel /* Set if part includes ASF firmware */ 2331bbdc25fSKevin Bowling mac->asf_firmware_present = true; 2348cfa0ad2SJack F Vogel 2358cfa0ad2SJack F Vogel /* Function Pointers */ 2368cfa0ad2SJack F Vogel 2378cfa0ad2SJack F Vogel /* bus type/speed/width */ 2388cfa0ad2SJack F Vogel mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; 239daf9197cSJack F Vogel /* function id */ 240daf9197cSJack F Vogel mac->ops.set_lan_id = e1000_set_lan_id_single_port; 2418cfa0ad2SJack F Vogel /* reset */ 2428cfa0ad2SJack F Vogel mac->ops.reset_hw = e1000_reset_hw_82541; 2438cfa0ad2SJack F Vogel /* hw initialization */ 2448cfa0ad2SJack F Vogel mac->ops.init_hw = e1000_init_hw_82541; 2458cfa0ad2SJack F Vogel /* link setup */ 2468cfa0ad2SJack F Vogel mac->ops.setup_link = e1000_setup_link_generic; 2478cfa0ad2SJack F Vogel /* physical interface link setup */ 2488cfa0ad2SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_82541; 2498cfa0ad2SJack F Vogel /* check for link */ 2508cfa0ad2SJack F Vogel mac->ops.check_for_link = e1000_check_for_link_82541; 2518cfa0ad2SJack F Vogel /* link info */ 2528cfa0ad2SJack F Vogel mac->ops.get_link_up_info = e1000_get_link_up_info_82541; 2538cfa0ad2SJack F Vogel /* multicast address update */ 2548cfa0ad2SJack F Vogel mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; 2558cfa0ad2SJack F Vogel /* writing VFTA */ 2568cfa0ad2SJack F Vogel mac->ops.write_vfta = e1000_write_vfta_generic; 2578cfa0ad2SJack F Vogel /* clearing VFTA */ 2588cfa0ad2SJack F Vogel mac->ops.clear_vfta = e1000_clear_vfta_generic; 2594edd8523SJack F Vogel /* read mac address */ 2604edd8523SJack F Vogel mac->ops.read_mac_addr = e1000_read_mac_addr_82541; 261d035aa2dSJack F Vogel /* ID LED init */ 262d035aa2dSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_generic; 2638cfa0ad2SJack F Vogel /* setup LED */ 2648cfa0ad2SJack F Vogel mac->ops.setup_led = e1000_setup_led_82541; 2658cfa0ad2SJack F Vogel /* cleanup LED */ 2668cfa0ad2SJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_82541; 2678cfa0ad2SJack F Vogel /* turn on/off LED */ 2688cfa0ad2SJack F Vogel mac->ops.led_on = e1000_led_on_generic; 2698cfa0ad2SJack F Vogel mac->ops.led_off = e1000_led_off_generic; 2708cfa0ad2SJack F Vogel /* clear hardware counters */ 2718cfa0ad2SJack F Vogel mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541; 2728cfa0ad2SJack F Vogel 273daf9197cSJack F Vogel return E1000_SUCCESS; 2748cfa0ad2SJack F Vogel } 2758cfa0ad2SJack F Vogel 2768cfa0ad2SJack F Vogel /** 2778cfa0ad2SJack F Vogel * e1000_init_function_pointers_82541 - Init func ptrs. 2788cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 2798cfa0ad2SJack F Vogel * 280daf9197cSJack F Vogel * Called to initialize all function pointers and parameters. 2818cfa0ad2SJack F Vogel **/ 2828cfa0ad2SJack F Vogel void e1000_init_function_pointers_82541(struct e1000_hw *hw) 2838cfa0ad2SJack F Vogel { 2848cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_function_pointers_82541"); 2858cfa0ad2SJack F Vogel 2868cfa0ad2SJack F Vogel hw->mac.ops.init_params = e1000_init_mac_params_82541; 2878cfa0ad2SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_82541; 2888cfa0ad2SJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_82541; 2898cfa0ad2SJack F Vogel } 2908cfa0ad2SJack F Vogel 2918cfa0ad2SJack F Vogel /** 2928cfa0ad2SJack F Vogel * e1000_reset_hw_82541 - Reset hardware 2938cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 2948cfa0ad2SJack F Vogel * 295daf9197cSJack F Vogel * This resets the hardware into a known state. 2968cfa0ad2SJack F Vogel **/ 2978cfa0ad2SJack F Vogel static s32 e1000_reset_hw_82541(struct e1000_hw *hw) 2988cfa0ad2SJack F Vogel { 299c80429ceSEric Joyner u32 ledctl, ctrl, manc; 3008cfa0ad2SJack F Vogel 3018cfa0ad2SJack F Vogel DEBUGFUNC("e1000_reset_hw_82541"); 3028cfa0ad2SJack F Vogel 3038cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n"); 3048cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); 3058cfa0ad2SJack F Vogel 3068cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, 0); 3078cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); 3088cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw); 3098cfa0ad2SJack F Vogel 3108cfa0ad2SJack F Vogel /* 3118cfa0ad2SJack F Vogel * Delay to allow any outstanding PCI transactions to complete 3128cfa0ad2SJack F Vogel * before resetting the device. 3138cfa0ad2SJack F Vogel */ 3148cfa0ad2SJack F Vogel msec_delay(10); 3158cfa0ad2SJack F Vogel 3168cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 3178cfa0ad2SJack F Vogel 3188cfa0ad2SJack F Vogel /* Must reset the Phy before resetting the MAC */ 3198cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) { 3208cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST)); 321c80429ceSEric Joyner E1000_WRITE_FLUSH(hw); 3228cfa0ad2SJack F Vogel msec_delay(5); 3238cfa0ad2SJack F Vogel } 3248cfa0ad2SJack F Vogel 3258cfa0ad2SJack F Vogel DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n"); 3268cfa0ad2SJack F Vogel switch (hw->mac.type) { 3278cfa0ad2SJack F Vogel case e1000_82541: 3288cfa0ad2SJack F Vogel case e1000_82541_rev_2: 3298cfa0ad2SJack F Vogel /* 3308cfa0ad2SJack F Vogel * These controllers can't ack the 64-bit write when 3318cfa0ad2SJack F Vogel * issuing the reset, so we use IO-mapping as a 3328cfa0ad2SJack F Vogel * workaround to issue the reset. 3338cfa0ad2SJack F Vogel */ 3348cfa0ad2SJack F Vogel E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); 3358cfa0ad2SJack F Vogel break; 3368cfa0ad2SJack F Vogel default: 3378cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); 3388cfa0ad2SJack F Vogel break; 3398cfa0ad2SJack F Vogel } 3408cfa0ad2SJack F Vogel 3418cfa0ad2SJack F Vogel /* Wait for NVM reload */ 3428cfa0ad2SJack F Vogel msec_delay(20); 3438cfa0ad2SJack F Vogel 3448cfa0ad2SJack F Vogel /* Disable HW ARPs on ASF enabled adapters */ 3458cfa0ad2SJack F Vogel manc = E1000_READ_REG(hw, E1000_MANC); 3468cfa0ad2SJack F Vogel manc &= ~E1000_MANC_ARP_EN; 3478cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_MANC, manc); 3488cfa0ad2SJack F Vogel 3498cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) { 3508cfa0ad2SJack F Vogel e1000_phy_init_script_82541(hw); 3518cfa0ad2SJack F Vogel 3528cfa0ad2SJack F Vogel /* Configure activity LED after Phy reset */ 3538cfa0ad2SJack F Vogel ledctl = E1000_READ_REG(hw, E1000_LEDCTL); 3548cfa0ad2SJack F Vogel ledctl &= IGP_ACTIVITY_LED_MASK; 3558cfa0ad2SJack F Vogel ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); 3568cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); 3578cfa0ad2SJack F Vogel } 3588cfa0ad2SJack F Vogel 3598cfa0ad2SJack F Vogel /* Once again, mask the interrupts */ 3608cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n"); 3618cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); 3628cfa0ad2SJack F Vogel 3638cfa0ad2SJack F Vogel /* Clear any pending interrupt events. */ 364c80429ceSEric Joyner E1000_READ_REG(hw, E1000_ICR); 3658cfa0ad2SJack F Vogel 3668cfa0ad2SJack F Vogel return E1000_SUCCESS; 3678cfa0ad2SJack F Vogel } 3688cfa0ad2SJack F Vogel 3698cfa0ad2SJack F Vogel /** 3708cfa0ad2SJack F Vogel * e1000_init_hw_82541 - Initialize hardware 3718cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 3728cfa0ad2SJack F Vogel * 373daf9197cSJack F Vogel * This inits the hardware readying it for operation. 3748cfa0ad2SJack F Vogel **/ 3758cfa0ad2SJack F Vogel static s32 e1000_init_hw_82541(struct e1000_hw *hw) 3768cfa0ad2SJack F Vogel { 3778cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 3789d81738fSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 3798cfa0ad2SJack F Vogel u32 i, txdctl; 3808cfa0ad2SJack F Vogel s32 ret_val; 3818cfa0ad2SJack F Vogel 3828cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_hw_82541"); 3838cfa0ad2SJack F Vogel 3848cfa0ad2SJack F Vogel /* Initialize identification LED */ 385d035aa2dSJack F Vogel ret_val = mac->ops.id_led_init(hw); 3868cfa0ad2SJack F Vogel if (ret_val) { 3878cfa0ad2SJack F Vogel DEBUGOUT("Error initializing identification LED\n"); 3888cfa0ad2SJack F Vogel /* This is not fatal and we should not stop init due to this */ 3898cfa0ad2SJack F Vogel } 3908cfa0ad2SJack F Vogel 3919d81738fSJack F Vogel /* Storing the Speed Power Down value for later use */ 39248600901SSean Bruno ret_val = hw->phy.ops.read_reg(hw, IGP01E1000_GMII_FIFO, 3939d81738fSJack F Vogel &dev_spec->spd_default); 3949d81738fSJack F Vogel if (ret_val) 3959d81738fSJack F Vogel goto out; 3969d81738fSJack F Vogel 3978cfa0ad2SJack F Vogel /* Disabling VLAN filtering */ 3988cfa0ad2SJack F Vogel DEBUGOUT("Initializing the IEEE VLAN\n"); 3998cfa0ad2SJack F Vogel mac->ops.clear_vfta(hw); 4008cfa0ad2SJack F Vogel 4018cfa0ad2SJack F Vogel /* Setup the receive address. */ 4028cfa0ad2SJack F Vogel e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); 4038cfa0ad2SJack F Vogel 4048cfa0ad2SJack F Vogel /* Zero out the Multicast HASH table */ 4058cfa0ad2SJack F Vogel DEBUGOUT("Zeroing the MTA\n"); 4068cfa0ad2SJack F Vogel for (i = 0; i < mac->mta_reg_count; i++) { 4078cfa0ad2SJack F Vogel E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 4088cfa0ad2SJack F Vogel /* 4098cfa0ad2SJack F Vogel * Avoid back to back register writes by adding the register 4108cfa0ad2SJack F Vogel * read (flush). This is to protect against some strange 4118cfa0ad2SJack F Vogel * bridge configurations that may issue Memory Write Block 4128cfa0ad2SJack F Vogel * (MWB) to our register space. 4138cfa0ad2SJack F Vogel */ 4148cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw); 4158cfa0ad2SJack F Vogel } 4168cfa0ad2SJack F Vogel 4178cfa0ad2SJack F Vogel /* Setup link and flow control */ 4188cfa0ad2SJack F Vogel ret_val = mac->ops.setup_link(hw); 4198cfa0ad2SJack F Vogel 4208cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); 4218cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | 4228cfa0ad2SJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB; 4238cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); 4248cfa0ad2SJack F Vogel 4258cfa0ad2SJack F Vogel /* 4268cfa0ad2SJack F Vogel * Clear all of the statistics registers (clear on read). It is 4278cfa0ad2SJack F Vogel * important that we do this after we have tried to establish link 4288cfa0ad2SJack F Vogel * because the symbol error count will increment wildly if there 4298cfa0ad2SJack F Vogel * is no link. 4308cfa0ad2SJack F Vogel */ 4318cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_82541(hw); 4328cfa0ad2SJack F Vogel 4339d81738fSJack F Vogel out: 4348cfa0ad2SJack F Vogel return ret_val; 4358cfa0ad2SJack F Vogel } 4368cfa0ad2SJack F Vogel 4378cfa0ad2SJack F Vogel /** 4388cfa0ad2SJack F Vogel * e1000_get_link_up_info_82541 - Report speed and duplex 4398cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 4408cfa0ad2SJack F Vogel * @speed: pointer to speed buffer 4418cfa0ad2SJack F Vogel * @duplex: pointer to duplex buffer 4428cfa0ad2SJack F Vogel * 4438cfa0ad2SJack F Vogel * Retrieve the current speed and duplex configuration. 4448cfa0ad2SJack F Vogel **/ 4458cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, 4468cfa0ad2SJack F Vogel u16 *duplex) 4478cfa0ad2SJack F Vogel { 4488cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 4498cfa0ad2SJack F Vogel s32 ret_val; 4508cfa0ad2SJack F Vogel u16 data; 4518cfa0ad2SJack F Vogel 4528cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_link_up_info_82541"); 4538cfa0ad2SJack F Vogel 4548cfa0ad2SJack F Vogel ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); 4558cfa0ad2SJack F Vogel if (ret_val) 4568cfa0ad2SJack F Vogel goto out; 4578cfa0ad2SJack F Vogel 4588cfa0ad2SJack F Vogel if (!phy->speed_downgraded) 4598cfa0ad2SJack F Vogel goto out; 4608cfa0ad2SJack F Vogel 4618cfa0ad2SJack F Vogel /* 4628cfa0ad2SJack F Vogel * IGP01 PHY may advertise full duplex operation after speed 4638cfa0ad2SJack F Vogel * downgrade even if it is operating at half duplex. 4648cfa0ad2SJack F Vogel * Here we set the duplex settings to match the duplex in the 4658cfa0ad2SJack F Vogel * link partner's capabilities. 4668cfa0ad2SJack F Vogel */ 4678cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data); 4688cfa0ad2SJack F Vogel if (ret_val) 4698cfa0ad2SJack F Vogel goto out; 4708cfa0ad2SJack F Vogel 4718cfa0ad2SJack F Vogel if (!(data & NWAY_ER_LP_NWAY_CAPS)) { 4728cfa0ad2SJack F Vogel *duplex = HALF_DUPLEX; 4738cfa0ad2SJack F Vogel } else { 4748cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data); 4758cfa0ad2SJack F Vogel if (ret_val) 4768cfa0ad2SJack F Vogel goto out; 4778cfa0ad2SJack F Vogel 4788cfa0ad2SJack F Vogel if (*speed == SPEED_100) { 4798cfa0ad2SJack F Vogel if (!(data & NWAY_LPAR_100TX_FD_CAPS)) 4808cfa0ad2SJack F Vogel *duplex = HALF_DUPLEX; 4818cfa0ad2SJack F Vogel } else if (*speed == SPEED_10) { 4828cfa0ad2SJack F Vogel if (!(data & NWAY_LPAR_10T_FD_CAPS)) 4838cfa0ad2SJack F Vogel *duplex = HALF_DUPLEX; 4848cfa0ad2SJack F Vogel } 4858cfa0ad2SJack F Vogel } 4868cfa0ad2SJack F Vogel 4878cfa0ad2SJack F Vogel out: 4888cfa0ad2SJack F Vogel return ret_val; 4898cfa0ad2SJack F Vogel } 4908cfa0ad2SJack F Vogel 4918cfa0ad2SJack F Vogel /** 4928cfa0ad2SJack F Vogel * e1000_phy_hw_reset_82541 - PHY hardware reset 4938cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 4948cfa0ad2SJack F Vogel * 4958cfa0ad2SJack F Vogel * Verify the reset block is not blocking us from resetting. Acquire 4968cfa0ad2SJack F Vogel * semaphore (if necessary) and read/set/write the device control reset 4978cfa0ad2SJack F Vogel * bit in the PHY. Wait the appropriate delay time for the device to 4988cfa0ad2SJack F Vogel * reset and release the semaphore (if necessary). 4998cfa0ad2SJack F Vogel **/ 5008cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw) 5018cfa0ad2SJack F Vogel { 5028cfa0ad2SJack F Vogel s32 ret_val; 5038cfa0ad2SJack F Vogel u32 ledctl; 5048cfa0ad2SJack F Vogel 5058cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_hw_reset_82541"); 5068cfa0ad2SJack F Vogel 5078cfa0ad2SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 5088cfa0ad2SJack F Vogel if (ret_val) 5098cfa0ad2SJack F Vogel goto out; 5108cfa0ad2SJack F Vogel 5118cfa0ad2SJack F Vogel e1000_phy_init_script_82541(hw); 5128cfa0ad2SJack F Vogel 5138cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) { 5148cfa0ad2SJack F Vogel /* Configure activity LED after PHY reset */ 5158cfa0ad2SJack F Vogel ledctl = E1000_READ_REG(hw, E1000_LEDCTL); 5168cfa0ad2SJack F Vogel ledctl &= IGP_ACTIVITY_LED_MASK; 5178cfa0ad2SJack F Vogel ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); 5188cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); 5198cfa0ad2SJack F Vogel } 5208cfa0ad2SJack F Vogel 5218cfa0ad2SJack F Vogel out: 5228cfa0ad2SJack F Vogel return ret_val; 5238cfa0ad2SJack F Vogel } 5248cfa0ad2SJack F Vogel 5258cfa0ad2SJack F Vogel /** 5268cfa0ad2SJack F Vogel * e1000_setup_copper_link_82541 - Configure copper link settings 5278cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5288cfa0ad2SJack F Vogel * 5298cfa0ad2SJack F Vogel * Calls the appropriate function to configure the link for auto-neg or forced 5308cfa0ad2SJack F Vogel * speed and duplex. Then we check for link, once link is established calls 5318cfa0ad2SJack F Vogel * to configure collision distance and flow control are called. If link is 532daf9197cSJack F Vogel * not established, we return -E1000_ERR_PHY (-2). 5338cfa0ad2SJack F Vogel **/ 5348cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw) 5358cfa0ad2SJack F Vogel { 5368cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 537daf9197cSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 5388cfa0ad2SJack F Vogel s32 ret_val; 5398cfa0ad2SJack F Vogel u32 ctrl, ledctl; 5408cfa0ad2SJack F Vogel 5418cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_82541"); 5428cfa0ad2SJack F Vogel 5438cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 5448cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_SLU; 5458cfa0ad2SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 5468cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 5478cfa0ad2SJack F Vogel 54848600901SSean Bruno 5498cfa0ad2SJack F Vogel /* Earlier revs of the IGP phy require us to force MDI. */ 5508cfa0ad2SJack F Vogel if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) { 5518cfa0ad2SJack F Vogel dev_spec->dsp_config = e1000_dsp_config_disabled; 5528cfa0ad2SJack F Vogel phy->mdix = 1; 5538cfa0ad2SJack F Vogel } else { 5548cfa0ad2SJack F Vogel dev_spec->dsp_config = e1000_dsp_config_enabled; 5558cfa0ad2SJack F Vogel } 5568cfa0ad2SJack F Vogel 5578cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_igp(hw); 5588cfa0ad2SJack F Vogel if (ret_val) 5598cfa0ad2SJack F Vogel goto out; 5608cfa0ad2SJack F Vogel 5618cfa0ad2SJack F Vogel if (hw->mac.autoneg) { 5628cfa0ad2SJack F Vogel if (dev_spec->ffe_config == e1000_ffe_config_active) 5638cfa0ad2SJack F Vogel dev_spec->ffe_config = e1000_ffe_config_enabled; 5648cfa0ad2SJack F Vogel } 5658cfa0ad2SJack F Vogel 5668cfa0ad2SJack F Vogel /* Configure activity LED after Phy reset */ 5678cfa0ad2SJack F Vogel ledctl = E1000_READ_REG(hw, E1000_LEDCTL); 5688cfa0ad2SJack F Vogel ledctl &= IGP_ACTIVITY_LED_MASK; 5698cfa0ad2SJack F Vogel ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); 5708cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); 5718cfa0ad2SJack F Vogel 5728cfa0ad2SJack F Vogel ret_val = e1000_setup_copper_link_generic(hw); 5738cfa0ad2SJack F Vogel 5748cfa0ad2SJack F Vogel out: 5758cfa0ad2SJack F Vogel return ret_val; 5768cfa0ad2SJack F Vogel } 5778cfa0ad2SJack F Vogel 5788cfa0ad2SJack F Vogel /** 5798cfa0ad2SJack F Vogel * e1000_check_for_link_82541 - Check/Store link connection 5808cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5818cfa0ad2SJack F Vogel * 5828cfa0ad2SJack F Vogel * This checks the link condition of the adapter and stores the 583daf9197cSJack F Vogel * results in the hw->mac structure. 5848cfa0ad2SJack F Vogel **/ 5858cfa0ad2SJack F Vogel static s32 e1000_check_for_link_82541(struct e1000_hw *hw) 5868cfa0ad2SJack F Vogel { 5878cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 5888cfa0ad2SJack F Vogel s32 ret_val; 5898cfa0ad2SJack F Vogel bool link; 5908cfa0ad2SJack F Vogel 5918cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_for_link_82541"); 5928cfa0ad2SJack F Vogel 5938cfa0ad2SJack F Vogel /* 5948cfa0ad2SJack F Vogel * We only want to go out to the PHY registers to see if Auto-Neg 5958cfa0ad2SJack F Vogel * has completed and/or if our link status has changed. The 5968cfa0ad2SJack F Vogel * get_link_status flag is set upon receiving a Link Status 5978cfa0ad2SJack F Vogel * Change or Rx Sequence Error interrupt. 5988cfa0ad2SJack F Vogel */ 5998cfa0ad2SJack F Vogel if (!mac->get_link_status) { 6008cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 6018cfa0ad2SJack F Vogel goto out; 6028cfa0ad2SJack F Vogel } 6038cfa0ad2SJack F Vogel 6048cfa0ad2SJack F Vogel /* 6058cfa0ad2SJack F Vogel * First we want to see if the MII Status Register reports 6068cfa0ad2SJack F Vogel * link. If so, then we want to get the current speed/duplex 6078cfa0ad2SJack F Vogel * of the PHY. 6088cfa0ad2SJack F Vogel */ 6098cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 6108cfa0ad2SJack F Vogel if (ret_val) 6118cfa0ad2SJack F Vogel goto out; 6128cfa0ad2SJack F Vogel 6138cfa0ad2SJack F Vogel if (!link) { 6141bbdc25fSKevin Bowling ret_val = e1000_config_dsp_after_link_change_82541(hw, false); 6158cfa0ad2SJack F Vogel goto out; /* No link detected */ 6168cfa0ad2SJack F Vogel } 6178cfa0ad2SJack F Vogel 6181bbdc25fSKevin Bowling mac->get_link_status = false; 6198cfa0ad2SJack F Vogel 6208cfa0ad2SJack F Vogel /* 6218cfa0ad2SJack F Vogel * Check if there was DownShift, must be checked 6228cfa0ad2SJack F Vogel * immediately after link-up 6238cfa0ad2SJack F Vogel */ 6248cfa0ad2SJack F Vogel e1000_check_downshift_generic(hw); 6258cfa0ad2SJack F Vogel 6268cfa0ad2SJack F Vogel /* 6278cfa0ad2SJack F Vogel * If we are forcing speed/duplex, then we simply return since 6288cfa0ad2SJack F Vogel * we have already determined whether we have link or not. 6298cfa0ad2SJack F Vogel */ 6308cfa0ad2SJack F Vogel if (!mac->autoneg) { 6318cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 6328cfa0ad2SJack F Vogel goto out; 6338cfa0ad2SJack F Vogel } 6348cfa0ad2SJack F Vogel 6351bbdc25fSKevin Bowling ret_val = e1000_config_dsp_after_link_change_82541(hw, true); 6368cfa0ad2SJack F Vogel 6378cfa0ad2SJack F Vogel /* 6388cfa0ad2SJack F Vogel * Auto-Neg is enabled. Auto Speed Detection takes care 6398cfa0ad2SJack F Vogel * of MAC speed/duplex configuration. So we only need to 6408cfa0ad2SJack F Vogel * configure Collision Distance in the MAC. 6418cfa0ad2SJack F Vogel */ 642ab5d0362SJack F Vogel mac->ops.config_collision_dist(hw); 6438cfa0ad2SJack F Vogel 6448cfa0ad2SJack F Vogel /* 6458cfa0ad2SJack F Vogel * Configure Flow Control now that Auto-Neg has completed. 6468cfa0ad2SJack F Vogel * First, we need to restore the desired flow control 6478cfa0ad2SJack F Vogel * settings because we may have had to re-autoneg with a 6488cfa0ad2SJack F Vogel * different link partner. 6498cfa0ad2SJack F Vogel */ 6508cfa0ad2SJack F Vogel ret_val = e1000_config_fc_after_link_up_generic(hw); 65148600901SSean Bruno if (ret_val) 6528cfa0ad2SJack F Vogel DEBUGOUT("Error configuring flow control\n"); 6538cfa0ad2SJack F Vogel 6548cfa0ad2SJack F Vogel out: 6558cfa0ad2SJack F Vogel return ret_val; 6568cfa0ad2SJack F Vogel } 6578cfa0ad2SJack F Vogel 6588cfa0ad2SJack F Vogel /** 6598cfa0ad2SJack F Vogel * e1000_config_dsp_after_link_change_82541 - Config DSP after link 6608cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 6618cfa0ad2SJack F Vogel * @link_up: boolean flag for link up status 6628cfa0ad2SJack F Vogel * 6638cfa0ad2SJack F Vogel * Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS 6648cfa0ad2SJack F Vogel * at any other case. 6658cfa0ad2SJack F Vogel * 6668cfa0ad2SJack F Vogel * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a 6678cfa0ad2SJack F Vogel * gigabit link is achieved to improve link quality. 6688cfa0ad2SJack F Vogel **/ 6698cfa0ad2SJack F Vogel static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw, 6708cfa0ad2SJack F Vogel bool link_up) 6718cfa0ad2SJack F Vogel { 6728cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 673daf9197cSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 6748cfa0ad2SJack F Vogel s32 ret_val; 6758cfa0ad2SJack F Vogel u32 idle_errs = 0; 6768cfa0ad2SJack F Vogel u16 phy_data, phy_saved_data, speed, duplex, i; 6778cfa0ad2SJack F Vogel u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20; 67848600901SSean Bruno u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = { 67948600901SSean Bruno IGP01E1000_PHY_AGC_PARAM_A, 6808cfa0ad2SJack F Vogel IGP01E1000_PHY_AGC_PARAM_B, 6818cfa0ad2SJack F Vogel IGP01E1000_PHY_AGC_PARAM_C, 6828cfa0ad2SJack F Vogel IGP01E1000_PHY_AGC_PARAM_D}; 6838cfa0ad2SJack F Vogel 6848cfa0ad2SJack F Vogel DEBUGFUNC("e1000_config_dsp_after_link_change_82541"); 6858cfa0ad2SJack F Vogel 6868cfa0ad2SJack F Vogel if (link_up) { 6878cfa0ad2SJack F Vogel ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex); 6888cfa0ad2SJack F Vogel if (ret_val) { 6898cfa0ad2SJack F Vogel DEBUGOUT("Error getting link speed and duplex\n"); 6908cfa0ad2SJack F Vogel goto out; 6918cfa0ad2SJack F Vogel } 6928cfa0ad2SJack F Vogel 6938cfa0ad2SJack F Vogel if (speed != SPEED_1000) { 6948cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 6958cfa0ad2SJack F Vogel goto out; 6968cfa0ad2SJack F Vogel } 6978cfa0ad2SJack F Vogel 6988cfa0ad2SJack F Vogel ret_val = phy->ops.get_cable_length(hw); 6998cfa0ad2SJack F Vogel if (ret_val) 7008cfa0ad2SJack F Vogel goto out; 7018cfa0ad2SJack F Vogel 7028cfa0ad2SJack F Vogel if ((dev_spec->dsp_config == e1000_dsp_config_enabled) && 7038cfa0ad2SJack F Vogel phy->min_cable_length >= 50) { 7048cfa0ad2SJack F Vogel 7058cfa0ad2SJack F Vogel for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { 7068cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 7078cfa0ad2SJack F Vogel dsp_reg_array[i], 7088cfa0ad2SJack F Vogel &phy_data); 7098cfa0ad2SJack F Vogel if (ret_val) 7108cfa0ad2SJack F Vogel goto out; 7118cfa0ad2SJack F Vogel 7128cfa0ad2SJack F Vogel phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; 7138cfa0ad2SJack F Vogel 7148cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 7158cfa0ad2SJack F Vogel dsp_reg_array[i], 7168cfa0ad2SJack F Vogel phy_data); 7178cfa0ad2SJack F Vogel if (ret_val) 7188cfa0ad2SJack F Vogel goto out; 7198cfa0ad2SJack F Vogel } 7208cfa0ad2SJack F Vogel dev_spec->dsp_config = e1000_dsp_config_activated; 7218cfa0ad2SJack F Vogel } 7228cfa0ad2SJack F Vogel 7238cfa0ad2SJack F Vogel if ((dev_spec->ffe_config != e1000_ffe_config_enabled) || 7248cfa0ad2SJack F Vogel (phy->min_cable_length >= 50)) { 7258cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 7268cfa0ad2SJack F Vogel goto out; 7278cfa0ad2SJack F Vogel } 7288cfa0ad2SJack F Vogel 7298cfa0ad2SJack F Vogel /* clear previous idle error counts */ 7308cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); 7318cfa0ad2SJack F Vogel if (ret_val) 7328cfa0ad2SJack F Vogel goto out; 7338cfa0ad2SJack F Vogel 7348cfa0ad2SJack F Vogel for (i = 0; i < ffe_idle_err_timeout; i++) { 7358cfa0ad2SJack F Vogel usec_delay(1000); 73648600901SSean Bruno ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, 7378cfa0ad2SJack F Vogel &phy_data); 7388cfa0ad2SJack F Vogel if (ret_val) 7398cfa0ad2SJack F Vogel goto out; 7408cfa0ad2SJack F Vogel 7418cfa0ad2SJack F Vogel idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT); 7428cfa0ad2SJack F Vogel if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) { 7438cfa0ad2SJack F Vogel dev_spec->ffe_config = e1000_ffe_config_active; 7448cfa0ad2SJack F Vogel 7458cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 7468cfa0ad2SJack F Vogel IGP01E1000_PHY_DSP_FFE, 7478cfa0ad2SJack F Vogel IGP01E1000_PHY_DSP_FFE_CM_CP); 7488cfa0ad2SJack F Vogel if (ret_val) 7498cfa0ad2SJack F Vogel goto out; 7508cfa0ad2SJack F Vogel break; 7518cfa0ad2SJack F Vogel } 7528cfa0ad2SJack F Vogel 7538cfa0ad2SJack F Vogel if (idle_errs) 7548cfa0ad2SJack F Vogel ffe_idle_err_timeout = 7558cfa0ad2SJack F Vogel FFE_IDLE_ERR_COUNT_TIMEOUT_100; 7568cfa0ad2SJack F Vogel } 7578cfa0ad2SJack F Vogel } else { 7588cfa0ad2SJack F Vogel if (dev_spec->dsp_config == e1000_dsp_config_activated) { 7598cfa0ad2SJack F Vogel /* 7608cfa0ad2SJack F Vogel * Save off the current value of register 0x2F5B 7618cfa0ad2SJack F Vogel * to be restored at the end of the routines. 7628cfa0ad2SJack F Vogel */ 76348600901SSean Bruno ret_val = phy->ops.read_reg(hw, 0x2F5B, 7648cfa0ad2SJack F Vogel &phy_saved_data); 7658cfa0ad2SJack F Vogel if (ret_val) 7668cfa0ad2SJack F Vogel goto out; 7678cfa0ad2SJack F Vogel 7688cfa0ad2SJack F Vogel /* Disable the PHY transmitter */ 7698cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003); 7708cfa0ad2SJack F Vogel if (ret_val) 7718cfa0ad2SJack F Vogel goto out; 7728cfa0ad2SJack F Vogel 7738cfa0ad2SJack F Vogel msec_delay_irq(20); 7748cfa0ad2SJack F Vogel 77548600901SSean Bruno ret_val = phy->ops.write_reg(hw, 0x0000, 7768cfa0ad2SJack F Vogel IGP01E1000_IEEE_FORCE_GIG); 7778cfa0ad2SJack F Vogel if (ret_val) 7788cfa0ad2SJack F Vogel goto out; 7798cfa0ad2SJack F Vogel for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { 7808cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 7818cfa0ad2SJack F Vogel dsp_reg_array[i], 7828cfa0ad2SJack F Vogel &phy_data); 7838cfa0ad2SJack F Vogel if (ret_val) 7848cfa0ad2SJack F Vogel goto out; 7858cfa0ad2SJack F Vogel 7868cfa0ad2SJack F Vogel phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; 7878cfa0ad2SJack F Vogel phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS; 7888cfa0ad2SJack F Vogel 7898cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 7908cfa0ad2SJack F Vogel dsp_reg_array[i], 7918cfa0ad2SJack F Vogel phy_data); 7928cfa0ad2SJack F Vogel if (ret_val) 7938cfa0ad2SJack F Vogel goto out; 7948cfa0ad2SJack F Vogel } 7958cfa0ad2SJack F Vogel 79648600901SSean Bruno ret_val = phy->ops.write_reg(hw, 0x0000, 7978cfa0ad2SJack F Vogel IGP01E1000_IEEE_RESTART_AUTONEG); 7988cfa0ad2SJack F Vogel if (ret_val) 7998cfa0ad2SJack F Vogel goto out; 8008cfa0ad2SJack F Vogel 8018cfa0ad2SJack F Vogel msec_delay_irq(20); 8028cfa0ad2SJack F Vogel 8038cfa0ad2SJack F Vogel /* Now enable the transmitter */ 80448600901SSean Bruno ret_val = phy->ops.write_reg(hw, 0x2F5B, 8058cfa0ad2SJack F Vogel phy_saved_data); 8068cfa0ad2SJack F Vogel if (ret_val) 8078cfa0ad2SJack F Vogel goto out; 8088cfa0ad2SJack F Vogel 8098cfa0ad2SJack F Vogel dev_spec->dsp_config = e1000_dsp_config_enabled; 8108cfa0ad2SJack F Vogel } 8118cfa0ad2SJack F Vogel 8128cfa0ad2SJack F Vogel if (dev_spec->ffe_config != e1000_ffe_config_active) { 8138cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 8148cfa0ad2SJack F Vogel goto out; 8158cfa0ad2SJack F Vogel } 8168cfa0ad2SJack F Vogel 8178cfa0ad2SJack F Vogel /* 8188cfa0ad2SJack F Vogel * Save off the current value of register 0x2F5B 8198cfa0ad2SJack F Vogel * to be restored at the end of the routines. 8208cfa0ad2SJack F Vogel */ 8218cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data); 8228cfa0ad2SJack F Vogel if (ret_val) 8238cfa0ad2SJack F Vogel goto out; 8248cfa0ad2SJack F Vogel 8258cfa0ad2SJack F Vogel /* Disable the PHY transmitter */ 8268cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003); 8278cfa0ad2SJack F Vogel if (ret_val) 8288cfa0ad2SJack F Vogel goto out; 8298cfa0ad2SJack F Vogel 8308cfa0ad2SJack F Vogel msec_delay_irq(20); 8318cfa0ad2SJack F Vogel 83248600901SSean Bruno ret_val = phy->ops.write_reg(hw, 0x0000, 8338cfa0ad2SJack F Vogel IGP01E1000_IEEE_FORCE_GIG); 8348cfa0ad2SJack F Vogel if (ret_val) 8358cfa0ad2SJack F Vogel goto out; 8368cfa0ad2SJack F Vogel 83748600901SSean Bruno ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_DSP_FFE, 8388cfa0ad2SJack F Vogel IGP01E1000_PHY_DSP_FFE_DEFAULT); 8398cfa0ad2SJack F Vogel if (ret_val) 8408cfa0ad2SJack F Vogel goto out; 8418cfa0ad2SJack F Vogel 84248600901SSean Bruno ret_val = phy->ops.write_reg(hw, 0x0000, 8438cfa0ad2SJack F Vogel IGP01E1000_IEEE_RESTART_AUTONEG); 8448cfa0ad2SJack F Vogel if (ret_val) 8458cfa0ad2SJack F Vogel goto out; 8468cfa0ad2SJack F Vogel 8478cfa0ad2SJack F Vogel msec_delay_irq(20); 8488cfa0ad2SJack F Vogel 8498cfa0ad2SJack F Vogel /* Now enable the transmitter */ 8508cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data); 8518cfa0ad2SJack F Vogel 8528cfa0ad2SJack F Vogel if (ret_val) 8538cfa0ad2SJack F Vogel goto out; 8548cfa0ad2SJack F Vogel 8558cfa0ad2SJack F Vogel dev_spec->ffe_config = e1000_ffe_config_enabled; 8568cfa0ad2SJack F Vogel } 8578cfa0ad2SJack F Vogel 8588cfa0ad2SJack F Vogel out: 8598cfa0ad2SJack F Vogel return ret_val; 8608cfa0ad2SJack F Vogel } 8618cfa0ad2SJack F Vogel 8628cfa0ad2SJack F Vogel /** 8638cfa0ad2SJack F Vogel * e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY 8648cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 8658cfa0ad2SJack F Vogel * 8668cfa0ad2SJack F Vogel * The automatic gain control (agc) normalizes the amplitude of the 8678cfa0ad2SJack F Vogel * received signal, adjusting for the attenuation produced by the 8688cfa0ad2SJack F Vogel * cable. By reading the AGC registers, which represent the 8698cfa0ad2SJack F Vogel * combination of coarse and fine gain value, the value can be put 8708cfa0ad2SJack F Vogel * into a lookup table to obtain the approximate cable length 871daf9197cSJack F Vogel * for each channel. 8728cfa0ad2SJack F Vogel **/ 8738cfa0ad2SJack F Vogel static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw) 8748cfa0ad2SJack F Vogel { 8758cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 8768cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 8778cfa0ad2SJack F Vogel u16 i, data; 8788cfa0ad2SJack F Vogel u16 cur_agc_value, agc_value = 0; 8798cfa0ad2SJack F Vogel u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE; 88048600901SSean Bruno u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {IGP01E1000_PHY_AGC_A, 8818cfa0ad2SJack F Vogel IGP01E1000_PHY_AGC_B, 8828cfa0ad2SJack F Vogel IGP01E1000_PHY_AGC_C, 8838cfa0ad2SJack F Vogel IGP01E1000_PHY_AGC_D}; 8848cfa0ad2SJack F Vogel 8858cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_cable_length_igp_82541"); 8868cfa0ad2SJack F Vogel 8878cfa0ad2SJack F Vogel /* Read the AGC registers for all channels */ 8888cfa0ad2SJack F Vogel for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { 8898cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data); 8908cfa0ad2SJack F Vogel if (ret_val) 8918cfa0ad2SJack F Vogel goto out; 8928cfa0ad2SJack F Vogel 8938cfa0ad2SJack F Vogel cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT; 8948cfa0ad2SJack F Vogel 8958cfa0ad2SJack F Vogel /* Bounds checking */ 8968cfa0ad2SJack F Vogel if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || 8978cfa0ad2SJack F Vogel (cur_agc_value == 0)) { 8988cfa0ad2SJack F Vogel ret_val = -E1000_ERR_PHY; 8998cfa0ad2SJack F Vogel goto out; 9008cfa0ad2SJack F Vogel } 9018cfa0ad2SJack F Vogel 9028cfa0ad2SJack F Vogel agc_value += cur_agc_value; 9038cfa0ad2SJack F Vogel 9048cfa0ad2SJack F Vogel if (min_agc_value > cur_agc_value) 9058cfa0ad2SJack F Vogel min_agc_value = cur_agc_value; 9068cfa0ad2SJack F Vogel } 9078cfa0ad2SJack F Vogel 9088cfa0ad2SJack F Vogel /* Remove the minimal AGC result for length < 50m */ 9098cfa0ad2SJack F Vogel if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) { 9108cfa0ad2SJack F Vogel agc_value -= min_agc_value; 9118cfa0ad2SJack F Vogel /* Average the three remaining channels for the length. */ 9128cfa0ad2SJack F Vogel agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1); 9138cfa0ad2SJack F Vogel } else { 9148cfa0ad2SJack F Vogel /* Average the channels for the length. */ 9158cfa0ad2SJack F Vogel agc_value /= IGP01E1000_PHY_CHANNEL_NUM; 9168cfa0ad2SJack F Vogel } 9178cfa0ad2SJack F Vogel 9188cfa0ad2SJack F Vogel phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] > 9198cfa0ad2SJack F Vogel IGP01E1000_AGC_RANGE) 9208cfa0ad2SJack F Vogel ? (e1000_igp_cable_length_table[agc_value] - 9218cfa0ad2SJack F Vogel IGP01E1000_AGC_RANGE) 9228cfa0ad2SJack F Vogel : 0; 9238cfa0ad2SJack F Vogel phy->max_cable_length = e1000_igp_cable_length_table[agc_value] + 9248cfa0ad2SJack F Vogel IGP01E1000_AGC_RANGE; 9258cfa0ad2SJack F Vogel 9268cfa0ad2SJack F Vogel phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; 9278cfa0ad2SJack F Vogel 9288cfa0ad2SJack F Vogel out: 9298cfa0ad2SJack F Vogel return ret_val; 9308cfa0ad2SJack F Vogel } 9318cfa0ad2SJack F Vogel 9328cfa0ad2SJack F Vogel /** 9338cfa0ad2SJack F Vogel * e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3 9348cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 9358cfa0ad2SJack F Vogel * @active: boolean used to enable/disable lplu 9368cfa0ad2SJack F Vogel * 9378cfa0ad2SJack F Vogel * Success returns 0, Failure returns 1 9388cfa0ad2SJack F Vogel * 9398cfa0ad2SJack F Vogel * The low power link up (lplu) state is set to the power management level D3 9401bbdc25fSKevin Bowling * and SmartSpeed is disabled when active is true, else clear lplu for D3 9418cfa0ad2SJack F Vogel * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU 9428cfa0ad2SJack F Vogel * is used during Dx states where the power conservation is most important. 9438cfa0ad2SJack F Vogel * During driver activity, SmartSpeed should be enabled so performance is 944daf9197cSJack F Vogel * maintained. 9458cfa0ad2SJack F Vogel **/ 9468cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active) 9478cfa0ad2SJack F Vogel { 9488cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 9498cfa0ad2SJack F Vogel s32 ret_val; 9508cfa0ad2SJack F Vogel u16 data; 9518cfa0ad2SJack F Vogel 9528cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d3_lplu_state_82541"); 9538cfa0ad2SJack F Vogel 9548cfa0ad2SJack F Vogel switch (hw->mac.type) { 9558cfa0ad2SJack F Vogel case e1000_82541_rev_2: 9568cfa0ad2SJack F Vogel case e1000_82547_rev_2: 9578cfa0ad2SJack F Vogel break; 9588cfa0ad2SJack F Vogel default: 9598cfa0ad2SJack F Vogel ret_val = e1000_set_d3_lplu_state_generic(hw, active); 9608cfa0ad2SJack F Vogel goto out; 9618cfa0ad2SJack F Vogel break; 9628cfa0ad2SJack F Vogel } 9638cfa0ad2SJack F Vogel 9648cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data); 9658cfa0ad2SJack F Vogel if (ret_val) 9668cfa0ad2SJack F Vogel goto out; 9678cfa0ad2SJack F Vogel 9688cfa0ad2SJack F Vogel if (!active) { 9698cfa0ad2SJack F Vogel data &= ~IGP01E1000_GMII_FLEX_SPD; 9708cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data); 9718cfa0ad2SJack F Vogel if (ret_val) 9728cfa0ad2SJack F Vogel goto out; 9738cfa0ad2SJack F Vogel 9748cfa0ad2SJack F Vogel /* 9758cfa0ad2SJack F Vogel * LPLU and SmartSpeed are mutually exclusive. LPLU is used 9768cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 9778cfa0ad2SJack F Vogel * important. During driver activity we should enable 9788cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 9798cfa0ad2SJack F Vogel */ 9808cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 9818cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 9828cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 9838cfa0ad2SJack F Vogel &data); 9848cfa0ad2SJack F Vogel if (ret_val) 9858cfa0ad2SJack F Vogel goto out; 9868cfa0ad2SJack F Vogel 9878cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 9888cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 9898cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 9908cfa0ad2SJack F Vogel data); 9918cfa0ad2SJack F Vogel if (ret_val) 9928cfa0ad2SJack F Vogel goto out; 9938cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 9948cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 9958cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 9968cfa0ad2SJack F Vogel &data); 9978cfa0ad2SJack F Vogel if (ret_val) 9988cfa0ad2SJack F Vogel goto out; 9998cfa0ad2SJack F Vogel 10008cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 10018cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 10028cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10038cfa0ad2SJack F Vogel data); 10048cfa0ad2SJack F Vogel if (ret_val) 10058cfa0ad2SJack F Vogel goto out; 10068cfa0ad2SJack F Vogel } 10078cfa0ad2SJack F Vogel } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 10088cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 10098cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 10108cfa0ad2SJack F Vogel data |= IGP01E1000_GMII_FLEX_SPD; 10118cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data); 10128cfa0ad2SJack F Vogel if (ret_val) 10138cfa0ad2SJack F Vogel goto out; 10148cfa0ad2SJack F Vogel 10158cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 101648600901SSean Bruno ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, 10178cfa0ad2SJack F Vogel &data); 10188cfa0ad2SJack F Vogel if (ret_val) 10198cfa0ad2SJack F Vogel goto out; 10208cfa0ad2SJack F Vogel 10218cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 102248600901SSean Bruno ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, 10238cfa0ad2SJack F Vogel data); 10248cfa0ad2SJack F Vogel } 10258cfa0ad2SJack F Vogel 10268cfa0ad2SJack F Vogel out: 10278cfa0ad2SJack F Vogel return ret_val; 10288cfa0ad2SJack F Vogel } 10298cfa0ad2SJack F Vogel 10308cfa0ad2SJack F Vogel /** 10318cfa0ad2SJack F Vogel * e1000_setup_led_82541 - Configures SW controllable LED 10328cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 10338cfa0ad2SJack F Vogel * 10348cfa0ad2SJack F Vogel * This prepares the SW controllable LED for use and saves the current state 1035daf9197cSJack F Vogel * of the LED so it can be later restored. 10368cfa0ad2SJack F Vogel **/ 10378cfa0ad2SJack F Vogel static s32 e1000_setup_led_82541(struct e1000_hw *hw) 10388cfa0ad2SJack F Vogel { 1039daf9197cSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 10408cfa0ad2SJack F Vogel s32 ret_val; 10418cfa0ad2SJack F Vogel 10428cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_led_82541"); 10438cfa0ad2SJack F Vogel 104448600901SSean Bruno ret_val = hw->phy.ops.read_reg(hw, IGP01E1000_GMII_FIFO, 10458cfa0ad2SJack F Vogel &dev_spec->spd_default); 10468cfa0ad2SJack F Vogel if (ret_val) 10478cfa0ad2SJack F Vogel goto out; 10488cfa0ad2SJack F Vogel 104948600901SSean Bruno ret_val = hw->phy.ops.write_reg(hw, IGP01E1000_GMII_FIFO, 10508cfa0ad2SJack F Vogel (u16)(dev_spec->spd_default & 10518cfa0ad2SJack F Vogel ~IGP01E1000_GMII_SPD)); 10528cfa0ad2SJack F Vogel if (ret_val) 10538cfa0ad2SJack F Vogel goto out; 10548cfa0ad2SJack F Vogel 10558cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); 10568cfa0ad2SJack F Vogel 10578cfa0ad2SJack F Vogel out: 10588cfa0ad2SJack F Vogel return ret_val; 10598cfa0ad2SJack F Vogel } 10608cfa0ad2SJack F Vogel 10618cfa0ad2SJack F Vogel /** 10628cfa0ad2SJack F Vogel * e1000_cleanup_led_82541 - Set LED config to default operation 10638cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 10648cfa0ad2SJack F Vogel * 10658cfa0ad2SJack F Vogel * Remove the current LED configuration and set the LED configuration 1066daf9197cSJack F Vogel * to the default value, saved from the EEPROM. 10678cfa0ad2SJack F Vogel **/ 10688cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_82541(struct e1000_hw *hw) 10698cfa0ad2SJack F Vogel { 1070daf9197cSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 10718cfa0ad2SJack F Vogel s32 ret_val; 10728cfa0ad2SJack F Vogel 10738cfa0ad2SJack F Vogel DEBUGFUNC("e1000_cleanup_led_82541"); 10748cfa0ad2SJack F Vogel 107548600901SSean Bruno ret_val = hw->phy.ops.write_reg(hw, IGP01E1000_GMII_FIFO, 10768cfa0ad2SJack F Vogel dev_spec->spd_default); 10778cfa0ad2SJack F Vogel if (ret_val) 10788cfa0ad2SJack F Vogel goto out; 10798cfa0ad2SJack F Vogel 10808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); 10818cfa0ad2SJack F Vogel 10828cfa0ad2SJack F Vogel out: 10838cfa0ad2SJack F Vogel return ret_val; 10848cfa0ad2SJack F Vogel } 10858cfa0ad2SJack F Vogel 10868cfa0ad2SJack F Vogel /** 10878cfa0ad2SJack F Vogel * e1000_phy_init_script_82541 - Initialize GbE PHY 10888cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 10898cfa0ad2SJack F Vogel * 10908cfa0ad2SJack F Vogel * Initializes the IGP PHY. 10918cfa0ad2SJack F Vogel **/ 10928cfa0ad2SJack F Vogel static s32 e1000_phy_init_script_82541(struct e1000_hw *hw) 10938cfa0ad2SJack F Vogel { 1094daf9197cSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 10958cfa0ad2SJack F Vogel u32 ret_val; 10968cfa0ad2SJack F Vogel u16 phy_saved_data; 10978cfa0ad2SJack F Vogel 10988cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_init_script_82541"); 10998cfa0ad2SJack F Vogel 11008cfa0ad2SJack F Vogel if (!dev_spec->phy_init_script) { 11018cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 11028cfa0ad2SJack F Vogel goto out; 11038cfa0ad2SJack F Vogel } 11048cfa0ad2SJack F Vogel 11058cfa0ad2SJack F Vogel /* Delay after phy reset to enable NVM configuration to load */ 11068cfa0ad2SJack F Vogel msec_delay(20); 11078cfa0ad2SJack F Vogel 11088cfa0ad2SJack F Vogel /* 11098cfa0ad2SJack F Vogel * Save off the current value of register 0x2F5B to be restored at 11108cfa0ad2SJack F Vogel * the end of this routine. 11118cfa0ad2SJack F Vogel */ 11128cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data); 11138cfa0ad2SJack F Vogel 11148cfa0ad2SJack F Vogel /* Disabled the PHY transmitter */ 11158cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003); 11168cfa0ad2SJack F Vogel 11178cfa0ad2SJack F Vogel msec_delay(20); 11188cfa0ad2SJack F Vogel 11198cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x0000, 0x0140); 11208cfa0ad2SJack F Vogel 11218cfa0ad2SJack F Vogel msec_delay(5); 11228cfa0ad2SJack F Vogel 11238cfa0ad2SJack F Vogel switch (hw->mac.type) { 11248cfa0ad2SJack F Vogel case e1000_82541: 11258cfa0ad2SJack F Vogel case e1000_82547: 11268cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F95, 0x0001); 11278cfa0ad2SJack F Vogel 11288cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21); 11298cfa0ad2SJack F Vogel 11308cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F79, 0x0018); 11318cfa0ad2SJack F Vogel 11328cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F30, 0x1600); 11338cfa0ad2SJack F Vogel 11348cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F31, 0x0014); 11358cfa0ad2SJack F Vogel 11368cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F32, 0x161C); 11378cfa0ad2SJack F Vogel 11388cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F94, 0x0003); 11398cfa0ad2SJack F Vogel 11408cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F96, 0x003F); 11418cfa0ad2SJack F Vogel 11428cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x2010, 0x0008); 11438cfa0ad2SJack F Vogel break; 11448cfa0ad2SJack F Vogel case e1000_82541_rev_2: 11458cfa0ad2SJack F Vogel case e1000_82547_rev_2: 11468cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x1F73, 0x0099); 11478cfa0ad2SJack F Vogel break; 11488cfa0ad2SJack F Vogel default: 11498cfa0ad2SJack F Vogel break; 11508cfa0ad2SJack F Vogel } 11518cfa0ad2SJack F Vogel 11528cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x0000, 0x3300); 11538cfa0ad2SJack F Vogel 11548cfa0ad2SJack F Vogel msec_delay(20); 11558cfa0ad2SJack F Vogel 11568cfa0ad2SJack F Vogel /* Now enable the transmitter */ 11578cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data); 11588cfa0ad2SJack F Vogel 11598cfa0ad2SJack F Vogel if (hw->mac.type == e1000_82547) { 11608cfa0ad2SJack F Vogel u16 fused, fine, coarse; 11618cfa0ad2SJack F Vogel 11628cfa0ad2SJack F Vogel /* Move to analog registers page */ 116348600901SSean Bruno hw->phy.ops.read_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, 11648cfa0ad2SJack F Vogel &fused); 11658cfa0ad2SJack F Vogel 11668cfa0ad2SJack F Vogel if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { 116748600901SSean Bruno hw->phy.ops.read_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, 11688cfa0ad2SJack F Vogel &fused); 11698cfa0ad2SJack F Vogel 11708cfa0ad2SJack F Vogel fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK; 11718cfa0ad2SJack F Vogel coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK; 11728cfa0ad2SJack F Vogel 11738cfa0ad2SJack F Vogel if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) { 11748cfa0ad2SJack F Vogel coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10; 11758cfa0ad2SJack F Vogel fine -= IGP01E1000_ANALOG_FUSE_FINE_1; 11768cfa0ad2SJack F Vogel } else if (coarse == 11778cfa0ad2SJack F Vogel IGP01E1000_ANALOG_FUSE_COARSE_THRESH) 11788cfa0ad2SJack F Vogel fine -= IGP01E1000_ANALOG_FUSE_FINE_10; 11798cfa0ad2SJack F Vogel 11808cfa0ad2SJack F Vogel fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) | 11818cfa0ad2SJack F Vogel (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) | 11828cfa0ad2SJack F Vogel (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK); 11838cfa0ad2SJack F Vogel 11848cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 11858cfa0ad2SJack F Vogel IGP01E1000_ANALOG_FUSE_CONTROL, 11868cfa0ad2SJack F Vogel fused); 11878cfa0ad2SJack F Vogel hw->phy.ops.write_reg(hw, 11888cfa0ad2SJack F Vogel IGP01E1000_ANALOG_FUSE_BYPASS, 11898cfa0ad2SJack F Vogel IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL); 11908cfa0ad2SJack F Vogel } 11918cfa0ad2SJack F Vogel } 11928cfa0ad2SJack F Vogel 11938cfa0ad2SJack F Vogel out: 11948cfa0ad2SJack F Vogel return ret_val; 11958cfa0ad2SJack F Vogel } 11968cfa0ad2SJack F Vogel 11978cfa0ad2SJack F Vogel /** 11988cfa0ad2SJack F Vogel * e1000_init_script_state_82541 - Enable/Disable PHY init script 11998cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 12008cfa0ad2SJack F Vogel * @state: boolean value used to enable/disable PHY init script 12018cfa0ad2SJack F Vogel * 12028cfa0ad2SJack F Vogel * Allows the driver to enable/disable the PHY init script, if the PHY is an 1203daf9197cSJack F Vogel * IGP PHY. 12048cfa0ad2SJack F Vogel **/ 12058cfa0ad2SJack F Vogel void e1000_init_script_state_82541(struct e1000_hw *hw, bool state) 12068cfa0ad2SJack F Vogel { 1207daf9197cSJack F Vogel struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; 12088cfa0ad2SJack F Vogel 12098cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_script_state_82541"); 12108cfa0ad2SJack F Vogel 12118cfa0ad2SJack F Vogel if (hw->phy.type != e1000_phy_igp) { 12128cfa0ad2SJack F Vogel DEBUGOUT("Initialization script not necessary.\n"); 12138cfa0ad2SJack F Vogel goto out; 12148cfa0ad2SJack F Vogel } 12158cfa0ad2SJack F Vogel 12168cfa0ad2SJack F Vogel dev_spec->phy_init_script = state; 12178cfa0ad2SJack F Vogel 12188cfa0ad2SJack F Vogel out: 12198cfa0ad2SJack F Vogel return; 12208cfa0ad2SJack F Vogel } 12218cfa0ad2SJack F Vogel 12228cfa0ad2SJack F Vogel /** 12238cfa0ad2SJack F Vogel * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down 12248cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 12258cfa0ad2SJack F Vogel * 12268cfa0ad2SJack F Vogel * In the case of a PHY power down to save power, or to turn off link during a 12278cfa0ad2SJack F Vogel * driver unload, or wake on lan is not enabled, remove the link. 12288cfa0ad2SJack F Vogel **/ 12298cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw) 12308cfa0ad2SJack F Vogel { 12318cfa0ad2SJack F Vogel /* If the management interface is not enabled, then power down */ 12328cfa0ad2SJack F Vogel if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN)) 12338cfa0ad2SJack F Vogel e1000_power_down_phy_copper(hw); 12348cfa0ad2SJack F Vogel 12358cfa0ad2SJack F Vogel return; 12368cfa0ad2SJack F Vogel } 12378cfa0ad2SJack F Vogel 12388cfa0ad2SJack F Vogel /** 12398cfa0ad2SJack F Vogel * e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters 12408cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 12418cfa0ad2SJack F Vogel * 12428cfa0ad2SJack F Vogel * Clears the hardware counters by reading the counter registers. 12438cfa0ad2SJack F Vogel **/ 12448cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw) 12458cfa0ad2SJack F Vogel { 12468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_clear_hw_cntrs_82541"); 12478cfa0ad2SJack F Vogel 12488cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_base_generic(hw); 12498cfa0ad2SJack F Vogel 1250daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PRC64); 1251daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PRC127); 1252daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PRC255); 1253daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PRC511); 1254daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PRC1023); 1255daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PRC1522); 1256daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PTC64); 1257daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PTC127); 1258daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PTC255); 1259daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PTC511); 1260daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PTC1023); 1261daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_PTC1522); 12628cfa0ad2SJack F Vogel 1263daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ALGNERRC); 1264daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_RXERRC); 1265daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TNCRS); 1266daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_CEXTERR); 1267daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTC); 1268daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTFC); 12698cfa0ad2SJack F Vogel 1270daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPRC); 1271daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPDC); 1272daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPTC); 12738cfa0ad2SJack F Vogel } 12744edd8523SJack F Vogel 12754edd8523SJack F Vogel /** 12764edd8523SJack F Vogel * e1000_read_mac_addr_82541 - Read device MAC address 12774edd8523SJack F Vogel * @hw: pointer to the HW structure 12784edd8523SJack F Vogel * 12794edd8523SJack F Vogel * Reads the device MAC address from the EEPROM and stores the value. 12804edd8523SJack F Vogel **/ 12814edd8523SJack F Vogel static s32 e1000_read_mac_addr_82541(struct e1000_hw *hw) 12824edd8523SJack F Vogel { 12834edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 12844edd8523SJack F Vogel u16 offset, nvm_data, i; 12854edd8523SJack F Vogel 12864edd8523SJack F Vogel DEBUGFUNC("e1000_read_mac_addr"); 12874edd8523SJack F Vogel 1288e81998f4SEric Joyner for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 12894edd8523SJack F Vogel offset = i >> 1; 12904edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); 12914edd8523SJack F Vogel if (ret_val) { 12924edd8523SJack F Vogel DEBUGOUT("NVM Read Error\n"); 12934edd8523SJack F Vogel goto out; 12944edd8523SJack F Vogel } 12954edd8523SJack F Vogel hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); 12964edd8523SJack F Vogel hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); 12974edd8523SJack F Vogel } 12984edd8523SJack F Vogel 1299e81998f4SEric Joyner for (i = 0; i < ETHER_ADDR_LEN; i++) 13004edd8523SJack F Vogel hw->mac.addr[i] = hw->mac.perm_addr[i]; 13014edd8523SJack F Vogel 13024edd8523SJack F Vogel out: 13034edd8523SJack F Vogel return ret_val; 13044edd8523SJack F Vogel } 13054edd8523SJack F Vogel 1306