18cfa0ad2SJack F Vogel /****************************************************************************** 28cfa0ad2SJack F Vogel 3*4dab5c37SJack F Vogel Copyright (c) 2001-2011, Intel Corporation 48cfa0ad2SJack F Vogel All rights reserved. 58cfa0ad2SJack F Vogel 68cfa0ad2SJack F Vogel Redistribution and use in source and binary forms, with or without 78cfa0ad2SJack F Vogel modification, are permitted provided that the following conditions are met: 88cfa0ad2SJack F Vogel 98cfa0ad2SJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 108cfa0ad2SJack F Vogel this list of conditions and the following disclaimer. 118cfa0ad2SJack F Vogel 128cfa0ad2SJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 138cfa0ad2SJack F Vogel notice, this list of conditions and the following disclaimer in the 148cfa0ad2SJack F Vogel documentation and/or other materials provided with the distribution. 158cfa0ad2SJack F Vogel 168cfa0ad2SJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 178cfa0ad2SJack F Vogel contributors may be used to endorse or promote products derived from 188cfa0ad2SJack F Vogel this software without specific prior written permission. 198cfa0ad2SJack F Vogel 208cfa0ad2SJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 218cfa0ad2SJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228cfa0ad2SJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238cfa0ad2SJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 248cfa0ad2SJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 258cfa0ad2SJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 268cfa0ad2SJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 278cfa0ad2SJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 288cfa0ad2SJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 298cfa0ad2SJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 308cfa0ad2SJack F Vogel POSSIBILITY OF SUCH DAMAGE. 318cfa0ad2SJack F Vogel 328cfa0ad2SJack F Vogel ******************************************************************************/ 338cfa0ad2SJack F Vogel /*$FreeBSD$*/ 348cfa0ad2SJack F Vogel 35daf9197cSJack F Vogel /* 36daf9197cSJack F Vogel * 82562G 10/100 Network Connection 37daf9197cSJack F Vogel * 82562G-2 10/100 Network Connection 38daf9197cSJack F Vogel * 82562GT 10/100 Network Connection 39daf9197cSJack F Vogel * 82562GT-2 10/100 Network Connection 40daf9197cSJack F Vogel * 82562V 10/100 Network Connection 41daf9197cSJack F Vogel * 82562V-2 10/100 Network Connection 42daf9197cSJack F Vogel * 82566DC-2 Gigabit Network Connection 43daf9197cSJack F Vogel * 82566DC Gigabit Network Connection 44daf9197cSJack F Vogel * 82566DM-2 Gigabit Network Connection 45daf9197cSJack F Vogel * 82566DM Gigabit Network Connection 46daf9197cSJack F Vogel * 82566MC Gigabit Network Connection 47daf9197cSJack F Vogel * 82566MM Gigabit Network Connection 48daf9197cSJack F Vogel * 82567LM Gigabit Network Connection 49daf9197cSJack F Vogel * 82567LF Gigabit Network Connection 50daf9197cSJack F Vogel * 82567V Gigabit Network Connection 51daf9197cSJack F Vogel * 82567LM-2 Gigabit Network Connection 52daf9197cSJack F Vogel * 82567LF-2 Gigabit Network Connection 53daf9197cSJack F Vogel * 82567V-2 Gigabit Network Connection 54daf9197cSJack F Vogel * 82567LF-3 Gigabit Network Connection 55daf9197cSJack F Vogel * 82567LM-3 Gigabit Network Connection 56daf9197cSJack F Vogel * 82567LM-4 Gigabit Network Connection 579d81738fSJack F Vogel * 82577LM Gigabit Network Connection 589d81738fSJack F Vogel * 82577LC Gigabit Network Connection 599d81738fSJack F Vogel * 82578DM Gigabit Network Connection 609d81738fSJack F Vogel * 82578DC Gigabit Network Connection 617d9119bdSJack F Vogel * 82579LM Gigabit Network Connection 627d9119bdSJack F Vogel * 82579V Gigabit Network Connection 638cfa0ad2SJack F Vogel */ 648cfa0ad2SJack F Vogel 658cfa0ad2SJack F Vogel #include "e1000_api.h" 668cfa0ad2SJack F Vogel 678cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw); 689d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw); 698cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw); 708cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw); 718cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); 728cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); 734edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); 744edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw); 758cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); 767d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw); 777d9119bdSJack F Vogel static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); 78730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw, 79730d3130SJack F Vogel u8 *mc_addr_list, 80730d3130SJack F Vogel u32 mc_addr_count); 818cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); 828cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); 834edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); 848cfa0ad2SJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, 858cfa0ad2SJack F Vogel bool active); 868cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, 878cfa0ad2SJack F Vogel bool active); 888cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 898cfa0ad2SJack F Vogel u16 words, u16 *data); 908cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 918cfa0ad2SJack F Vogel u16 words, u16 *data); 928cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); 938cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); 948cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, 958cfa0ad2SJack F Vogel u16 *data); 969d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); 978cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); 988cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); 998cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); 1008cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); 1018cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); 1028cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, 1038cfa0ad2SJack F Vogel u16 *speed, u16 *duplex); 1048cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); 1058cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); 1068cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); 1074edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); 1089d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); 1099d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); 1109d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw); 1119d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw); 1128cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); 1138cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); 1148cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); 1158cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw); 1168cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); 1178cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); 1188cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, 1198cfa0ad2SJack F Vogel u32 offset, u8 *data); 1208cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1218cfa0ad2SJack F Vogel u8 size, u16 *data); 1228cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, 1238cfa0ad2SJack F Vogel u32 offset, u16 *data); 1248cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 1258cfa0ad2SJack F Vogel u32 offset, u8 byte); 1268cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, 1278cfa0ad2SJack F Vogel u32 offset, u8 data); 1288cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1298cfa0ad2SJack F Vogel u8 size, u16 data); 1308cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); 1318cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); 1324edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); 1334edd8523SJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); 1344edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw); 135a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); 1367d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); 1377d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); 138*4dab5c37SJack F Vogel #if defined(NAHUM6_HW) && (defined(LTR_SUPPORT) || defined(OBFF_SUPPORT)) 139*4dab5c37SJack F Vogel 140*4dab5c37SJack F Vogel #endif /* NAHUM6_HW && (LTR_SUPPORT || OBFF_SUPPORT) */ 1418cfa0ad2SJack F Vogel 1428cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ 1438cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */ 1448cfa0ad2SJack F Vogel union ich8_hws_flash_status { 1458cfa0ad2SJack F Vogel struct ich8_hsfsts { 1468cfa0ad2SJack F Vogel u16 flcdone:1; /* bit 0 Flash Cycle Done */ 1478cfa0ad2SJack F Vogel u16 flcerr:1; /* bit 1 Flash Cycle Error */ 1488cfa0ad2SJack F Vogel u16 dael:1; /* bit 2 Direct Access error Log */ 1498cfa0ad2SJack F Vogel u16 berasesz:2; /* bit 4:3 Sector Erase Size */ 1508cfa0ad2SJack F Vogel u16 flcinprog:1; /* bit 5 flash cycle in Progress */ 1518cfa0ad2SJack F Vogel u16 reserved1:2; /* bit 13:6 Reserved */ 1528cfa0ad2SJack F Vogel u16 reserved2:6; /* bit 13:6 Reserved */ 1538cfa0ad2SJack F Vogel u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */ 1548cfa0ad2SJack F Vogel u16 flockdn:1; /* bit 15 Flash Config Lock-Down */ 1558cfa0ad2SJack F Vogel } hsf_status; 1568cfa0ad2SJack F Vogel u16 regval; 1578cfa0ad2SJack F Vogel }; 1588cfa0ad2SJack F Vogel 1598cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ 1608cfa0ad2SJack F Vogel /* Offset 06h FLCTL */ 1618cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl { 1628cfa0ad2SJack F Vogel struct ich8_hsflctl { 1638cfa0ad2SJack F Vogel u16 flcgo:1; /* 0 Flash Cycle Go */ 1648cfa0ad2SJack F Vogel u16 flcycle:2; /* 2:1 Flash Cycle */ 1658cfa0ad2SJack F Vogel u16 reserved:5; /* 7:3 Reserved */ 1668cfa0ad2SJack F Vogel u16 fldbcount:2; /* 9:8 Flash Data Byte Count */ 1678cfa0ad2SJack F Vogel u16 flockdn:6; /* 15:10 Reserved */ 1688cfa0ad2SJack F Vogel } hsf_ctrl; 1698cfa0ad2SJack F Vogel u16 regval; 1708cfa0ad2SJack F Vogel }; 1718cfa0ad2SJack F Vogel 1728cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */ 1738cfa0ad2SJack F Vogel union ich8_hws_flash_regacc { 1748cfa0ad2SJack F Vogel struct ich8_flracc { 1758cfa0ad2SJack F Vogel u32 grra:8; /* 0:7 GbE region Read Access */ 1768cfa0ad2SJack F Vogel u32 grwa:8; /* 8:15 GbE region Write Access */ 1778cfa0ad2SJack F Vogel u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */ 1788cfa0ad2SJack F Vogel u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */ 1798cfa0ad2SJack F Vogel } hsf_flregacc; 1808cfa0ad2SJack F Vogel u16 regval; 1818cfa0ad2SJack F Vogel }; 1828cfa0ad2SJack F Vogel 183*4dab5c37SJack F Vogel static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw) 184*4dab5c37SJack F Vogel { 185*4dab5c37SJack F Vogel u32 ctrl; 186*4dab5c37SJack F Vogel 187*4dab5c37SJack F Vogel DEBUGFUNC("e1000_toggle_lanphypc_value_ich8lan"); 188*4dab5c37SJack F Vogel 189*4dab5c37SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 190*4dab5c37SJack F Vogel ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; 191*4dab5c37SJack F Vogel ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; 192*4dab5c37SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 193*4dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 194*4dab5c37SJack F Vogel usec_delay(10); 195*4dab5c37SJack F Vogel ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; 196*4dab5c37SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 197*4dab5c37SJack F Vogel } 198*4dab5c37SJack F Vogel 1998cfa0ad2SJack F Vogel /** 2009d81738fSJack F Vogel * e1000_init_phy_params_pchlan - Initialize PHY function pointers 2019d81738fSJack F Vogel * @hw: pointer to the HW structure 2029d81738fSJack F Vogel * 2039d81738fSJack F Vogel * Initialize family-specific PHY parameters and function pointers. 2049d81738fSJack F Vogel **/ 2059d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 2069d81738fSJack F Vogel { 2079d81738fSJack F Vogel struct e1000_phy_info *phy = &hw->phy; 2089d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS; 2099d81738fSJack F Vogel 2109d81738fSJack F Vogel DEBUGFUNC("e1000_init_phy_params_pchlan"); 2119d81738fSJack F Vogel 2129d81738fSJack F Vogel phy->addr = 1; 2139d81738fSJack F Vogel phy->reset_delay_us = 100; 2149d81738fSJack F Vogel 2159d81738fSJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 2169d81738fSJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 2179d81738fSJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 218*4dab5c37SJack F Vogel phy->ops.set_page = e1000_set_page_igp; 2199d81738fSJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_hv; 2204edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; 221*4dab5c37SJack F Vogel phy->ops.read_reg_page = e1000_read_phy_reg_page_hv; 2229d81738fSJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 2239d81738fSJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 2244edd8523SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; 2254edd8523SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; 2269d81738fSJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_hv; 2274edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; 228*4dab5c37SJack F Vogel phy->ops.write_reg_page = e1000_write_phy_reg_page_hv; 2299d81738fSJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 2309d81738fSJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 2319d81738fSJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 2329d81738fSJack F Vogel 233*4dab5c37SJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) { 234*4dab5c37SJack F Vogel u32 fwsm = E1000_READ_REG(hw, E1000_FWSM); 235*4dab5c37SJack F Vogel 2368ec87fc5SJack F Vogel /* 237*4dab5c37SJack F Vogel * The MAC-PHY interconnect may still be in SMBus mode after 238*4dab5c37SJack F Vogel * Sx->S0. If resetting the PHY is not blocked, toggle the 239*4dab5c37SJack F Vogel * LANPHYPC Value bit to force the interconnect to PCIe mode. 2408ec87fc5SJack F Vogel */ 241*4dab5c37SJack F Vogel e1000_toggle_lanphypc_value_ich8lan(hw); 2428ec87fc5SJack F Vogel msec_delay(50); 2437d9119bdSJack F Vogel 2447d9119bdSJack F Vogel /* 2457d9119bdSJack F Vogel * Gate automatic PHY configuration by hardware on 2467d9119bdSJack F Vogel * non-managed 82579 2477d9119bdSJack F Vogel */ 248*4dab5c37SJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 249*4dab5c37SJack F Vogel !(fwsm & E1000_ICH_FWSM_FW_VALID)) 2507d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 2518ec87fc5SJack F Vogel 2528ec87fc5SJack F Vogel /* 253*4dab5c37SJack F Vogel * Reset the PHY before any access to it. Doing so, ensures 254*4dab5c37SJack F Vogel * that the PHY is in a known good state before we read/write 255*4dab5c37SJack F Vogel * PHY registers. The generic reset is sufficient here, 256*4dab5c37SJack F Vogel * because we haven't determined the PHY type yet. 2578ec87fc5SJack F Vogel */ 2588ec87fc5SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 2598ec87fc5SJack F Vogel if (ret_val) 2608ec87fc5SJack F Vogel goto out; 2618ec87fc5SJack F Vogel 2627d9119bdSJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */ 2637d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 2647d9119bdSJack F Vogel !(fwsm & E1000_ICH_FWSM_FW_VALID)) { 2657d9119bdSJack F Vogel msec_delay(10); 2667d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, FALSE); 2677d9119bdSJack F Vogel } 268*4dab5c37SJack F Vogel } 2697d9119bdSJack F Vogel 2709d81738fSJack F Vogel phy->id = e1000_phy_unknown; 2717d9119bdSJack F Vogel switch (hw->mac.type) { 2727d9119bdSJack F Vogel default: 273a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw); 274a69ed8dfSJack F Vogel if (ret_val) 275a69ed8dfSJack F Vogel goto out; 2767d9119bdSJack F Vogel if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) 2777d9119bdSJack F Vogel break; 2787d9119bdSJack F Vogel /* fall-through */ 2797d9119bdSJack F Vogel case e1000_pch2lan: 280a69ed8dfSJack F Vogel /* 2817d9119bdSJack F Vogel * In case the PHY needs to be in mdio slow mode, 282a69ed8dfSJack F Vogel * set slow mode and try to get the PHY id again. 283a69ed8dfSJack F Vogel */ 284a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 285a69ed8dfSJack F Vogel if (ret_val) 286a69ed8dfSJack F Vogel goto out; 287a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw); 288a69ed8dfSJack F Vogel if (ret_val) 289a69ed8dfSJack F Vogel goto out; 2907d9119bdSJack F Vogel break; 291a69ed8dfSJack F Vogel } 2929d81738fSJack F Vogel phy->type = e1000_get_phy_type_from_id(phy->id); 2939d81738fSJack F Vogel 2944edd8523SJack F Vogel switch (phy->type) { 2954edd8523SJack F Vogel case e1000_phy_82577: 2967d9119bdSJack F Vogel case e1000_phy_82579: 2979d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_82577; 2989d81738fSJack F Vogel phy->ops.force_speed_duplex = 2999d81738fSJack F Vogel e1000_phy_force_speed_duplex_82577; 3009d81738fSJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_82577; 3019d81738fSJack F Vogel phy->ops.get_info = e1000_get_phy_info_82577; 3029d81738fSJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 3038ec87fc5SJack F Vogel break; 3044edd8523SJack F Vogel case e1000_phy_82578: 3054edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88; 3064edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 3074edd8523SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_m88; 3084edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88; 3094edd8523SJack F Vogel break; 3104edd8523SJack F Vogel default: 3114edd8523SJack F Vogel ret_val = -E1000_ERR_PHY; 3124edd8523SJack F Vogel break; 3139d81738fSJack F Vogel } 3149d81738fSJack F Vogel 315a69ed8dfSJack F Vogel out: 3169d81738fSJack F Vogel return ret_val; 3179d81738fSJack F Vogel } 3189d81738fSJack F Vogel 3199d81738fSJack F Vogel /** 3208cfa0ad2SJack F Vogel * e1000_init_phy_params_ich8lan - Initialize PHY function pointers 3218cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 3228cfa0ad2SJack F Vogel * 3238cfa0ad2SJack F Vogel * Initialize family-specific PHY parameters and function pointers. 3248cfa0ad2SJack F Vogel **/ 3258cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) 3268cfa0ad2SJack F Vogel { 3278cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 3288cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 3298cfa0ad2SJack F Vogel u16 i = 0; 3308cfa0ad2SJack F Vogel 3318cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_phy_params_ich8lan"); 3328cfa0ad2SJack F Vogel 3338cfa0ad2SJack F Vogel phy->addr = 1; 3348cfa0ad2SJack F Vogel phy->reset_delay_us = 100; 3358cfa0ad2SJack F Vogel 3368cfa0ad2SJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 3378cfa0ad2SJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 3388cfa0ad2SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_2; 3398cfa0ad2SJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 3408cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_igp; 3418cfa0ad2SJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 3428cfa0ad2SJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 3438cfa0ad2SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; 3448cfa0ad2SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; 3458cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_igp; 3468cfa0ad2SJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 3478cfa0ad2SJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 3488cfa0ad2SJack F Vogel 3498cfa0ad2SJack F Vogel /* 3508cfa0ad2SJack F Vogel * We may need to do this twice - once for IGP and if that fails, 3518cfa0ad2SJack F Vogel * we'll set BM func pointers and try again 3528cfa0ad2SJack F Vogel */ 3538cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 3548cfa0ad2SJack F Vogel if (ret_val) { 3558cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 3568cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 3578cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 3588cfa0ad2SJack F Vogel if (ret_val) { 359d035aa2dSJack F Vogel DEBUGOUT("Cannot determine PHY addr. Erroring out\n"); 3608cfa0ad2SJack F Vogel goto out; 3618cfa0ad2SJack F Vogel } 3628cfa0ad2SJack F Vogel } 3638cfa0ad2SJack F Vogel 3648cfa0ad2SJack F Vogel phy->id = 0; 3658cfa0ad2SJack F Vogel while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) && 3668cfa0ad2SJack F Vogel (i++ < 100)) { 3678cfa0ad2SJack F Vogel msec_delay(1); 3688cfa0ad2SJack F Vogel ret_val = e1000_get_phy_id(hw); 3698cfa0ad2SJack F Vogel if (ret_val) 3708cfa0ad2SJack F Vogel goto out; 3718cfa0ad2SJack F Vogel } 3728cfa0ad2SJack F Vogel 3738cfa0ad2SJack F Vogel /* Verify phy id */ 3748cfa0ad2SJack F Vogel switch (phy->id) { 3758cfa0ad2SJack F Vogel case IGP03E1000_E_PHY_ID: 3768cfa0ad2SJack F Vogel phy->type = e1000_phy_igp_3; 3778cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 3784edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked; 3794edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked; 3804edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_igp; 3814edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_igp; 3824edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; 3838cfa0ad2SJack F Vogel break; 3848cfa0ad2SJack F Vogel case IFE_E_PHY_ID: 3858cfa0ad2SJack F Vogel case IFE_PLUS_E_PHY_ID: 3868cfa0ad2SJack F Vogel case IFE_C_E_PHY_ID: 3878cfa0ad2SJack F Vogel phy->type = e1000_phy_ife; 3888cfa0ad2SJack F Vogel phy->autoneg_mask = E1000_ALL_NOT_GIG; 3894edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_ife; 3904edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_ife; 3914edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; 3928cfa0ad2SJack F Vogel break; 3938cfa0ad2SJack F Vogel case BME1000_E_PHY_ID: 3948cfa0ad2SJack F Vogel phy->type = e1000_phy_bm; 3958cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 3968cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 3978cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 3988cfa0ad2SJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 3994edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88; 4004edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88; 4014edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 4028cfa0ad2SJack F Vogel break; 4038cfa0ad2SJack F Vogel default: 4048cfa0ad2SJack F Vogel ret_val = -E1000_ERR_PHY; 4058cfa0ad2SJack F Vogel goto out; 4068cfa0ad2SJack F Vogel } 4078cfa0ad2SJack F Vogel 4088cfa0ad2SJack F Vogel out: 4098cfa0ad2SJack F Vogel return ret_val; 4108cfa0ad2SJack F Vogel } 4118cfa0ad2SJack F Vogel 4128cfa0ad2SJack F Vogel /** 4138cfa0ad2SJack F Vogel * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers 4148cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 4158cfa0ad2SJack F Vogel * 4168cfa0ad2SJack F Vogel * Initialize family-specific NVM parameters and function 4178cfa0ad2SJack F Vogel * pointers. 4188cfa0ad2SJack F Vogel **/ 4198cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) 4208cfa0ad2SJack F Vogel { 4218cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 422daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 4238cfa0ad2SJack F Vogel u32 gfpreg, sector_base_addr, sector_end_addr; 4248cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 4258cfa0ad2SJack F Vogel u16 i; 4268cfa0ad2SJack F Vogel 4278cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_ich8lan"); 4288cfa0ad2SJack F Vogel 4298cfa0ad2SJack F Vogel /* Can't read flash registers if the register set isn't mapped. */ 4308cfa0ad2SJack F Vogel if (!hw->flash_address) { 4318cfa0ad2SJack F Vogel DEBUGOUT("ERROR: Flash registers not mapped\n"); 4328cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 4338cfa0ad2SJack F Vogel goto out; 4348cfa0ad2SJack F Vogel } 4358cfa0ad2SJack F Vogel 4368cfa0ad2SJack F Vogel nvm->type = e1000_nvm_flash_sw; 4378cfa0ad2SJack F Vogel 4388cfa0ad2SJack F Vogel gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); 4398cfa0ad2SJack F Vogel 4408cfa0ad2SJack F Vogel /* 4418cfa0ad2SJack F Vogel * sector_X_addr is a "sector"-aligned address (4096 bytes) 4428cfa0ad2SJack F Vogel * Add 1 to sector_end_addr since this sector is included in 4438cfa0ad2SJack F Vogel * the overall size. 4448cfa0ad2SJack F Vogel */ 4458cfa0ad2SJack F Vogel sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 4468cfa0ad2SJack F Vogel sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; 4478cfa0ad2SJack F Vogel 4488cfa0ad2SJack F Vogel /* flash_base_addr is byte-aligned */ 4498cfa0ad2SJack F Vogel nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; 4508cfa0ad2SJack F Vogel 4518cfa0ad2SJack F Vogel /* 4528cfa0ad2SJack F Vogel * find total size of the NVM, then cut in half since the total 4538cfa0ad2SJack F Vogel * size represents two separate NVM banks. 4548cfa0ad2SJack F Vogel */ 4558cfa0ad2SJack F Vogel nvm->flash_bank_size = (sector_end_addr - sector_base_addr) 4568cfa0ad2SJack F Vogel << FLASH_SECTOR_ADDR_SHIFT; 4578cfa0ad2SJack F Vogel nvm->flash_bank_size /= 2; 4588cfa0ad2SJack F Vogel /* Adjust to word count */ 4598cfa0ad2SJack F Vogel nvm->flash_bank_size /= sizeof(u16); 4608cfa0ad2SJack F Vogel 4618cfa0ad2SJack F Vogel nvm->word_size = E1000_SHADOW_RAM_WORDS; 4628cfa0ad2SJack F Vogel 4638cfa0ad2SJack F Vogel /* Clear shadow ram */ 4648cfa0ad2SJack F Vogel for (i = 0; i < nvm->word_size; i++) { 4658cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 4668cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 4678cfa0ad2SJack F Vogel } 4688cfa0ad2SJack F Vogel 4694edd8523SJack F Vogel E1000_MUTEX_INIT(&dev_spec->nvm_mutex); 4704edd8523SJack F Vogel E1000_MUTEX_INIT(&dev_spec->swflag_mutex); 4714edd8523SJack F Vogel 4728cfa0ad2SJack F Vogel /* Function Pointers */ 4734edd8523SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_ich8lan; 4744edd8523SJack F Vogel nvm->ops.release = e1000_release_nvm_ich8lan; 4758cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_ich8lan; 4768cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_ich8lan; 4778cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; 4788cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; 4798cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_ich8lan; 4808cfa0ad2SJack F Vogel 4818cfa0ad2SJack F Vogel out: 4828cfa0ad2SJack F Vogel return ret_val; 4838cfa0ad2SJack F Vogel } 4848cfa0ad2SJack F Vogel 4858cfa0ad2SJack F Vogel /** 4868cfa0ad2SJack F Vogel * e1000_init_mac_params_ich8lan - Initialize MAC function pointers 4878cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 4888cfa0ad2SJack F Vogel * 4898cfa0ad2SJack F Vogel * Initialize family-specific MAC parameters and function 4908cfa0ad2SJack F Vogel * pointers. 4918cfa0ad2SJack F Vogel **/ 4928cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) 4938cfa0ad2SJack F Vogel { 4948cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 4958cfa0ad2SJack F Vogel 4968cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_mac_params_ich8lan"); 4978cfa0ad2SJack F Vogel 4988cfa0ad2SJack F Vogel /* Set media type function pointer */ 4998cfa0ad2SJack F Vogel hw->phy.media_type = e1000_media_type_copper; 5008cfa0ad2SJack F Vogel 5018cfa0ad2SJack F Vogel /* Set mta register count */ 5028cfa0ad2SJack F Vogel mac->mta_reg_count = 32; 5038cfa0ad2SJack F Vogel /* Set rar entry count */ 5048cfa0ad2SJack F Vogel mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; 5058cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 5068cfa0ad2SJack F Vogel mac->rar_entry_count--; 5078cfa0ad2SJack F Vogel /* Set if part includes ASF firmware */ 5088cfa0ad2SJack F Vogel mac->asf_firmware_present = TRUE; 5098ec87fc5SJack F Vogel /* FWSM register */ 5108ec87fc5SJack F Vogel mac->has_fwsm = TRUE; 5118ec87fc5SJack F Vogel /* ARC subsystem not supported */ 5128ec87fc5SJack F Vogel mac->arc_subsystem_valid = FALSE; 5134edd8523SJack F Vogel /* Adaptive IFS supported */ 5144edd8523SJack F Vogel mac->adaptive_ifs = TRUE; 5158cfa0ad2SJack F Vogel 5168cfa0ad2SJack F Vogel /* Function pointers */ 5178cfa0ad2SJack F Vogel 5188cfa0ad2SJack F Vogel /* bus type/speed/width */ 5198cfa0ad2SJack F Vogel mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; 520daf9197cSJack F Vogel /* function id */ 521daf9197cSJack F Vogel mac->ops.set_lan_id = e1000_set_lan_id_single_port; 5228cfa0ad2SJack F Vogel /* reset */ 5238cfa0ad2SJack F Vogel mac->ops.reset_hw = e1000_reset_hw_ich8lan; 5248cfa0ad2SJack F Vogel /* hw initialization */ 5258cfa0ad2SJack F Vogel mac->ops.init_hw = e1000_init_hw_ich8lan; 5268cfa0ad2SJack F Vogel /* link setup */ 5278cfa0ad2SJack F Vogel mac->ops.setup_link = e1000_setup_link_ich8lan; 5288cfa0ad2SJack F Vogel /* physical interface setup */ 5298cfa0ad2SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; 5308cfa0ad2SJack F Vogel /* check for link */ 5314edd8523SJack F Vogel mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan; 5328cfa0ad2SJack F Vogel /* link info */ 5338cfa0ad2SJack F Vogel mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; 5348cfa0ad2SJack F Vogel /* multicast address update */ 5358cfa0ad2SJack F Vogel mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; 536d035aa2dSJack F Vogel /* clear hardware counters */ 537d035aa2dSJack F Vogel mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; 538d035aa2dSJack F Vogel 539d035aa2dSJack F Vogel /* LED operations */ 540d035aa2dSJack F Vogel switch (mac->type) { 541d035aa2dSJack F Vogel case e1000_ich8lan: 542d035aa2dSJack F Vogel case e1000_ich9lan: 543d035aa2dSJack F Vogel case e1000_ich10lan: 5447d9119bdSJack F Vogel /* check management mode */ 5457d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; 546d035aa2dSJack F Vogel /* ID LED init */ 547d035aa2dSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_generic; 5488cfa0ad2SJack F Vogel /* blink LED */ 5498cfa0ad2SJack F Vogel mac->ops.blink_led = e1000_blink_led_generic; 5508cfa0ad2SJack F Vogel /* setup LED */ 5518cfa0ad2SJack F Vogel mac->ops.setup_led = e1000_setup_led_generic; 5528cfa0ad2SJack F Vogel /* cleanup LED */ 5538cfa0ad2SJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; 5548cfa0ad2SJack F Vogel /* turn on/off LED */ 5558cfa0ad2SJack F Vogel mac->ops.led_on = e1000_led_on_ich8lan; 5568cfa0ad2SJack F Vogel mac->ops.led_off = e1000_led_off_ich8lan; 557d035aa2dSJack F Vogel break; 5587d9119bdSJack F Vogel case e1000_pch2lan: 5597d9119bdSJack F Vogel mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES; 5607d9119bdSJack F Vogel mac->ops.rar_set = e1000_rar_set_pch2lan; 561730d3130SJack F Vogel /* multicast address update for pch2 */ 562730d3130SJack F Vogel mac->ops.update_mc_addr_list = 563730d3130SJack F Vogel e1000_update_mc_addr_list_pch2lan; 5647d9119bdSJack F Vogel /* fall-through */ 5659d81738fSJack F Vogel case e1000_pchlan: 5667d9119bdSJack F Vogel /* check management mode */ 5677d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; 5689d81738fSJack F Vogel /* ID LED init */ 5699d81738fSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_pchlan; 5709d81738fSJack F Vogel /* setup LED */ 5719d81738fSJack F Vogel mac->ops.setup_led = e1000_setup_led_pchlan; 5729d81738fSJack F Vogel /* cleanup LED */ 5739d81738fSJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_pchlan; 5749d81738fSJack F Vogel /* turn on/off LED */ 5759d81738fSJack F Vogel mac->ops.led_on = e1000_led_on_pchlan; 5769d81738fSJack F Vogel mac->ops.led_off = e1000_led_off_pchlan; 5779d81738fSJack F Vogel break; 578d035aa2dSJack F Vogel default: 579d035aa2dSJack F Vogel break; 580d035aa2dSJack F Vogel } 5818cfa0ad2SJack F Vogel 582*4dab5c37SJack F Vogel #if defined(NAHUM6_HW) && (defined(LTR_SUPPORT) || defined(OBFF_SUPPORT)) 583*4dab5c37SJack F Vogel if (mac->type == e1000_pch_lpt) { 584*4dab5c37SJack F Vogel } 585*4dab5c37SJack F Vogel 586*4dab5c37SJack F Vogel #endif /* NAHUM6_HW && (LTR_SUPPORT || OBFF_SUPPORT) */ 5878cfa0ad2SJack F Vogel /* Enable PCS Lock-loss workaround for ICH8 */ 5888cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 5898cfa0ad2SJack F Vogel e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE); 5908cfa0ad2SJack F Vogel 5917d9119bdSJack F Vogel /* Gate automatic PHY configuration by hardware on managed 82579 */ 5927d9119bdSJack F Vogel if ((mac->type == e1000_pch2lan) && 5937d9119bdSJack F Vogel (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 5947d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 5957d9119bdSJack F Vogel 596daf9197cSJack F Vogel return E1000_SUCCESS; 5978cfa0ad2SJack F Vogel } 5988cfa0ad2SJack F Vogel 5998cfa0ad2SJack F Vogel /** 6007d9119bdSJack F Vogel * e1000_set_eee_pchlan - Enable/disable EEE support 6017d9119bdSJack F Vogel * @hw: pointer to the HW structure 6027d9119bdSJack F Vogel * 6037d9119bdSJack F Vogel * Enable/disable EEE based on setting in dev_spec structure. The bits in 6047d9119bdSJack F Vogel * the LPI Control register will remain set only if/when link is up. 6057d9119bdSJack F Vogel **/ 6067d9119bdSJack F Vogel static s32 e1000_set_eee_pchlan(struct e1000_hw *hw) 6077d9119bdSJack F Vogel { 608*4dab5c37SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 6097d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 6107d9119bdSJack F Vogel u16 phy_reg; 6117d9119bdSJack F Vogel 6127d9119bdSJack F Vogel DEBUGFUNC("e1000_set_eee_pchlan"); 6137d9119bdSJack F Vogel 6147d9119bdSJack F Vogel if (hw->phy.type != e1000_phy_82579) 6157d9119bdSJack F Vogel goto out; 6167d9119bdSJack F Vogel 6177d9119bdSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg); 6187d9119bdSJack F Vogel if (ret_val) 6197d9119bdSJack F Vogel goto out; 6207d9119bdSJack F Vogel 621*4dab5c37SJack F Vogel if (dev_spec->eee_disable) 6227d9119bdSJack F Vogel phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK; 6237d9119bdSJack F Vogel else 6247d9119bdSJack F Vogel phy_reg |= I82579_LPI_CTRL_ENABLE_MASK; 6257d9119bdSJack F Vogel 6267d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg); 6277d9119bdSJack F Vogel out: 6287d9119bdSJack F Vogel return ret_val; 6297d9119bdSJack F Vogel } 6307d9119bdSJack F Vogel 6317d9119bdSJack F Vogel /** 6324edd8523SJack F Vogel * e1000_check_for_copper_link_ich8lan - Check for link (Copper) 6334edd8523SJack F Vogel * @hw: pointer to the HW structure 6344edd8523SJack F Vogel * 6354edd8523SJack F Vogel * Checks to see of the link status of the hardware has changed. If a 6364edd8523SJack F Vogel * change in link status has been detected, then we read the PHY registers 6374edd8523SJack F Vogel * to get the current speed/duplex if link exists. 6384edd8523SJack F Vogel **/ 6394edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) 6404edd8523SJack F Vogel { 6414edd8523SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 6424edd8523SJack F Vogel s32 ret_val; 6434edd8523SJack F Vogel bool link; 644*4dab5c37SJack F Vogel u16 phy_reg; 6454edd8523SJack F Vogel 6464edd8523SJack F Vogel DEBUGFUNC("e1000_check_for_copper_link_ich8lan"); 6474edd8523SJack F Vogel 6484edd8523SJack F Vogel /* 6494edd8523SJack F Vogel * We only want to go out to the PHY registers to see if Auto-Neg 6504edd8523SJack F Vogel * has completed and/or if our link status has changed. The 6514edd8523SJack F Vogel * get_link_status flag is set upon receiving a Link Status 6524edd8523SJack F Vogel * Change or Rx Sequence Error interrupt. 6534edd8523SJack F Vogel */ 6544edd8523SJack F Vogel if (!mac->get_link_status) { 6554edd8523SJack F Vogel ret_val = E1000_SUCCESS; 6564edd8523SJack F Vogel goto out; 6574edd8523SJack F Vogel } 6584edd8523SJack F Vogel 6594edd8523SJack F Vogel /* 6604edd8523SJack F Vogel * First we want to see if the MII Status Register reports 6614edd8523SJack F Vogel * link. If so, then we want to get the current speed/duplex 6624edd8523SJack F Vogel * of the PHY. 6634edd8523SJack F Vogel */ 6644edd8523SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 6654edd8523SJack F Vogel if (ret_val) 6664edd8523SJack F Vogel goto out; 6674edd8523SJack F Vogel 6684edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) { 6694edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, link); 6704edd8523SJack F Vogel if (ret_val) 6714edd8523SJack F Vogel goto out; 6724edd8523SJack F Vogel } 6734edd8523SJack F Vogel 674*4dab5c37SJack F Vogel #if defined(NAHUM6_HW) && (defined(LTR_SUPPORT) || defined(OBFF_SUPPORT)) 675*4dab5c37SJack F Vogel if (hw->mac.type == e1000_pch_lpt) { 676*4dab5c37SJack F Vogel } 677*4dab5c37SJack F Vogel 678*4dab5c37SJack F Vogel #endif /* NAHUM6_HW && (LTR_SUPPORT || OBFF_SUPPORT) */ 6794edd8523SJack F Vogel if (!link) 6804edd8523SJack F Vogel goto out; /* No link detected */ 6814edd8523SJack F Vogel 6824edd8523SJack F Vogel mac->get_link_status = FALSE; 6834edd8523SJack F Vogel 684*4dab5c37SJack F Vogel switch (hw->mac.type) { 685*4dab5c37SJack F Vogel case e1000_pch2lan: 686*4dab5c37SJack F Vogel ret_val = e1000_k1_workaround_lv(hw); 687*4dab5c37SJack F Vogel if (ret_val) 688*4dab5c37SJack F Vogel goto out; 689*4dab5c37SJack F Vogel /* fall-thru */ 690*4dab5c37SJack F Vogel case e1000_pchlan: 6914edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) { 6924edd8523SJack F Vogel ret_val = e1000_link_stall_workaround_hv(hw); 6934edd8523SJack F Vogel if (ret_val) 6944edd8523SJack F Vogel goto out; 6954edd8523SJack F Vogel } 6964edd8523SJack F Vogel 697*4dab5c37SJack F Vogel /* 698*4dab5c37SJack F Vogel * Workaround for PCHx parts in half-duplex: 699*4dab5c37SJack F Vogel * Set the number of preambles removed from the packet 700*4dab5c37SJack F Vogel * when it is passed from the PHY to the MAC to prevent 701*4dab5c37SJack F Vogel * the MAC from misinterpreting the packet type. 702*4dab5c37SJack F Vogel */ 703*4dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg); 704*4dab5c37SJack F Vogel phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK; 705*4dab5c37SJack F Vogel 706*4dab5c37SJack F Vogel if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) != 707*4dab5c37SJack F Vogel E1000_STATUS_FD) 708*4dab5c37SJack F Vogel phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT); 709*4dab5c37SJack F Vogel 710*4dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg); 711*4dab5c37SJack F Vogel break; 712*4dab5c37SJack F Vogel default: 713*4dab5c37SJack F Vogel break; 7147d9119bdSJack F Vogel } 7157d9119bdSJack F Vogel 7164edd8523SJack F Vogel /* 7174edd8523SJack F Vogel * Check if there was DownShift, must be checked 7184edd8523SJack F Vogel * immediately after link-up 7194edd8523SJack F Vogel */ 7204edd8523SJack F Vogel e1000_check_downshift_generic(hw); 7214edd8523SJack F Vogel 7227d9119bdSJack F Vogel /* Enable/Disable EEE after link up */ 7237d9119bdSJack F Vogel ret_val = e1000_set_eee_pchlan(hw); 7247d9119bdSJack F Vogel if (ret_val) 7257d9119bdSJack F Vogel goto out; 7267d9119bdSJack F Vogel 7274edd8523SJack F Vogel /* 7284edd8523SJack F Vogel * If we are forcing speed/duplex, then we simply return since 7294edd8523SJack F Vogel * we have already determined whether we have link or not. 7304edd8523SJack F Vogel */ 7314edd8523SJack F Vogel if (!mac->autoneg) { 7324edd8523SJack F Vogel ret_val = -E1000_ERR_CONFIG; 7334edd8523SJack F Vogel goto out; 7344edd8523SJack F Vogel } 7354edd8523SJack F Vogel 7364edd8523SJack F Vogel /* 7374edd8523SJack F Vogel * Auto-Neg is enabled. Auto Speed Detection takes care 7384edd8523SJack F Vogel * of MAC speed/duplex configuration. So we only need to 7394edd8523SJack F Vogel * configure Collision Distance in the MAC. 7404edd8523SJack F Vogel */ 7414edd8523SJack F Vogel e1000_config_collision_dist_generic(hw); 7424edd8523SJack F Vogel 7434edd8523SJack F Vogel /* 7444edd8523SJack F Vogel * Configure Flow Control now that Auto-Neg has completed. 7454edd8523SJack F Vogel * First, we need to restore the desired flow control 7464edd8523SJack F Vogel * settings because we may have had to re-autoneg with a 7474edd8523SJack F Vogel * different link partner. 7484edd8523SJack F Vogel */ 7494edd8523SJack F Vogel ret_val = e1000_config_fc_after_link_up_generic(hw); 7504edd8523SJack F Vogel if (ret_val) 7514edd8523SJack F Vogel DEBUGOUT("Error configuring flow control\n"); 7524edd8523SJack F Vogel 7534edd8523SJack F Vogel out: 7544edd8523SJack F Vogel return ret_val; 7554edd8523SJack F Vogel } 7564edd8523SJack F Vogel 7574edd8523SJack F Vogel /** 7588cfa0ad2SJack F Vogel * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers 7598cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 7608cfa0ad2SJack F Vogel * 7618cfa0ad2SJack F Vogel * Initialize family-specific function pointers for PHY, MAC, and NVM. 7628cfa0ad2SJack F Vogel **/ 7638cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) 7648cfa0ad2SJack F Vogel { 7658cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_function_pointers_ich8lan"); 7668cfa0ad2SJack F Vogel 7678cfa0ad2SJack F Vogel hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; 7688cfa0ad2SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; 7699d81738fSJack F Vogel switch (hw->mac.type) { 7709d81738fSJack F Vogel case e1000_ich8lan: 7719d81738fSJack F Vogel case e1000_ich9lan: 7729d81738fSJack F Vogel case e1000_ich10lan: 7738cfa0ad2SJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; 7749d81738fSJack F Vogel break; 7759d81738fSJack F Vogel case e1000_pchlan: 7767d9119bdSJack F Vogel case e1000_pch2lan: 7779d81738fSJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_pchlan; 7789d81738fSJack F Vogel break; 7799d81738fSJack F Vogel default: 7809d81738fSJack F Vogel break; 7819d81738fSJack F Vogel } 7828cfa0ad2SJack F Vogel } 7838cfa0ad2SJack F Vogel 7848cfa0ad2SJack F Vogel /** 7854edd8523SJack F Vogel * e1000_acquire_nvm_ich8lan - Acquire NVM mutex 7864edd8523SJack F Vogel * @hw: pointer to the HW structure 7874edd8523SJack F Vogel * 7884edd8523SJack F Vogel * Acquires the mutex for performing NVM operations. 7894edd8523SJack F Vogel **/ 7904edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw) 7914edd8523SJack F Vogel { 7924edd8523SJack F Vogel DEBUGFUNC("e1000_acquire_nvm_ich8lan"); 7934edd8523SJack F Vogel 7944edd8523SJack F Vogel E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex); 7954edd8523SJack F Vogel 7964edd8523SJack F Vogel return E1000_SUCCESS; 7974edd8523SJack F Vogel } 7984edd8523SJack F Vogel 7994edd8523SJack F Vogel /** 8004edd8523SJack F Vogel * e1000_release_nvm_ich8lan - Release NVM mutex 8014edd8523SJack F Vogel * @hw: pointer to the HW structure 8024edd8523SJack F Vogel * 8034edd8523SJack F Vogel * Releases the mutex used while performing NVM operations. 8044edd8523SJack F Vogel **/ 8054edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw) 8064edd8523SJack F Vogel { 8074edd8523SJack F Vogel DEBUGFUNC("e1000_release_nvm_ich8lan"); 8084edd8523SJack F Vogel 8094edd8523SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex); 8104edd8523SJack F Vogel 8114edd8523SJack F Vogel return; 8124edd8523SJack F Vogel } 8134edd8523SJack F Vogel 8144edd8523SJack F Vogel /** 8158cfa0ad2SJack F Vogel * e1000_acquire_swflag_ich8lan - Acquire software control flag 8168cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 8178cfa0ad2SJack F Vogel * 8184edd8523SJack F Vogel * Acquires the software control flag for performing PHY and select 8194edd8523SJack F Vogel * MAC CSR accesses. 8208cfa0ad2SJack F Vogel **/ 8218cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) 8228cfa0ad2SJack F Vogel { 8238cfa0ad2SJack F Vogel u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; 8248cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 8258cfa0ad2SJack F Vogel 8268cfa0ad2SJack F Vogel DEBUGFUNC("e1000_acquire_swflag_ich8lan"); 8278cfa0ad2SJack F Vogel 8284edd8523SJack F Vogel E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex); 8294edd8523SJack F Vogel 8308cfa0ad2SJack F Vogel while (timeout) { 8318cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 8324edd8523SJack F Vogel if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) 8338cfa0ad2SJack F Vogel break; 8344edd8523SJack F Vogel 8358cfa0ad2SJack F Vogel msec_delay_irq(1); 8368cfa0ad2SJack F Vogel timeout--; 8378cfa0ad2SJack F Vogel } 8388cfa0ad2SJack F Vogel 8398cfa0ad2SJack F Vogel if (!timeout) { 840*4dab5c37SJack F Vogel DEBUGOUT("SW has already locked the resource.\n"); 8414edd8523SJack F Vogel ret_val = -E1000_ERR_CONFIG; 8424edd8523SJack F Vogel goto out; 8434edd8523SJack F Vogel } 8444edd8523SJack F Vogel 8454edd8523SJack F Vogel timeout = SW_FLAG_TIMEOUT; 8464edd8523SJack F Vogel 8474edd8523SJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; 8484edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 8494edd8523SJack F Vogel 8504edd8523SJack F Vogel while (timeout) { 8514edd8523SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 8524edd8523SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) 8534edd8523SJack F Vogel break; 8544edd8523SJack F Vogel 8554edd8523SJack F Vogel msec_delay_irq(1); 8564edd8523SJack F Vogel timeout--; 8574edd8523SJack F Vogel } 8584edd8523SJack F Vogel 8594edd8523SJack F Vogel if (!timeout) { 860*4dab5c37SJack F Vogel DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n", 861*4dab5c37SJack F Vogel E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl); 8628cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 8638cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 8648cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 8658cfa0ad2SJack F Vogel goto out; 8668cfa0ad2SJack F Vogel } 8678cfa0ad2SJack F Vogel 8688cfa0ad2SJack F Vogel out: 8694edd8523SJack F Vogel if (ret_val) 8704edd8523SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); 8714edd8523SJack F Vogel 8728cfa0ad2SJack F Vogel return ret_val; 8738cfa0ad2SJack F Vogel } 8748cfa0ad2SJack F Vogel 8758cfa0ad2SJack F Vogel /** 8768cfa0ad2SJack F Vogel * e1000_release_swflag_ich8lan - Release software control flag 8778cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 8788cfa0ad2SJack F Vogel * 8794edd8523SJack F Vogel * Releases the software control flag for performing PHY and select 8804edd8523SJack F Vogel * MAC CSR accesses. 8818cfa0ad2SJack F Vogel **/ 8828cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) 8838cfa0ad2SJack F Vogel { 8848cfa0ad2SJack F Vogel u32 extcnf_ctrl; 8858cfa0ad2SJack F Vogel 8868cfa0ad2SJack F Vogel DEBUGFUNC("e1000_release_swflag_ich8lan"); 8878cfa0ad2SJack F Vogel 8888cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 889730d3130SJack F Vogel 890730d3130SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) { 8918cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 8928cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 893730d3130SJack F Vogel } else { 894730d3130SJack F Vogel DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n"); 895730d3130SJack F Vogel } 8968cfa0ad2SJack F Vogel 8974edd8523SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); 8984edd8523SJack F Vogel 8998cfa0ad2SJack F Vogel return; 9008cfa0ad2SJack F Vogel } 9018cfa0ad2SJack F Vogel 9028cfa0ad2SJack F Vogel /** 9038cfa0ad2SJack F Vogel * e1000_check_mng_mode_ich8lan - Checks management mode 9048cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 9058cfa0ad2SJack F Vogel * 9067d9119bdSJack F Vogel * This checks if the adapter has any manageability enabled. 9078cfa0ad2SJack F Vogel * This is a function pointer entry point only called by read/write 9088cfa0ad2SJack F Vogel * routines for the PHY and NVM parts. 9098cfa0ad2SJack F Vogel **/ 9108cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) 9118cfa0ad2SJack F Vogel { 9128cfa0ad2SJack F Vogel u32 fwsm; 9138cfa0ad2SJack F Vogel 9148cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_mng_mode_ich8lan"); 9158cfa0ad2SJack F Vogel 9168cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 9178cfa0ad2SJack F Vogel 9187d9119bdSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) && 9197d9119bdSJack F Vogel ((fwsm & E1000_FWSM_MODE_MASK) == 9207d9119bdSJack F Vogel (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 9217d9119bdSJack F Vogel } 9227d9119bdSJack F Vogel 9237d9119bdSJack F Vogel /** 9247d9119bdSJack F Vogel * e1000_check_mng_mode_pchlan - Checks management mode 9257d9119bdSJack F Vogel * @hw: pointer to the HW structure 9267d9119bdSJack F Vogel * 9277d9119bdSJack F Vogel * This checks if the adapter has iAMT enabled. 9287d9119bdSJack F Vogel * This is a function pointer entry point only called by read/write 9297d9119bdSJack F Vogel * routines for the PHY and NVM parts. 9307d9119bdSJack F Vogel **/ 9317d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw) 9327d9119bdSJack F Vogel { 9337d9119bdSJack F Vogel u32 fwsm; 9347d9119bdSJack F Vogel 9357d9119bdSJack F Vogel DEBUGFUNC("e1000_check_mng_mode_pchlan"); 9367d9119bdSJack F Vogel 9377d9119bdSJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 9387d9119bdSJack F Vogel 9397d9119bdSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) && 9407d9119bdSJack F Vogel (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 9417d9119bdSJack F Vogel } 9427d9119bdSJack F Vogel 9437d9119bdSJack F Vogel /** 9447d9119bdSJack F Vogel * e1000_rar_set_pch2lan - Set receive address register 9457d9119bdSJack F Vogel * @hw: pointer to the HW structure 9467d9119bdSJack F Vogel * @addr: pointer to the receive address 9477d9119bdSJack F Vogel * @index: receive address array register 9487d9119bdSJack F Vogel * 9497d9119bdSJack F Vogel * Sets the receive address array register at index to the address passed 9507d9119bdSJack F Vogel * in by addr. For 82579, RAR[0] is the base address register that is to 9517d9119bdSJack F Vogel * contain the MAC address but RAR[1-6] are reserved for manageability (ME). 9527d9119bdSJack F Vogel * Use SHRA[0-3] in place of those reserved for ME. 9537d9119bdSJack F Vogel **/ 9547d9119bdSJack F Vogel static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) 9557d9119bdSJack F Vogel { 9567d9119bdSJack F Vogel u32 rar_low, rar_high; 9577d9119bdSJack F Vogel 9587d9119bdSJack F Vogel DEBUGFUNC("e1000_rar_set_pch2lan"); 9597d9119bdSJack F Vogel 9607d9119bdSJack F Vogel /* 9617d9119bdSJack F Vogel * HW expects these in little endian so we reverse the byte order 9627d9119bdSJack F Vogel * from network order (big endian) to little endian 9637d9119bdSJack F Vogel */ 9647d9119bdSJack F Vogel rar_low = ((u32) addr[0] | 9657d9119bdSJack F Vogel ((u32) addr[1] << 8) | 9667d9119bdSJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); 9677d9119bdSJack F Vogel 9687d9119bdSJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); 9697d9119bdSJack F Vogel 9707d9119bdSJack F Vogel /* If MAC address zero, no need to set the AV bit */ 9717d9119bdSJack F Vogel if (rar_low || rar_high) 9727d9119bdSJack F Vogel rar_high |= E1000_RAH_AV; 9737d9119bdSJack F Vogel 9747d9119bdSJack F Vogel if (index == 0) { 9757d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); 9767d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 9777d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); 9787d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 9797d9119bdSJack F Vogel return; 9807d9119bdSJack F Vogel } 9817d9119bdSJack F Vogel 9827d9119bdSJack F Vogel if (index < hw->mac.rar_entry_count) { 9837d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low); 9847d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 9857d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high); 9867d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 9877d9119bdSJack F Vogel 9887d9119bdSJack F Vogel /* verify the register updates */ 9897d9119bdSJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) && 9907d9119bdSJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high)) 9917d9119bdSJack F Vogel return; 9927d9119bdSJack F Vogel 9937d9119bdSJack F Vogel DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n", 9947d9119bdSJack F Vogel (index - 1), E1000_READ_REG(hw, E1000_FWSM)); 9957d9119bdSJack F Vogel } 9967d9119bdSJack F Vogel 9977d9119bdSJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index); 9988cfa0ad2SJack F Vogel } 9998cfa0ad2SJack F Vogel 10008cfa0ad2SJack F Vogel /** 1001730d3130SJack F Vogel * e1000_update_mc_addr_list_pch2lan - Update Multicast addresses 1002730d3130SJack F Vogel * @hw: pointer to the HW structure 1003730d3130SJack F Vogel * @mc_addr_list: array of multicast addresses to program 1004730d3130SJack F Vogel * @mc_addr_count: number of multicast addresses to program 1005730d3130SJack F Vogel * 1006730d3130SJack F Vogel * Updates entire Multicast Table Array of the PCH2 MAC and PHY. 1007730d3130SJack F Vogel * The caller must have a packed mc_addr_list of multicast addresses. 1008730d3130SJack F Vogel **/ 1009730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw, 1010730d3130SJack F Vogel u8 *mc_addr_list, 1011730d3130SJack F Vogel u32 mc_addr_count) 1012730d3130SJack F Vogel { 1013*4dab5c37SJack F Vogel u16 phy_reg = 0; 1014730d3130SJack F Vogel int i; 1015*4dab5c37SJack F Vogel s32 ret_val; 1016730d3130SJack F Vogel 1017730d3130SJack F Vogel DEBUGFUNC("e1000_update_mc_addr_list_pch2lan"); 1018730d3130SJack F Vogel 1019730d3130SJack F Vogel e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count); 1020730d3130SJack F Vogel 1021*4dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 1022*4dab5c37SJack F Vogel if (ret_val) 1023*4dab5c37SJack F Vogel return; 1024*4dab5c37SJack F Vogel 1025*4dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 1026*4dab5c37SJack F Vogel if (ret_val) 1027*4dab5c37SJack F Vogel goto release; 1028*4dab5c37SJack F Vogel 1029730d3130SJack F Vogel for (i = 0; i < hw->mac.mta_reg_count; i++) { 1030*4dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_MTA(i), 1031*4dab5c37SJack F Vogel (u16)(hw->mac.mta_shadow[i] & 1032*4dab5c37SJack F Vogel 0xFFFF)); 1033*4dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1), 1034730d3130SJack F Vogel (u16)((hw->mac.mta_shadow[i] >> 16) & 1035730d3130SJack F Vogel 0xFFFF)); 1036730d3130SJack F Vogel } 1037*4dab5c37SJack F Vogel 1038*4dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 1039*4dab5c37SJack F Vogel 1040*4dab5c37SJack F Vogel release: 1041*4dab5c37SJack F Vogel hw->phy.ops.release(hw); 1042730d3130SJack F Vogel } 1043730d3130SJack F Vogel 1044730d3130SJack F Vogel /** 10458cfa0ad2SJack F Vogel * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked 10468cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 10478cfa0ad2SJack F Vogel * 10488cfa0ad2SJack F Vogel * Checks if firmware is blocking the reset of the PHY. 10498cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 10508cfa0ad2SJack F Vogel * reset routines. 10518cfa0ad2SJack F Vogel **/ 10528cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) 10538cfa0ad2SJack F Vogel { 10548cfa0ad2SJack F Vogel u32 fwsm; 10558cfa0ad2SJack F Vogel 10568cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_reset_block_ich8lan"); 10578cfa0ad2SJack F Vogel 10588cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 10598cfa0ad2SJack F Vogel 10608cfa0ad2SJack F Vogel return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS 10618cfa0ad2SJack F Vogel : E1000_BLK_PHY_RESET; 10628cfa0ad2SJack F Vogel } 10638cfa0ad2SJack F Vogel 10648cfa0ad2SJack F Vogel /** 10657d9119bdSJack F Vogel * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states 10667d9119bdSJack F Vogel * @hw: pointer to the HW structure 10677d9119bdSJack F Vogel * 10687d9119bdSJack F Vogel * Assumes semaphore already acquired. 10697d9119bdSJack F Vogel * 10707d9119bdSJack F Vogel **/ 10717d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw) 10727d9119bdSJack F Vogel { 10737d9119bdSJack F Vogel u16 phy_data; 10747d9119bdSJack F Vogel u32 strap = E1000_READ_REG(hw, E1000_STRAP); 10757d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 10767d9119bdSJack F Vogel 10777d9119bdSJack F Vogel strap &= E1000_STRAP_SMBUS_ADDRESS_MASK; 10787d9119bdSJack F Vogel 10797d9119bdSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data); 10807d9119bdSJack F Vogel if (ret_val) 10817d9119bdSJack F Vogel goto out; 10827d9119bdSJack F Vogel 10837d9119bdSJack F Vogel phy_data &= ~HV_SMB_ADDR_MASK; 10847d9119bdSJack F Vogel phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT); 10857d9119bdSJack F Vogel phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; 10867d9119bdSJack F Vogel ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data); 10877d9119bdSJack F Vogel 10887d9119bdSJack F Vogel out: 10897d9119bdSJack F Vogel return ret_val; 10907d9119bdSJack F Vogel } 10917d9119bdSJack F Vogel 10927d9119bdSJack F Vogel /** 10934edd8523SJack F Vogel * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration 10944edd8523SJack F Vogel * @hw: pointer to the HW structure 10954edd8523SJack F Vogel * 10964edd8523SJack F Vogel * SW should configure the LCD from the NVM extended configuration region 10974edd8523SJack F Vogel * as a workaround for certain parts. 10984edd8523SJack F Vogel **/ 10994edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) 11004edd8523SJack F Vogel { 11014edd8523SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 11024edd8523SJack F Vogel u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; 1103a69ed8dfSJack F Vogel s32 ret_val = E1000_SUCCESS; 11044edd8523SJack F Vogel u16 word_addr, reg_data, reg_addr, phy_page = 0; 11054edd8523SJack F Vogel 11067d9119bdSJack F Vogel DEBUGFUNC("e1000_sw_lcd_config_ich8lan"); 11074edd8523SJack F Vogel 11084edd8523SJack F Vogel /* 11094edd8523SJack F Vogel * Initialize the PHY from the NVM on ICH platforms. This 11104edd8523SJack F Vogel * is needed due to an issue where the NVM configuration is 11114edd8523SJack F Vogel * not properly autoloaded after power transitions. 11124edd8523SJack F Vogel * Therefore, after each PHY reset, we will load the 11134edd8523SJack F Vogel * configuration data out of the NVM manually. 11144edd8523SJack F Vogel */ 11157d9119bdSJack F Vogel switch (hw->mac.type) { 11167d9119bdSJack F Vogel case e1000_ich8lan: 11177d9119bdSJack F Vogel if (phy->type != e1000_phy_igp_3) 11187d9119bdSJack F Vogel return ret_val; 11197d9119bdSJack F Vogel 11207d9119bdSJack F Vogel if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) || 11217d9119bdSJack F Vogel (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) { 11224edd8523SJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; 11237d9119bdSJack F Vogel break; 11247d9119bdSJack F Vogel } 11257d9119bdSJack F Vogel /* Fall-thru */ 11267d9119bdSJack F Vogel case e1000_pchlan: 11277d9119bdSJack F Vogel case e1000_pch2lan: 11287d9119bdSJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; 11297d9119bdSJack F Vogel break; 11307d9119bdSJack F Vogel default: 11317d9119bdSJack F Vogel return ret_val; 11327d9119bdSJack F Vogel } 11337d9119bdSJack F Vogel 11347d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 11357d9119bdSJack F Vogel if (ret_val) 11367d9119bdSJack F Vogel return ret_val; 11374edd8523SJack F Vogel 11384edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_FEXTNVM); 11394edd8523SJack F Vogel if (!(data & sw_cfg_mask)) 11404edd8523SJack F Vogel goto out; 11414edd8523SJack F Vogel 11424edd8523SJack F Vogel /* 11434edd8523SJack F Vogel * Make sure HW does not configure LCD from PHY 11444edd8523SJack F Vogel * extended configuration before SW configuration 11454edd8523SJack F Vogel */ 11464edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 11477d9119bdSJack F Vogel if (!(hw->mac.type == e1000_pch2lan)) { 11484edd8523SJack F Vogel if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) 11494edd8523SJack F Vogel goto out; 11507d9119bdSJack F Vogel } 11514edd8523SJack F Vogel 11524edd8523SJack F Vogel cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); 11534edd8523SJack F Vogel cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; 11544edd8523SJack F Vogel cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; 11554edd8523SJack F Vogel if (!cnf_size) 11564edd8523SJack F Vogel goto out; 11574edd8523SJack F Vogel 11584edd8523SJack F Vogel cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; 11594edd8523SJack F Vogel cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; 11604edd8523SJack F Vogel 11617d9119bdSJack F Vogel if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && 11627d9119bdSJack F Vogel (hw->mac.type == e1000_pchlan)) || 11637d9119bdSJack F Vogel (hw->mac.type == e1000_pch2lan)) { 11644edd8523SJack F Vogel /* 11654edd8523SJack F Vogel * HW configures the SMBus address and LEDs when the 11664edd8523SJack F Vogel * OEM and LCD Write Enable bits are set in the NVM. 11674edd8523SJack F Vogel * When both NVM bits are cleared, SW will configure 11684edd8523SJack F Vogel * them instead. 11694edd8523SJack F Vogel */ 11707d9119bdSJack F Vogel ret_val = e1000_write_smbus_addr(hw); 11714edd8523SJack F Vogel if (ret_val) 11724edd8523SJack F Vogel goto out; 11734edd8523SJack F Vogel 11744edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_LEDCTL); 1175a69ed8dfSJack F Vogel ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG, 11764edd8523SJack F Vogel (u16)data); 11774edd8523SJack F Vogel if (ret_val) 11784edd8523SJack F Vogel goto out; 11794edd8523SJack F Vogel } 11804edd8523SJack F Vogel 11814edd8523SJack F Vogel /* Configure LCD from extended configuration region. */ 11824edd8523SJack F Vogel 11834edd8523SJack F Vogel /* cnf_base_addr is in DWORD */ 11844edd8523SJack F Vogel word_addr = (u16)(cnf_base_addr << 1); 11854edd8523SJack F Vogel 11864edd8523SJack F Vogel for (i = 0; i < cnf_size; i++) { 11874edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, 11884edd8523SJack F Vogel ®_data); 11894edd8523SJack F Vogel if (ret_val) 11904edd8523SJack F Vogel goto out; 11914edd8523SJack F Vogel 11924edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), 11934edd8523SJack F Vogel 1, ®_addr); 11944edd8523SJack F Vogel if (ret_val) 11954edd8523SJack F Vogel goto out; 11964edd8523SJack F Vogel 11974edd8523SJack F Vogel /* Save off the PHY page for future writes. */ 11984edd8523SJack F Vogel if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { 11994edd8523SJack F Vogel phy_page = reg_data; 12004edd8523SJack F Vogel continue; 12014edd8523SJack F Vogel } 12024edd8523SJack F Vogel 12034edd8523SJack F Vogel reg_addr &= PHY_REG_MASK; 12044edd8523SJack F Vogel reg_addr |= phy_page; 12054edd8523SJack F Vogel 12064edd8523SJack F Vogel ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, 12074edd8523SJack F Vogel reg_data); 12084edd8523SJack F Vogel if (ret_val) 12094edd8523SJack F Vogel goto out; 12104edd8523SJack F Vogel } 12114edd8523SJack F Vogel 12124edd8523SJack F Vogel out: 12134edd8523SJack F Vogel hw->phy.ops.release(hw); 12144edd8523SJack F Vogel return ret_val; 12154edd8523SJack F Vogel } 12164edd8523SJack F Vogel 12174edd8523SJack F Vogel /** 12184edd8523SJack F Vogel * e1000_k1_gig_workaround_hv - K1 Si workaround 12194edd8523SJack F Vogel * @hw: pointer to the HW structure 12204edd8523SJack F Vogel * @link: link up bool flag 12214edd8523SJack F Vogel * 12224edd8523SJack F Vogel * If K1 is enabled for 1Gbps, the MAC might stall when transitioning 12234edd8523SJack F Vogel * from a lower speed. This workaround disables K1 whenever link is at 1Gig 12244edd8523SJack F Vogel * If link is down, the function will restore the default K1 setting located 12254edd8523SJack F Vogel * in the NVM. 12264edd8523SJack F Vogel **/ 12274edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) 12284edd8523SJack F Vogel { 12294edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 12304edd8523SJack F Vogel u16 status_reg = 0; 12314edd8523SJack F Vogel bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; 12324edd8523SJack F Vogel 12334edd8523SJack F Vogel DEBUGFUNC("e1000_k1_gig_workaround_hv"); 12344edd8523SJack F Vogel 12354edd8523SJack F Vogel if (hw->mac.type != e1000_pchlan) 12364edd8523SJack F Vogel goto out; 12374edd8523SJack F Vogel 12384edd8523SJack F Vogel /* Wrap the whole flow with the sw flag */ 12394edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 12404edd8523SJack F Vogel if (ret_val) 12414edd8523SJack F Vogel goto out; 12424edd8523SJack F Vogel 12434edd8523SJack F Vogel /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ 12444edd8523SJack F Vogel if (link) { 12454edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) { 12464edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, 12474edd8523SJack F Vogel &status_reg); 12484edd8523SJack F Vogel if (ret_val) 12494edd8523SJack F Vogel goto release; 12504edd8523SJack F Vogel 12514edd8523SJack F Vogel status_reg &= BM_CS_STATUS_LINK_UP | 12524edd8523SJack F Vogel BM_CS_STATUS_RESOLVED | 12534edd8523SJack F Vogel BM_CS_STATUS_SPEED_MASK; 12544edd8523SJack F Vogel 12554edd8523SJack F Vogel if (status_reg == (BM_CS_STATUS_LINK_UP | 12564edd8523SJack F Vogel BM_CS_STATUS_RESOLVED | 12574edd8523SJack F Vogel BM_CS_STATUS_SPEED_1000)) 12584edd8523SJack F Vogel k1_enable = FALSE; 12594edd8523SJack F Vogel } 12604edd8523SJack F Vogel 12614edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82577) { 12624edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, 12634edd8523SJack F Vogel &status_reg); 12644edd8523SJack F Vogel if (ret_val) 12654edd8523SJack F Vogel goto release; 12664edd8523SJack F Vogel 12674edd8523SJack F Vogel status_reg &= HV_M_STATUS_LINK_UP | 12684edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE | 12694edd8523SJack F Vogel HV_M_STATUS_SPEED_MASK; 12704edd8523SJack F Vogel 12714edd8523SJack F Vogel if (status_reg == (HV_M_STATUS_LINK_UP | 12724edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE | 12734edd8523SJack F Vogel HV_M_STATUS_SPEED_1000)) 12744edd8523SJack F Vogel k1_enable = FALSE; 12754edd8523SJack F Vogel } 12764edd8523SJack F Vogel 12774edd8523SJack F Vogel /* Link stall fix for link up */ 12784edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), 12794edd8523SJack F Vogel 0x0100); 12804edd8523SJack F Vogel if (ret_val) 12814edd8523SJack F Vogel goto release; 12824edd8523SJack F Vogel 12834edd8523SJack F Vogel } else { 12844edd8523SJack F Vogel /* Link stall fix for link down */ 12854edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), 12864edd8523SJack F Vogel 0x4100); 12874edd8523SJack F Vogel if (ret_val) 12884edd8523SJack F Vogel goto release; 12894edd8523SJack F Vogel } 12904edd8523SJack F Vogel 12914edd8523SJack F Vogel ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); 12924edd8523SJack F Vogel 12934edd8523SJack F Vogel release: 12944edd8523SJack F Vogel hw->phy.ops.release(hw); 12954edd8523SJack F Vogel out: 12964edd8523SJack F Vogel return ret_val; 12974edd8523SJack F Vogel } 12984edd8523SJack F Vogel 12994edd8523SJack F Vogel /** 13004edd8523SJack F Vogel * e1000_configure_k1_ich8lan - Configure K1 power state 13014edd8523SJack F Vogel * @hw: pointer to the HW structure 13024edd8523SJack F Vogel * @enable: K1 state to configure 13034edd8523SJack F Vogel * 13044edd8523SJack F Vogel * Configure the K1 power state based on the provided parameter. 13054edd8523SJack F Vogel * Assumes semaphore already acquired. 13064edd8523SJack F Vogel * 13074edd8523SJack F Vogel * Success returns 0, Failure returns -E1000_ERR_PHY (-2) 13084edd8523SJack F Vogel **/ 13094edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) 13104edd8523SJack F Vogel { 13114edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 13124edd8523SJack F Vogel u32 ctrl_reg = 0; 13134edd8523SJack F Vogel u32 ctrl_ext = 0; 13144edd8523SJack F Vogel u32 reg = 0; 13154edd8523SJack F Vogel u16 kmrn_reg = 0; 13164edd8523SJack F Vogel 13177d9119bdSJack F Vogel DEBUGFUNC("e1000_configure_k1_ich8lan"); 13187d9119bdSJack F Vogel 1319*4dab5c37SJack F Vogel ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 13204edd8523SJack F Vogel &kmrn_reg); 13214edd8523SJack F Vogel if (ret_val) 13224edd8523SJack F Vogel goto out; 13234edd8523SJack F Vogel 13244edd8523SJack F Vogel if (k1_enable) 13254edd8523SJack F Vogel kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; 13264edd8523SJack F Vogel else 13274edd8523SJack F Vogel kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; 13284edd8523SJack F Vogel 1329*4dab5c37SJack F Vogel ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 13304edd8523SJack F Vogel kmrn_reg); 13314edd8523SJack F Vogel if (ret_val) 13324edd8523SJack F Vogel goto out; 13334edd8523SJack F Vogel 13344edd8523SJack F Vogel usec_delay(20); 13354edd8523SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 13364edd8523SJack F Vogel ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); 13374edd8523SJack F Vogel 13384edd8523SJack F Vogel reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); 13394edd8523SJack F Vogel reg |= E1000_CTRL_FRCSPD; 13404edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg); 13414edd8523SJack F Vogel 13424edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); 1343*4dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 13444edd8523SJack F Vogel usec_delay(20); 13454edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); 13464edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 1347*4dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 13484edd8523SJack F Vogel usec_delay(20); 13494edd8523SJack F Vogel 13504edd8523SJack F Vogel out: 13514edd8523SJack F Vogel return ret_val; 13524edd8523SJack F Vogel } 13534edd8523SJack F Vogel 13544edd8523SJack F Vogel /** 13554edd8523SJack F Vogel * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration 13564edd8523SJack F Vogel * @hw: pointer to the HW structure 13574edd8523SJack F Vogel * @d0_state: boolean if entering d0 or d3 device state 13584edd8523SJack F Vogel * 13594edd8523SJack F Vogel * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are 13604edd8523SJack F Vogel * collectively called OEM bits. The OEM Write Enable bit and SW Config bit 13614edd8523SJack F Vogel * in NVM determines whether HW should configure LPLU and Gbe Disable. 13624edd8523SJack F Vogel **/ 1363*4dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) 13644edd8523SJack F Vogel { 13654edd8523SJack F Vogel s32 ret_val = 0; 13664edd8523SJack F Vogel u32 mac_reg; 13674edd8523SJack F Vogel u16 oem_reg; 13684edd8523SJack F Vogel 13697d9119bdSJack F Vogel DEBUGFUNC("e1000_oem_bits_config_ich8lan"); 13707d9119bdSJack F Vogel 13717d9119bdSJack F Vogel if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan)) 13724edd8523SJack F Vogel return ret_val; 13734edd8523SJack F Vogel 13744edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 13754edd8523SJack F Vogel if (ret_val) 13764edd8523SJack F Vogel return ret_val; 13774edd8523SJack F Vogel 13787d9119bdSJack F Vogel if (!(hw->mac.type == e1000_pch2lan)) { 13794edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 13804edd8523SJack F Vogel if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) 13814edd8523SJack F Vogel goto out; 13827d9119bdSJack F Vogel } 13834edd8523SJack F Vogel 13844edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM); 13854edd8523SJack F Vogel if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) 13864edd8523SJack F Vogel goto out; 13874edd8523SJack F Vogel 13884edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 13894edd8523SJack F Vogel 13904edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); 13914edd8523SJack F Vogel if (ret_val) 13924edd8523SJack F Vogel goto out; 13934edd8523SJack F Vogel 13944edd8523SJack F Vogel oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); 13954edd8523SJack F Vogel 13964edd8523SJack F Vogel if (d0_state) { 13974edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) 13984edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS; 13994edd8523SJack F Vogel 14004edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) 14014edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 14024edd8523SJack F Vogel 1403*4dab5c37SJack F Vogel /* Set Restart auto-neg to activate the bits */ 14044edd8523SJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) 14054edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN; 1406*4dab5c37SJack F Vogel } else { 1407*4dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE | 1408*4dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE)) 1409*4dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS; 1410*4dab5c37SJack F Vogel 1411*4dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU | 1412*4dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU)) 1413*4dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 1414*4dab5c37SJack F Vogel } 1415*4dab5c37SJack F Vogel 14164edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); 14174edd8523SJack F Vogel 14184edd8523SJack F Vogel out: 14194edd8523SJack F Vogel hw->phy.ops.release(hw); 14204edd8523SJack F Vogel 14214edd8523SJack F Vogel return ret_val; 14224edd8523SJack F Vogel } 14234edd8523SJack F Vogel 14244edd8523SJack F Vogel 14254edd8523SJack F Vogel /** 1426a69ed8dfSJack F Vogel * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode 1427a69ed8dfSJack F Vogel * @hw: pointer to the HW structure 1428a69ed8dfSJack F Vogel **/ 1429a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw) 1430a69ed8dfSJack F Vogel { 1431a69ed8dfSJack F Vogel s32 ret_val; 1432a69ed8dfSJack F Vogel u16 data; 1433a69ed8dfSJack F Vogel 14347d9119bdSJack F Vogel DEBUGFUNC("e1000_set_mdio_slow_mode_hv"); 14357d9119bdSJack F Vogel 1436a69ed8dfSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data); 1437a69ed8dfSJack F Vogel if (ret_val) 1438a69ed8dfSJack F Vogel return ret_val; 1439a69ed8dfSJack F Vogel 1440a69ed8dfSJack F Vogel data |= HV_KMRN_MDIO_SLOW; 1441a69ed8dfSJack F Vogel 1442a69ed8dfSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data); 1443a69ed8dfSJack F Vogel 1444a69ed8dfSJack F Vogel return ret_val; 1445a69ed8dfSJack F Vogel } 1446a69ed8dfSJack F Vogel 1447a69ed8dfSJack F Vogel /** 14489d81738fSJack F Vogel * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be 14499d81738fSJack F Vogel * done after every PHY reset. 14509d81738fSJack F Vogel **/ 14519d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) 14529d81738fSJack F Vogel { 14539d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS; 1454a69ed8dfSJack F Vogel u16 phy_data; 14559d81738fSJack F Vogel 14567d9119bdSJack F Vogel DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan"); 14577d9119bdSJack F Vogel 14589d81738fSJack F Vogel if (hw->mac.type != e1000_pchlan) 14594edd8523SJack F Vogel goto out; 14609d81738fSJack F Vogel 1461a69ed8dfSJack F Vogel /* Set MDIO slow mode before any other MDIO access */ 1462a69ed8dfSJack F Vogel if (hw->phy.type == e1000_phy_82577) { 1463a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 1464a69ed8dfSJack F Vogel if (ret_val) 1465a69ed8dfSJack F Vogel goto out; 1466a69ed8dfSJack F Vogel } 1467a69ed8dfSJack F Vogel 14689d81738fSJack F Vogel if (((hw->phy.type == e1000_phy_82577) && 14699d81738fSJack F Vogel ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || 14709d81738fSJack F Vogel ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { 14719d81738fSJack F Vogel /* Disable generation of early preamble */ 14729d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); 14739d81738fSJack F Vogel if (ret_val) 14744edd8523SJack F Vogel goto out; 14759d81738fSJack F Vogel 14769d81738fSJack F Vogel /* Preamble tuning for SSC */ 1477*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, 1478*4dab5c37SJack F Vogel 0xA204); 14799d81738fSJack F Vogel if (ret_val) 14804edd8523SJack F Vogel goto out; 14819d81738fSJack F Vogel } 14829d81738fSJack F Vogel 14839d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 14849d81738fSJack F Vogel /* 14859d81738fSJack F Vogel * Return registers to default by doing a soft reset then 14869d81738fSJack F Vogel * writing 0x3140 to the control register. 14879d81738fSJack F Vogel */ 14889d81738fSJack F Vogel if (hw->phy.revision < 2) { 14899d81738fSJack F Vogel e1000_phy_sw_reset_generic(hw); 14909d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, 14919d81738fSJack F Vogel 0x3140); 14929d81738fSJack F Vogel } 14939d81738fSJack F Vogel } 14949d81738fSJack F Vogel 14959d81738fSJack F Vogel /* Select page 0 */ 14969d81738fSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 14979d81738fSJack F Vogel if (ret_val) 14984edd8523SJack F Vogel goto out; 14994edd8523SJack F Vogel 15009d81738fSJack F Vogel hw->phy.addr = 1; 15014edd8523SJack F Vogel ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); 1502a69ed8dfSJack F Vogel hw->phy.ops.release(hw); 15034edd8523SJack F Vogel if (ret_val) 15044edd8523SJack F Vogel goto out; 15059d81738fSJack F Vogel 15064edd8523SJack F Vogel /* 15074edd8523SJack F Vogel * Configure the K1 Si workaround during phy reset assuming there is 15084edd8523SJack F Vogel * link so that it disables K1 if link is in 1Gbps. 15094edd8523SJack F Vogel */ 15104edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, TRUE); 1511a69ed8dfSJack F Vogel if (ret_val) 1512a69ed8dfSJack F Vogel goto out; 15134edd8523SJack F Vogel 1514a69ed8dfSJack F Vogel /* Workaround for link disconnects on a busy hub in half duplex */ 1515a69ed8dfSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 1516a69ed8dfSJack F Vogel if (ret_val) 1517a69ed8dfSJack F Vogel goto out; 1518*4dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data); 1519a69ed8dfSJack F Vogel if (ret_val) 1520a69ed8dfSJack F Vogel goto release; 1521*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG, 1522a69ed8dfSJack F Vogel phy_data & 0x00FF); 1523a69ed8dfSJack F Vogel release: 1524a69ed8dfSJack F Vogel hw->phy.ops.release(hw); 15254edd8523SJack F Vogel out: 15269d81738fSJack F Vogel return ret_val; 15279d81738fSJack F Vogel } 15289d81738fSJack F Vogel 15299d81738fSJack F Vogel /** 15307d9119bdSJack F Vogel * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY 15317d9119bdSJack F Vogel * @hw: pointer to the HW structure 15327d9119bdSJack F Vogel **/ 15337d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw) 15347d9119bdSJack F Vogel { 15357d9119bdSJack F Vogel u32 mac_reg; 1536*4dab5c37SJack F Vogel u16 i, phy_reg = 0; 1537*4dab5c37SJack F Vogel s32 ret_val; 15387d9119bdSJack F Vogel 15397d9119bdSJack F Vogel DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan"); 15407d9119bdSJack F Vogel 1541*4dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 1542*4dab5c37SJack F Vogel if (ret_val) 1543*4dab5c37SJack F Vogel return; 1544*4dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 1545*4dab5c37SJack F Vogel if (ret_val) 1546*4dab5c37SJack F Vogel goto release; 1547*4dab5c37SJack F Vogel 15487d9119bdSJack F Vogel /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */ 15497d9119bdSJack F Vogel for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) { 15507d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAL(i)); 1551*4dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_L(i), 1552*4dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF)); 1553*4dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_M(i), 1554*4dab5c37SJack F Vogel (u16)((mac_reg >> 16) & 0xFFFF)); 1555*4dab5c37SJack F Vogel 15567d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAH(i)); 1557*4dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_H(i), 1558*4dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF)); 1559*4dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i), 1560*4dab5c37SJack F Vogel (u16)((mac_reg & E1000_RAH_AV) 1561*4dab5c37SJack F Vogel >> 16)); 15627d9119bdSJack F Vogel } 1563*4dab5c37SJack F Vogel 1564*4dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 1565*4dab5c37SJack F Vogel 1566*4dab5c37SJack F Vogel release: 1567*4dab5c37SJack F Vogel hw->phy.ops.release(hw); 15687d9119bdSJack F Vogel } 15697d9119bdSJack F Vogel 15707d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[]) 15717d9119bdSJack F Vogel { 15727d9119bdSJack F Vogel u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */ 15737d9119bdSJack F Vogel u32 i, j, mask, crc; 15747d9119bdSJack F Vogel 15757d9119bdSJack F Vogel DEBUGFUNC("e1000_calc_rx_da_crc"); 15767d9119bdSJack F Vogel 15777d9119bdSJack F Vogel crc = 0xffffffff; 15787d9119bdSJack F Vogel for (i = 0; i < 6; i++) { 15797d9119bdSJack F Vogel crc = crc ^ mac[i]; 15807d9119bdSJack F Vogel for (j = 8; j > 0; j--) { 15817d9119bdSJack F Vogel mask = (crc & 1) * (-1); 15827d9119bdSJack F Vogel crc = (crc >> 1) ^ (poly & mask); 15837d9119bdSJack F Vogel } 15847d9119bdSJack F Vogel } 15857d9119bdSJack F Vogel return ~crc; 15867d9119bdSJack F Vogel } 15877d9119bdSJack F Vogel 15887d9119bdSJack F Vogel /** 15897d9119bdSJack F Vogel * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation 15907d9119bdSJack F Vogel * with 82579 PHY 15917d9119bdSJack F Vogel * @hw: pointer to the HW structure 15927d9119bdSJack F Vogel * @enable: flag to enable/disable workaround when enabling/disabling jumbos 15937d9119bdSJack F Vogel **/ 15947d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) 15957d9119bdSJack F Vogel { 15967d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 15977d9119bdSJack F Vogel u16 phy_reg, data; 15987d9119bdSJack F Vogel u32 mac_reg; 15997d9119bdSJack F Vogel u16 i; 16007d9119bdSJack F Vogel 16017d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan"); 16027d9119bdSJack F Vogel 16037d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 16047d9119bdSJack F Vogel goto out; 16057d9119bdSJack F Vogel 16067d9119bdSJack F Vogel /* disable Rx path while enabling/disabling workaround */ 16077d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); 1608*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), 1609*4dab5c37SJack F Vogel phy_reg | (1 << 14)); 16107d9119bdSJack F Vogel if (ret_val) 16117d9119bdSJack F Vogel goto out; 16127d9119bdSJack F Vogel 16137d9119bdSJack F Vogel if (enable) { 16147d9119bdSJack F Vogel /* 16157d9119bdSJack F Vogel * Write Rx addresses (rar_entry_count for RAL/H, +4 for 16167d9119bdSJack F Vogel * SHRAL/H) and initial CRC values to the MAC 16177d9119bdSJack F Vogel */ 16187d9119bdSJack F Vogel for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) { 16197d9119bdSJack F Vogel u8 mac_addr[ETH_ADDR_LEN] = {0}; 16207d9119bdSJack F Vogel u32 addr_high, addr_low; 16217d9119bdSJack F Vogel 16227d9119bdSJack F Vogel addr_high = E1000_READ_REG(hw, E1000_RAH(i)); 16237d9119bdSJack F Vogel if (!(addr_high & E1000_RAH_AV)) 16247d9119bdSJack F Vogel continue; 16257d9119bdSJack F Vogel addr_low = E1000_READ_REG(hw, E1000_RAL(i)); 16267d9119bdSJack F Vogel mac_addr[0] = (addr_low & 0xFF); 16277d9119bdSJack F Vogel mac_addr[1] = ((addr_low >> 8) & 0xFF); 16287d9119bdSJack F Vogel mac_addr[2] = ((addr_low >> 16) & 0xFF); 16297d9119bdSJack F Vogel mac_addr[3] = ((addr_low >> 24) & 0xFF); 16307d9119bdSJack F Vogel mac_addr[4] = (addr_high & 0xFF); 16317d9119bdSJack F Vogel mac_addr[5] = ((addr_high >> 8) & 0xFF); 16327d9119bdSJack F Vogel 16337d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_PCH_RAICC(i), 16347d9119bdSJack F Vogel e1000_calc_rx_da_crc(mac_addr)); 16357d9119bdSJack F Vogel } 16367d9119bdSJack F Vogel 16377d9119bdSJack F Vogel /* Write Rx addresses to the PHY */ 16387d9119bdSJack F Vogel e1000_copy_rx_addrs_to_phy_ich8lan(hw); 16397d9119bdSJack F Vogel 16407d9119bdSJack F Vogel /* Enable jumbo frame workaround in the MAC */ 16417d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); 16427d9119bdSJack F Vogel mac_reg &= ~(1 << 14); 16437d9119bdSJack F Vogel mac_reg |= (7 << 15); 16447d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); 16457d9119bdSJack F Vogel 16467d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL); 16477d9119bdSJack F Vogel mac_reg |= E1000_RCTL_SECRC; 16487d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); 16497d9119bdSJack F Vogel 16507d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 16517d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 16527d9119bdSJack F Vogel &data); 16537d9119bdSJack F Vogel if (ret_val) 16547d9119bdSJack F Vogel goto out; 16557d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 16567d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 16577d9119bdSJack F Vogel data | (1 << 0)); 16587d9119bdSJack F Vogel if (ret_val) 16597d9119bdSJack F Vogel goto out; 16607d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 16617d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 16627d9119bdSJack F Vogel &data); 16637d9119bdSJack F Vogel if (ret_val) 16647d9119bdSJack F Vogel goto out; 16657d9119bdSJack F Vogel data &= ~(0xF << 8); 16667d9119bdSJack F Vogel data |= (0xB << 8); 16677d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 16687d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 16697d9119bdSJack F Vogel data); 16707d9119bdSJack F Vogel if (ret_val) 16717d9119bdSJack F Vogel goto out; 16727d9119bdSJack F Vogel 16737d9119bdSJack F Vogel /* Enable jumbo frame workaround in the PHY */ 16747d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); 16757d9119bdSJack F Vogel data &= ~(0x7F << 5); 16767d9119bdSJack F Vogel data |= (0x37 << 5); 16777d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); 16787d9119bdSJack F Vogel if (ret_val) 16797d9119bdSJack F Vogel goto out; 16807d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); 16817d9119bdSJack F Vogel data &= ~(1 << 13); 16827d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); 16837d9119bdSJack F Vogel if (ret_val) 16847d9119bdSJack F Vogel goto out; 16857d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); 16867d9119bdSJack F Vogel data &= ~(0x3FF << 2); 16877d9119bdSJack F Vogel data |= (0x1A << 2); 16887d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); 16897d9119bdSJack F Vogel if (ret_val) 16907d9119bdSJack F Vogel goto out; 1691*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100); 16927d9119bdSJack F Vogel if (ret_val) 16937d9119bdSJack F Vogel goto out; 16947d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); 1695*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | 1696*4dab5c37SJack F Vogel (1 << 10)); 16977d9119bdSJack F Vogel if (ret_val) 16987d9119bdSJack F Vogel goto out; 16997d9119bdSJack F Vogel } else { 17007d9119bdSJack F Vogel /* Write MAC register values back to h/w defaults */ 17017d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); 17027d9119bdSJack F Vogel mac_reg &= ~(0xF << 14); 17037d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); 17047d9119bdSJack F Vogel 17057d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL); 17067d9119bdSJack F Vogel mac_reg &= ~E1000_RCTL_SECRC; 17077d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); 17087d9119bdSJack F Vogel 17097d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 17107d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 17117d9119bdSJack F Vogel &data); 17127d9119bdSJack F Vogel if (ret_val) 17137d9119bdSJack F Vogel goto out; 17147d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 17157d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 17167d9119bdSJack F Vogel data & ~(1 << 0)); 17177d9119bdSJack F Vogel if (ret_val) 17187d9119bdSJack F Vogel goto out; 17197d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 17207d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 17217d9119bdSJack F Vogel &data); 17227d9119bdSJack F Vogel if (ret_val) 17237d9119bdSJack F Vogel goto out; 17247d9119bdSJack F Vogel data &= ~(0xF << 8); 17257d9119bdSJack F Vogel data |= (0xB << 8); 17267d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 17277d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 17287d9119bdSJack F Vogel data); 17297d9119bdSJack F Vogel if (ret_val) 17307d9119bdSJack F Vogel goto out; 17317d9119bdSJack F Vogel 17327d9119bdSJack F Vogel /* Write PHY register values back to h/w defaults */ 17337d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); 17347d9119bdSJack F Vogel data &= ~(0x7F << 5); 17357d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); 17367d9119bdSJack F Vogel if (ret_val) 17377d9119bdSJack F Vogel goto out; 17387d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); 17397d9119bdSJack F Vogel data |= (1 << 13); 17407d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); 17417d9119bdSJack F Vogel if (ret_val) 17427d9119bdSJack F Vogel goto out; 17437d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); 17447d9119bdSJack F Vogel data &= ~(0x3FF << 2); 17457d9119bdSJack F Vogel data |= (0x8 << 2); 17467d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); 17477d9119bdSJack F Vogel if (ret_val) 17487d9119bdSJack F Vogel goto out; 17497d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00); 17507d9119bdSJack F Vogel if (ret_val) 17517d9119bdSJack F Vogel goto out; 17527d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); 1753*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & 1754*4dab5c37SJack F Vogel ~(1 << 10)); 17557d9119bdSJack F Vogel if (ret_val) 17567d9119bdSJack F Vogel goto out; 17577d9119bdSJack F Vogel } 17587d9119bdSJack F Vogel 17597d9119bdSJack F Vogel /* re-enable Rx path after enabling/disabling workaround */ 1760*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & 1761*4dab5c37SJack F Vogel ~(1 << 14)); 17627d9119bdSJack F Vogel 17637d9119bdSJack F Vogel out: 17647d9119bdSJack F Vogel return ret_val; 17657d9119bdSJack F Vogel } 17667d9119bdSJack F Vogel 17677d9119bdSJack F Vogel /** 17687d9119bdSJack F Vogel * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be 17697d9119bdSJack F Vogel * done after every PHY reset. 17707d9119bdSJack F Vogel **/ 17717d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) 17727d9119bdSJack F Vogel { 17737d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 17747d9119bdSJack F Vogel 17757d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan"); 17767d9119bdSJack F Vogel 17777d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 17787d9119bdSJack F Vogel goto out; 17797d9119bdSJack F Vogel 17807d9119bdSJack F Vogel /* Set MDIO slow mode before any other MDIO access */ 17817d9119bdSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 17827d9119bdSJack F Vogel 1783*4dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 1784*4dab5c37SJack F Vogel if (ret_val) 1785*4dab5c37SJack F Vogel goto out; 1786*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, 1787*4dab5c37SJack F Vogel I82579_MSE_THRESHOLD); 1788*4dab5c37SJack F Vogel if (ret_val) 1789*4dab5c37SJack F Vogel goto release; 1790*4dab5c37SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */ 1791*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 1792*4dab5c37SJack F Vogel 0x0034); 1793*4dab5c37SJack F Vogel if (ret_val) 1794*4dab5c37SJack F Vogel goto release; 1795*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, 1796*4dab5c37SJack F Vogel I82579_MSE_LINK_DOWN); 1797*4dab5c37SJack F Vogel if (ret_val) 1798*4dab5c37SJack F Vogel goto release; 1799*4dab5c37SJack F Vogel /* drop link after 5 times MSE threshold was reached */ 1800*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 1801*4dab5c37SJack F Vogel 0x0005); 1802*4dab5c37SJack F Vogel release: 1803*4dab5c37SJack F Vogel hw->phy.ops.release(hw); 1804*4dab5c37SJack F Vogel 18057d9119bdSJack F Vogel out: 18067d9119bdSJack F Vogel return ret_val; 18077d9119bdSJack F Vogel } 18087d9119bdSJack F Vogel 18097d9119bdSJack F Vogel /** 18107d9119bdSJack F Vogel * e1000_k1_gig_workaround_lv - K1 Si workaround 18117d9119bdSJack F Vogel * @hw: pointer to the HW structure 18127d9119bdSJack F Vogel * 18137d9119bdSJack F Vogel * Workaround to set the K1 beacon duration for 82579 parts 18147d9119bdSJack F Vogel **/ 18157d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw) 18167d9119bdSJack F Vogel { 18177d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 18187d9119bdSJack F Vogel u16 status_reg = 0; 18197d9119bdSJack F Vogel u32 mac_reg; 1820*4dab5c37SJack F Vogel u16 phy_reg; 18217d9119bdSJack F Vogel 18227d9119bdSJack F Vogel DEBUGFUNC("e1000_k1_workaround_lv"); 18237d9119bdSJack F Vogel 18247d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 18257d9119bdSJack F Vogel goto out; 18267d9119bdSJack F Vogel 18277d9119bdSJack F Vogel /* Set K1 beacon duration based on 1Gbps speed or otherwise */ 18287d9119bdSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg); 18297d9119bdSJack F Vogel if (ret_val) 18307d9119bdSJack F Vogel goto out; 18317d9119bdSJack F Vogel 18327d9119bdSJack F Vogel if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) 18337d9119bdSJack F Vogel == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) { 18347d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); 18357d9119bdSJack F Vogel mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 18367d9119bdSJack F Vogel 1837*4dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg); 1838*4dab5c37SJack F Vogel if (ret_val) 1839*4dab5c37SJack F Vogel goto out; 18407d9119bdSJack F Vogel 1841*4dab5c37SJack F Vogel if (status_reg & HV_M_STATUS_SPEED_1000) { 1842*4dab5c37SJack F Vogel mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC; 1843*4dab5c37SJack F Vogel phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT; 1844*4dab5c37SJack F Vogel } else { 1845*4dab5c37SJack F Vogel mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC; 1846*4dab5c37SJack F Vogel phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT; 1847*4dab5c37SJack F Vogel } 18487d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg); 1849*4dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg); 18507d9119bdSJack F Vogel } 18517d9119bdSJack F Vogel 18527d9119bdSJack F Vogel out: 18537d9119bdSJack F Vogel return ret_val; 18547d9119bdSJack F Vogel } 18557d9119bdSJack F Vogel 18567d9119bdSJack F Vogel /** 18577d9119bdSJack F Vogel * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware 18587d9119bdSJack F Vogel * @hw: pointer to the HW structure 1859730d3130SJack F Vogel * @gate: boolean set to TRUE to gate, FALSE to ungate 18607d9119bdSJack F Vogel * 18617d9119bdSJack F Vogel * Gate/ungate the automatic PHY configuration via hardware; perform 18627d9119bdSJack F Vogel * the configuration via software instead. 18637d9119bdSJack F Vogel **/ 18647d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate) 18657d9119bdSJack F Vogel { 18667d9119bdSJack F Vogel u32 extcnf_ctrl; 18677d9119bdSJack F Vogel 18687d9119bdSJack F Vogel DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan"); 18697d9119bdSJack F Vogel 18707d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 18717d9119bdSJack F Vogel return; 18727d9119bdSJack F Vogel 18737d9119bdSJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 18747d9119bdSJack F Vogel 18757d9119bdSJack F Vogel if (gate) 18767d9119bdSJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; 18777d9119bdSJack F Vogel else 18787d9119bdSJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG; 18797d9119bdSJack F Vogel 18807d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 18817d9119bdSJack F Vogel return; 18827d9119bdSJack F Vogel } 18837d9119bdSJack F Vogel 18847d9119bdSJack F Vogel /** 18859d81738fSJack F Vogel * e1000_lan_init_done_ich8lan - Check for PHY config completion 18868cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 18878cfa0ad2SJack F Vogel * 18889d81738fSJack F Vogel * Check the appropriate indication the MAC has finished configuring the 18899d81738fSJack F Vogel * PHY after a software reset. 18908cfa0ad2SJack F Vogel **/ 18919d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) 18928cfa0ad2SJack F Vogel { 18939d81738fSJack F Vogel u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; 18948cfa0ad2SJack F Vogel 18959d81738fSJack F Vogel DEBUGFUNC("e1000_lan_init_done_ich8lan"); 18968cfa0ad2SJack F Vogel 18979d81738fSJack F Vogel /* Wait for basic configuration completes before proceeding */ 18989d81738fSJack F Vogel do { 18999d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 19009d81738fSJack F Vogel data &= E1000_STATUS_LAN_INIT_DONE; 19019d81738fSJack F Vogel usec_delay(100); 19029d81738fSJack F Vogel } while ((!data) && --loop); 19038cfa0ad2SJack F Vogel 19049d81738fSJack F Vogel /* 19059d81738fSJack F Vogel * If basic configuration is incomplete before the above loop 19069d81738fSJack F Vogel * count reaches 0, loading the configuration from NVM will 19079d81738fSJack F Vogel * leave the PHY in a bad state possibly resulting in no link. 19089d81738fSJack F Vogel */ 19099d81738fSJack F Vogel if (loop == 0) 19109d81738fSJack F Vogel DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); 19118cfa0ad2SJack F Vogel 19129d81738fSJack F Vogel /* Clear the Init Done bit for the next init event */ 19139d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 19149d81738fSJack F Vogel data &= ~E1000_STATUS_LAN_INIT_DONE; 19159d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, data); 19168cfa0ad2SJack F Vogel } 19178cfa0ad2SJack F Vogel 19188cfa0ad2SJack F Vogel /** 19197d9119bdSJack F Vogel * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset 19207d9119bdSJack F Vogel * @hw: pointer to the HW structure 19217d9119bdSJack F Vogel **/ 19227d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) 19237d9119bdSJack F Vogel { 19247d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 19257d9119bdSJack F Vogel u16 reg; 19267d9119bdSJack F Vogel 19277d9119bdSJack F Vogel DEBUGFUNC("e1000_post_phy_reset_ich8lan"); 19287d9119bdSJack F Vogel 19297d9119bdSJack F Vogel if (hw->phy.ops.check_reset_block(hw)) 19307d9119bdSJack F Vogel goto out; 19317d9119bdSJack F Vogel 19327d9119bdSJack F Vogel /* Allow time for h/w to get to quiescent state after reset */ 19337d9119bdSJack F Vogel msec_delay(10); 19347d9119bdSJack F Vogel 19357d9119bdSJack F Vogel /* Perform any necessary post-reset workarounds */ 19367d9119bdSJack F Vogel switch (hw->mac.type) { 19377d9119bdSJack F Vogel case e1000_pchlan: 19387d9119bdSJack F Vogel ret_val = e1000_hv_phy_workarounds_ich8lan(hw); 19397d9119bdSJack F Vogel if (ret_val) 19407d9119bdSJack F Vogel goto out; 19417d9119bdSJack F Vogel break; 19427d9119bdSJack F Vogel case e1000_pch2lan: 19437d9119bdSJack F Vogel ret_val = e1000_lv_phy_workarounds_ich8lan(hw); 19447d9119bdSJack F Vogel if (ret_val) 19457d9119bdSJack F Vogel goto out; 19467d9119bdSJack F Vogel break; 19477d9119bdSJack F Vogel default: 19487d9119bdSJack F Vogel break; 19497d9119bdSJack F Vogel } 19507d9119bdSJack F Vogel 1951*4dab5c37SJack F Vogel /* Clear the host wakeup bit after lcd reset */ 1952*4dab5c37SJack F Vogel if (hw->mac.type >= e1000_pchlan) { 1953*4dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, ®); 1954*4dab5c37SJack F Vogel reg &= ~BM_WUC_HOST_WU_BIT; 1955*4dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg); 19567d9119bdSJack F Vogel } 19577d9119bdSJack F Vogel 19587d9119bdSJack F Vogel /* Configure the LCD with the extended configuration region in NVM */ 19597d9119bdSJack F Vogel ret_val = e1000_sw_lcd_config_ich8lan(hw); 19607d9119bdSJack F Vogel if (ret_val) 19617d9119bdSJack F Vogel goto out; 19627d9119bdSJack F Vogel 19637d9119bdSJack F Vogel /* Configure the LCD with the OEM bits in NVM */ 19647d9119bdSJack F Vogel ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); 19657d9119bdSJack F Vogel 1966730d3130SJack F Vogel if (hw->mac.type == e1000_pch2lan) { 19677d9119bdSJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */ 1968730d3130SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 1969730d3130SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 19707d9119bdSJack F Vogel msec_delay(10); 19717d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, FALSE); 19727d9119bdSJack F Vogel } 19737d9119bdSJack F Vogel 1974730d3130SJack F Vogel /* Set EEE LPI Update Timer to 200usec */ 1975730d3130SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 1976730d3130SJack F Vogel if (ret_val) 1977730d3130SJack F Vogel goto out; 1978730d3130SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, 1979730d3130SJack F Vogel I82579_LPI_UPDATE_TIMER); 1980730d3130SJack F Vogel if (ret_val) 1981730d3130SJack F Vogel goto release; 1982730d3130SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 1983730d3130SJack F Vogel 0x1387); 1984730d3130SJack F Vogel release: 1985730d3130SJack F Vogel hw->phy.ops.release(hw); 1986730d3130SJack F Vogel } 1987730d3130SJack F Vogel 19887d9119bdSJack F Vogel out: 19897d9119bdSJack F Vogel return ret_val; 19907d9119bdSJack F Vogel } 19917d9119bdSJack F Vogel 19927d9119bdSJack F Vogel /** 19938cfa0ad2SJack F Vogel * e1000_phy_hw_reset_ich8lan - Performs a PHY reset 19948cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 19958cfa0ad2SJack F Vogel * 19968cfa0ad2SJack F Vogel * Resets the PHY 19978cfa0ad2SJack F Vogel * This is a function pointer entry point called by drivers 19988cfa0ad2SJack F Vogel * or other shared routines. 19998cfa0ad2SJack F Vogel **/ 20008cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) 20018cfa0ad2SJack F Vogel { 20024edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 20038cfa0ad2SJack F Vogel 20048cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); 20058cfa0ad2SJack F Vogel 20067d9119bdSJack F Vogel /* Gate automatic PHY configuration by hardware on non-managed 82579 */ 20077d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 20087d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 20097d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 20107d9119bdSJack F Vogel 20118cfa0ad2SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 20128cfa0ad2SJack F Vogel if (ret_val) 20138cfa0ad2SJack F Vogel goto out; 20148cfa0ad2SJack F Vogel 20157d9119bdSJack F Vogel ret_val = e1000_post_phy_reset_ich8lan(hw); 20168cfa0ad2SJack F Vogel 20178cfa0ad2SJack F Vogel out: 20188cfa0ad2SJack F Vogel return ret_val; 20198cfa0ad2SJack F Vogel } 20208cfa0ad2SJack F Vogel 20218cfa0ad2SJack F Vogel /** 20224edd8523SJack F Vogel * e1000_set_lplu_state_pchlan - Set Low Power Link Up state 20238cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 20244edd8523SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 20258cfa0ad2SJack F Vogel * 20264edd8523SJack F Vogel * Sets the LPLU state according to the active flag. For PCH, if OEM write 20274edd8523SJack F Vogel * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set 20284edd8523SJack F Vogel * the phy speed. This function will manually set the LPLU bit and restart 20294edd8523SJack F Vogel * auto-neg as hw would do. D3 and D0 LPLU will call the same function 20304edd8523SJack F Vogel * since it configures the same bit. 20318cfa0ad2SJack F Vogel **/ 20324edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) 20338cfa0ad2SJack F Vogel { 20344edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 20354edd8523SJack F Vogel u16 oem_reg; 20368cfa0ad2SJack F Vogel 20374edd8523SJack F Vogel DEBUGFUNC("e1000_set_lplu_state_pchlan"); 20388cfa0ad2SJack F Vogel 20394edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg); 20408cfa0ad2SJack F Vogel if (ret_val) 20418cfa0ad2SJack F Vogel goto out; 20428cfa0ad2SJack F Vogel 20434edd8523SJack F Vogel if (active) 20444edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 20454edd8523SJack F Vogel else 20464edd8523SJack F Vogel oem_reg &= ~HV_OEM_BITS_LPLU; 20478cfa0ad2SJack F Vogel 2048*4dab5c37SJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) 20494edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN; 2050*4dab5c37SJack F Vogel 20514edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg); 20528cfa0ad2SJack F Vogel 20538cfa0ad2SJack F Vogel out: 20548cfa0ad2SJack F Vogel return ret_val; 20558cfa0ad2SJack F Vogel } 20568cfa0ad2SJack F Vogel 20578cfa0ad2SJack F Vogel /** 20588cfa0ad2SJack F Vogel * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state 20598cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 20608cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 20618cfa0ad2SJack F Vogel * 20628cfa0ad2SJack F Vogel * Sets the LPLU D0 state according to the active flag. When 20638cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 20648cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 20658cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 20668cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 20678cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 20688cfa0ad2SJack F Vogel * PHY setup routines. 20698cfa0ad2SJack F Vogel **/ 2070daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 20718cfa0ad2SJack F Vogel { 20728cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 20738cfa0ad2SJack F Vogel u32 phy_ctrl; 20748cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 20758cfa0ad2SJack F Vogel u16 data; 20768cfa0ad2SJack F Vogel 20778cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); 20788cfa0ad2SJack F Vogel 20798cfa0ad2SJack F Vogel if (phy->type == e1000_phy_ife) 20808cfa0ad2SJack F Vogel goto out; 20818cfa0ad2SJack F Vogel 20828cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 20838cfa0ad2SJack F Vogel 20848cfa0ad2SJack F Vogel if (active) { 20858cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; 20868cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 20878cfa0ad2SJack F Vogel 20889d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 20899d81738fSJack F Vogel goto out; 20909d81738fSJack F Vogel 20918cfa0ad2SJack F Vogel /* 20928cfa0ad2SJack F Vogel * Call gig speed drop workaround on LPLU before accessing 20938cfa0ad2SJack F Vogel * any PHY registers 20948cfa0ad2SJack F Vogel */ 20959d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 20968cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 20978cfa0ad2SJack F Vogel 20988cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 20998cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 21008cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21018cfa0ad2SJack F Vogel &data); 21028cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 21038cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 21048cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21058cfa0ad2SJack F Vogel data); 21068cfa0ad2SJack F Vogel if (ret_val) 21078cfa0ad2SJack F Vogel goto out; 21088cfa0ad2SJack F Vogel } else { 21098cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; 21108cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 21118cfa0ad2SJack F Vogel 21129d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 21139d81738fSJack F Vogel goto out; 21149d81738fSJack F Vogel 21158cfa0ad2SJack F Vogel /* 21168cfa0ad2SJack F Vogel * LPLU and SmartSpeed are mutually exclusive. LPLU is used 21178cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 21188cfa0ad2SJack F Vogel * important. During driver activity we should enable 21198cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 21208cfa0ad2SJack F Vogel */ 21218cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 21228cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 21238cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21248cfa0ad2SJack F Vogel &data); 21258cfa0ad2SJack F Vogel if (ret_val) 21268cfa0ad2SJack F Vogel goto out; 21278cfa0ad2SJack F Vogel 21288cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 21298cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 21308cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21318cfa0ad2SJack F Vogel data); 21328cfa0ad2SJack F Vogel if (ret_val) 21338cfa0ad2SJack F Vogel goto out; 21348cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 21358cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 21368cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21378cfa0ad2SJack F Vogel &data); 21388cfa0ad2SJack F Vogel if (ret_val) 21398cfa0ad2SJack F Vogel goto out; 21408cfa0ad2SJack F Vogel 21418cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 21428cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 21438cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21448cfa0ad2SJack F Vogel data); 21458cfa0ad2SJack F Vogel if (ret_val) 21468cfa0ad2SJack F Vogel goto out; 21478cfa0ad2SJack F Vogel } 21488cfa0ad2SJack F Vogel } 21498cfa0ad2SJack F Vogel 21508cfa0ad2SJack F Vogel out: 21518cfa0ad2SJack F Vogel return ret_val; 21528cfa0ad2SJack F Vogel } 21538cfa0ad2SJack F Vogel 21548cfa0ad2SJack F Vogel /** 21558cfa0ad2SJack F Vogel * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state 21568cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 21578cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 21588cfa0ad2SJack F Vogel * 21598cfa0ad2SJack F Vogel * Sets the LPLU D3 state according to the active flag. When 21608cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 21618cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 21628cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 21638cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 21648cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 21658cfa0ad2SJack F Vogel * PHY setup routines. 21668cfa0ad2SJack F Vogel **/ 2167daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 21688cfa0ad2SJack F Vogel { 21698cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 21708cfa0ad2SJack F Vogel u32 phy_ctrl; 21718cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 21728cfa0ad2SJack F Vogel u16 data; 21738cfa0ad2SJack F Vogel 21748cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan"); 21758cfa0ad2SJack F Vogel 21768cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 21778cfa0ad2SJack F Vogel 21788cfa0ad2SJack F Vogel if (!active) { 21798cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; 21808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 21819d81738fSJack F Vogel 21829d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 21839d81738fSJack F Vogel goto out; 21849d81738fSJack F Vogel 21858cfa0ad2SJack F Vogel /* 21868cfa0ad2SJack F Vogel * LPLU and SmartSpeed are mutually exclusive. LPLU is used 21878cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 21888cfa0ad2SJack F Vogel * important. During driver activity we should enable 21898cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 21908cfa0ad2SJack F Vogel */ 21918cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 21928cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 21938cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 21948cfa0ad2SJack F Vogel &data); 21958cfa0ad2SJack F Vogel if (ret_val) 21968cfa0ad2SJack F Vogel goto out; 21978cfa0ad2SJack F Vogel 21988cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 21998cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 22008cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 22018cfa0ad2SJack F Vogel data); 22028cfa0ad2SJack F Vogel if (ret_val) 22038cfa0ad2SJack F Vogel goto out; 22048cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 22058cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 22068cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 22078cfa0ad2SJack F Vogel &data); 22088cfa0ad2SJack F Vogel if (ret_val) 22098cfa0ad2SJack F Vogel goto out; 22108cfa0ad2SJack F Vogel 22118cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 22128cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 22138cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 22148cfa0ad2SJack F Vogel data); 22158cfa0ad2SJack F Vogel if (ret_val) 22168cfa0ad2SJack F Vogel goto out; 22178cfa0ad2SJack F Vogel } 22188cfa0ad2SJack F Vogel } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 22198cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 22208cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 22218cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; 22228cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 22238cfa0ad2SJack F Vogel 22249d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 22259d81738fSJack F Vogel goto out; 22269d81738fSJack F Vogel 22278cfa0ad2SJack F Vogel /* 22288cfa0ad2SJack F Vogel * Call gig speed drop workaround on LPLU before accessing 22298cfa0ad2SJack F Vogel * any PHY registers 22308cfa0ad2SJack F Vogel */ 22319d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 22328cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 22338cfa0ad2SJack F Vogel 22348cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 22358cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 22368cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 22378cfa0ad2SJack F Vogel &data); 22388cfa0ad2SJack F Vogel if (ret_val) 22398cfa0ad2SJack F Vogel goto out; 22408cfa0ad2SJack F Vogel 22418cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 22428cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 22438cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 22448cfa0ad2SJack F Vogel data); 22458cfa0ad2SJack F Vogel } 22468cfa0ad2SJack F Vogel 22478cfa0ad2SJack F Vogel out: 22488cfa0ad2SJack F Vogel return ret_val; 22498cfa0ad2SJack F Vogel } 22508cfa0ad2SJack F Vogel 22518cfa0ad2SJack F Vogel /** 22528cfa0ad2SJack F Vogel * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 22538cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 22548cfa0ad2SJack F Vogel * @bank: pointer to the variable that returns the active bank 22558cfa0ad2SJack F Vogel * 22568cfa0ad2SJack F Vogel * Reads signature byte from the NVM using the flash access registers. 2257d035aa2dSJack F Vogel * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. 22588cfa0ad2SJack F Vogel **/ 22598cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) 22608cfa0ad2SJack F Vogel { 2261d035aa2dSJack F Vogel u32 eecd; 22628cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 22638cfa0ad2SJack F Vogel u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); 22648cfa0ad2SJack F Vogel u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; 2265d035aa2dSJack F Vogel u8 sig_byte = 0; 2266d035aa2dSJack F Vogel s32 ret_val = E1000_SUCCESS; 22678cfa0ad2SJack F Vogel 22687d9119bdSJack F Vogel DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan"); 22697d9119bdSJack F Vogel 2270d035aa2dSJack F Vogel switch (hw->mac.type) { 2271d035aa2dSJack F Vogel case e1000_ich8lan: 2272d035aa2dSJack F Vogel case e1000_ich9lan: 2273d035aa2dSJack F Vogel eecd = E1000_READ_REG(hw, E1000_EECD); 2274d035aa2dSJack F Vogel if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == 2275d035aa2dSJack F Vogel E1000_EECD_SEC1VAL_VALID_MASK) { 2276d035aa2dSJack F Vogel if (eecd & E1000_EECD_SEC1VAL) 22778cfa0ad2SJack F Vogel *bank = 1; 22788cfa0ad2SJack F Vogel else 22798cfa0ad2SJack F Vogel *bank = 0; 2280d035aa2dSJack F Vogel 2281d035aa2dSJack F Vogel goto out; 2282d035aa2dSJack F Vogel } 2283*4dab5c37SJack F Vogel DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n"); 2284d035aa2dSJack F Vogel /* fall-thru */ 2285d035aa2dSJack F Vogel default: 2286d035aa2dSJack F Vogel /* set bank to 0 in case flash read fails */ 22878cfa0ad2SJack F Vogel *bank = 0; 22888cfa0ad2SJack F Vogel 2289d035aa2dSJack F Vogel /* Check bank 0 */ 2290d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, 2291d035aa2dSJack F Vogel &sig_byte); 2292d035aa2dSJack F Vogel if (ret_val) 2293d035aa2dSJack F Vogel goto out; 2294d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 2295d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 2296d035aa2dSJack F Vogel *bank = 0; 2297d035aa2dSJack F Vogel goto out; 2298d035aa2dSJack F Vogel } 2299d035aa2dSJack F Vogel 2300d035aa2dSJack F Vogel /* Check bank 1 */ 2301d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + 2302d035aa2dSJack F Vogel bank1_offset, 2303d035aa2dSJack F Vogel &sig_byte); 2304d035aa2dSJack F Vogel if (ret_val) 2305d035aa2dSJack F Vogel goto out; 2306d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 2307d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 23088cfa0ad2SJack F Vogel *bank = 1; 2309d035aa2dSJack F Vogel goto out; 23108cfa0ad2SJack F Vogel } 23118cfa0ad2SJack F Vogel 2312d035aa2dSJack F Vogel DEBUGOUT("ERROR: No valid NVM bank present\n"); 2313d035aa2dSJack F Vogel ret_val = -E1000_ERR_NVM; 2314d035aa2dSJack F Vogel break; 2315d035aa2dSJack F Vogel } 2316d035aa2dSJack F Vogel out: 23178cfa0ad2SJack F Vogel return ret_val; 23188cfa0ad2SJack F Vogel } 23198cfa0ad2SJack F Vogel 23208cfa0ad2SJack F Vogel /** 23218cfa0ad2SJack F Vogel * e1000_read_nvm_ich8lan - Read word(s) from the NVM 23228cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 23238cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to read. 23248cfa0ad2SJack F Vogel * @words: Size of data to read in words 23258cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to read at offset. 23268cfa0ad2SJack F Vogel * 23278cfa0ad2SJack F Vogel * Reads a word(s) from the NVM using the flash access registers. 23288cfa0ad2SJack F Vogel **/ 23298cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 23308cfa0ad2SJack F Vogel u16 *data) 23318cfa0ad2SJack F Vogel { 23328cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 2333daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 23348cfa0ad2SJack F Vogel u32 act_offset; 23358cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 23368cfa0ad2SJack F Vogel u32 bank = 0; 23378cfa0ad2SJack F Vogel u16 i, word; 23388cfa0ad2SJack F Vogel 23398cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_nvm_ich8lan"); 23408cfa0ad2SJack F Vogel 23418cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 23428cfa0ad2SJack F Vogel (words == 0)) { 23438cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 23448cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 23458cfa0ad2SJack F Vogel goto out; 23468cfa0ad2SJack F Vogel } 23478cfa0ad2SJack F Vogel 23484edd8523SJack F Vogel nvm->ops.acquire(hw); 23498cfa0ad2SJack F Vogel 23508cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 23514edd8523SJack F Vogel if (ret_val != E1000_SUCCESS) { 23524edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 23534edd8523SJack F Vogel bank = 0; 23544edd8523SJack F Vogel } 23558cfa0ad2SJack F Vogel 23568cfa0ad2SJack F Vogel act_offset = (bank) ? nvm->flash_bank_size : 0; 23578cfa0ad2SJack F Vogel act_offset += offset; 23588cfa0ad2SJack F Vogel 23594edd8523SJack F Vogel ret_val = E1000_SUCCESS; 23608cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 2361*4dab5c37SJack F Vogel if (dev_spec->shadow_ram[offset+i].modified) { 23628cfa0ad2SJack F Vogel data[i] = dev_spec->shadow_ram[offset+i].value; 23638cfa0ad2SJack F Vogel } else { 23648cfa0ad2SJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, 23658cfa0ad2SJack F Vogel act_offset + i, 23668cfa0ad2SJack F Vogel &word); 23678cfa0ad2SJack F Vogel if (ret_val) 23688cfa0ad2SJack F Vogel break; 23698cfa0ad2SJack F Vogel data[i] = word; 23708cfa0ad2SJack F Vogel } 23718cfa0ad2SJack F Vogel } 23728cfa0ad2SJack F Vogel 23738cfa0ad2SJack F Vogel nvm->ops.release(hw); 23748cfa0ad2SJack F Vogel 23758cfa0ad2SJack F Vogel out: 2376d035aa2dSJack F Vogel if (ret_val) 2377d035aa2dSJack F Vogel DEBUGOUT1("NVM read error: %d\n", ret_val); 2378d035aa2dSJack F Vogel 23798cfa0ad2SJack F Vogel return ret_val; 23808cfa0ad2SJack F Vogel } 23818cfa0ad2SJack F Vogel 23828cfa0ad2SJack F Vogel /** 23838cfa0ad2SJack F Vogel * e1000_flash_cycle_init_ich8lan - Initialize flash 23848cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 23858cfa0ad2SJack F Vogel * 23868cfa0ad2SJack F Vogel * This function does initial flash setup so that a new read/write/erase cycle 23878cfa0ad2SJack F Vogel * can be started. 23888cfa0ad2SJack F Vogel **/ 23898cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) 23908cfa0ad2SJack F Vogel { 23918cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 23928cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 23938cfa0ad2SJack F Vogel 23948cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_init_ich8lan"); 23958cfa0ad2SJack F Vogel 23968cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 23978cfa0ad2SJack F Vogel 23988cfa0ad2SJack F Vogel /* Check if the flash descriptor is valid */ 23998cfa0ad2SJack F Vogel if (hsfsts.hsf_status.fldesvalid == 0) { 2400*4dab5c37SJack F Vogel DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used.\n"); 24018cfa0ad2SJack F Vogel goto out; 24028cfa0ad2SJack F Vogel } 24038cfa0ad2SJack F Vogel 24048cfa0ad2SJack F Vogel /* Clear FCERR and DAEL in hw status by writing 1 */ 24058cfa0ad2SJack F Vogel hsfsts.hsf_status.flcerr = 1; 24068cfa0ad2SJack F Vogel hsfsts.hsf_status.dael = 1; 24078cfa0ad2SJack F Vogel 24088cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); 24098cfa0ad2SJack F Vogel 24108cfa0ad2SJack F Vogel /* 24118cfa0ad2SJack F Vogel * Either we should have a hardware SPI cycle in progress 24128cfa0ad2SJack F Vogel * bit to check against, in order to start a new cycle or 24138cfa0ad2SJack F Vogel * FDONE bit should be changed in the hardware so that it 24148cfa0ad2SJack F Vogel * is 1 after hardware reset, which can then be used as an 24158cfa0ad2SJack F Vogel * indication whether a cycle is in progress or has been 24168cfa0ad2SJack F Vogel * completed. 24178cfa0ad2SJack F Vogel */ 24188cfa0ad2SJack F Vogel 24198cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcinprog == 0) { 24208cfa0ad2SJack F Vogel /* 24218cfa0ad2SJack F Vogel * There is no cycle running at present, 24228cfa0ad2SJack F Vogel * so we can start a cycle. 24238cfa0ad2SJack F Vogel * Begin by setting Flash Cycle Done. 24248cfa0ad2SJack F Vogel */ 24258cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 24268cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); 24278cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 24288cfa0ad2SJack F Vogel } else { 2429730d3130SJack F Vogel s32 i; 2430730d3130SJack F Vogel 24318cfa0ad2SJack F Vogel /* 24328cfa0ad2SJack F Vogel * Otherwise poll for sometime so the current 24338cfa0ad2SJack F Vogel * cycle has a chance to end before giving up. 24348cfa0ad2SJack F Vogel */ 24358cfa0ad2SJack F Vogel for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 24368cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 24378cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 24388cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcinprog == 0) { 24398cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 24408cfa0ad2SJack F Vogel break; 24418cfa0ad2SJack F Vogel } 24428cfa0ad2SJack F Vogel usec_delay(1); 24438cfa0ad2SJack F Vogel } 24448cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 24458cfa0ad2SJack F Vogel /* 24468cfa0ad2SJack F Vogel * Successful in waiting for previous cycle to timeout, 24478cfa0ad2SJack F Vogel * now set the Flash Cycle Done. 24488cfa0ad2SJack F Vogel */ 24498cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 2450daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, 24518cfa0ad2SJack F Vogel hsfsts.regval); 24528cfa0ad2SJack F Vogel } else { 2453*4dab5c37SJack F Vogel DEBUGOUT("Flash controller busy, cannot get access\n"); 24548cfa0ad2SJack F Vogel } 24558cfa0ad2SJack F Vogel } 24568cfa0ad2SJack F Vogel 24578cfa0ad2SJack F Vogel out: 24588cfa0ad2SJack F Vogel return ret_val; 24598cfa0ad2SJack F Vogel } 24608cfa0ad2SJack F Vogel 24618cfa0ad2SJack F Vogel /** 24628cfa0ad2SJack F Vogel * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) 24638cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 24648cfa0ad2SJack F Vogel * @timeout: maximum time to wait for completion 24658cfa0ad2SJack F Vogel * 24668cfa0ad2SJack F Vogel * This function starts a flash cycle and waits for its completion. 24678cfa0ad2SJack F Vogel **/ 24688cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) 24698cfa0ad2SJack F Vogel { 24708cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 24718cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 24728cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 24738cfa0ad2SJack F Vogel u32 i = 0; 24748cfa0ad2SJack F Vogel 24758cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_ich8lan"); 24768cfa0ad2SJack F Vogel 24778cfa0ad2SJack F Vogel /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 24788cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 24798cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcgo = 1; 24808cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 24818cfa0ad2SJack F Vogel 24828cfa0ad2SJack F Vogel /* wait till FDONE bit is set to 1 */ 24838cfa0ad2SJack F Vogel do { 24848cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 24858cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcdone == 1) 24868cfa0ad2SJack F Vogel break; 24878cfa0ad2SJack F Vogel usec_delay(1); 24888cfa0ad2SJack F Vogel } while (i++ < timeout); 24898cfa0ad2SJack F Vogel 24908cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) 24918cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 24928cfa0ad2SJack F Vogel 24938cfa0ad2SJack F Vogel return ret_val; 24948cfa0ad2SJack F Vogel } 24958cfa0ad2SJack F Vogel 24968cfa0ad2SJack F Vogel /** 24978cfa0ad2SJack F Vogel * e1000_read_flash_word_ich8lan - Read word from flash 24988cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 24998cfa0ad2SJack F Vogel * @offset: offset to data location 25008cfa0ad2SJack F Vogel * @data: pointer to the location for storing the data 25018cfa0ad2SJack F Vogel * 25028cfa0ad2SJack F Vogel * Reads the flash word at offset into data. Offset is converted 25038cfa0ad2SJack F Vogel * to bytes before read. 25048cfa0ad2SJack F Vogel **/ 25058cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, 25068cfa0ad2SJack F Vogel u16 *data) 25078cfa0ad2SJack F Vogel { 25088cfa0ad2SJack F Vogel s32 ret_val; 25098cfa0ad2SJack F Vogel 25108cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_word_ich8lan"); 25118cfa0ad2SJack F Vogel 25128cfa0ad2SJack F Vogel if (!data) { 25138cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 25148cfa0ad2SJack F Vogel goto out; 25158cfa0ad2SJack F Vogel } 25168cfa0ad2SJack F Vogel 25178cfa0ad2SJack F Vogel /* Must convert offset into bytes. */ 25188cfa0ad2SJack F Vogel offset <<= 1; 25198cfa0ad2SJack F Vogel 25208cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data); 25218cfa0ad2SJack F Vogel 25228cfa0ad2SJack F Vogel out: 25238cfa0ad2SJack F Vogel return ret_val; 25248cfa0ad2SJack F Vogel } 25258cfa0ad2SJack F Vogel 25268cfa0ad2SJack F Vogel /** 25278cfa0ad2SJack F Vogel * e1000_read_flash_byte_ich8lan - Read byte from flash 25288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 25298cfa0ad2SJack F Vogel * @offset: The offset of the byte to read. 25308cfa0ad2SJack F Vogel * @data: Pointer to a byte to store the value read. 25318cfa0ad2SJack F Vogel * 25328cfa0ad2SJack F Vogel * Reads a single byte from the NVM using the flash access registers. 25338cfa0ad2SJack F Vogel **/ 25348cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 25358cfa0ad2SJack F Vogel u8 *data) 25368cfa0ad2SJack F Vogel { 25378cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 25388cfa0ad2SJack F Vogel u16 word = 0; 25398cfa0ad2SJack F Vogel 25408cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); 25418cfa0ad2SJack F Vogel if (ret_val) 25428cfa0ad2SJack F Vogel goto out; 25438cfa0ad2SJack F Vogel 25448cfa0ad2SJack F Vogel *data = (u8)word; 25458cfa0ad2SJack F Vogel 25468cfa0ad2SJack F Vogel out: 25478cfa0ad2SJack F Vogel return ret_val; 25488cfa0ad2SJack F Vogel } 25498cfa0ad2SJack F Vogel 25508cfa0ad2SJack F Vogel /** 25518cfa0ad2SJack F Vogel * e1000_read_flash_data_ich8lan - Read byte or word from NVM 25528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 25538cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte or word to read. 25548cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 25558cfa0ad2SJack F Vogel * @data: Pointer to the word to store the value read. 25568cfa0ad2SJack F Vogel * 25578cfa0ad2SJack F Vogel * Reads a byte or word from the NVM using the flash access registers. 25588cfa0ad2SJack F Vogel **/ 25598cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 25608cfa0ad2SJack F Vogel u8 size, u16 *data) 25618cfa0ad2SJack F Vogel { 25628cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 25638cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 25648cfa0ad2SJack F Vogel u32 flash_linear_addr; 25658cfa0ad2SJack F Vogel u32 flash_data = 0; 25668cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 25678cfa0ad2SJack F Vogel u8 count = 0; 25688cfa0ad2SJack F Vogel 25698cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_data_ich8lan"); 25708cfa0ad2SJack F Vogel 25718cfa0ad2SJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 25728cfa0ad2SJack F Vogel goto out; 25738cfa0ad2SJack F Vogel 25748cfa0ad2SJack F Vogel flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + 25758cfa0ad2SJack F Vogel hw->nvm.flash_base_addr; 25768cfa0ad2SJack F Vogel 25778cfa0ad2SJack F Vogel do { 25788cfa0ad2SJack F Vogel usec_delay(1); 25798cfa0ad2SJack F Vogel /* Steps */ 25808cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 25818cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 25828cfa0ad2SJack F Vogel break; 25838cfa0ad2SJack F Vogel 25848cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 25858cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 25868cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 25878cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 25888cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 25898cfa0ad2SJack F Vogel 25908cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 25918cfa0ad2SJack F Vogel 25928cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 25938cfa0ad2SJack F Vogel ICH_FLASH_READ_COMMAND_TIMEOUT); 25948cfa0ad2SJack F Vogel 25958cfa0ad2SJack F Vogel /* 25968cfa0ad2SJack F Vogel * Check if FCERR is set to 1, if set to 1, clear it 25978cfa0ad2SJack F Vogel * and try the whole sequence a few more times, else 25988cfa0ad2SJack F Vogel * read in (shift in) the Flash Data0, the order is 25998cfa0ad2SJack F Vogel * least significant byte first msb to lsb 26008cfa0ad2SJack F Vogel */ 26018cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 26028cfa0ad2SJack F Vogel flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); 2603daf9197cSJack F Vogel if (size == 1) 26048cfa0ad2SJack F Vogel *data = (u8)(flash_data & 0x000000FF); 2605daf9197cSJack F Vogel else if (size == 2) 26068cfa0ad2SJack F Vogel *data = (u16)(flash_data & 0x0000FFFF); 26078cfa0ad2SJack F Vogel break; 26088cfa0ad2SJack F Vogel } else { 26098cfa0ad2SJack F Vogel /* 26108cfa0ad2SJack F Vogel * If we've gotten here, then things are probably 26118cfa0ad2SJack F Vogel * completely hosed, but if the error condition is 26128cfa0ad2SJack F Vogel * detected, it won't hurt to give it another try... 26138cfa0ad2SJack F Vogel * ICH_FLASH_CYCLE_REPEAT_COUNT times. 26148cfa0ad2SJack F Vogel */ 26158cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 26168cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 26178cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcerr == 1) { 26188cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 26198cfa0ad2SJack F Vogel continue; 26208cfa0ad2SJack F Vogel } else if (hsfsts.hsf_status.flcdone == 0) { 2621*4dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 26228cfa0ad2SJack F Vogel break; 26238cfa0ad2SJack F Vogel } 26248cfa0ad2SJack F Vogel } 26258cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 26268cfa0ad2SJack F Vogel 26278cfa0ad2SJack F Vogel out: 26288cfa0ad2SJack F Vogel return ret_val; 26298cfa0ad2SJack F Vogel } 26308cfa0ad2SJack F Vogel 26318cfa0ad2SJack F Vogel /** 26328cfa0ad2SJack F Vogel * e1000_write_nvm_ich8lan - Write word(s) to the NVM 26338cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 26348cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to write. 26358cfa0ad2SJack F Vogel * @words: Size of data to write in words 26368cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to write at offset. 26378cfa0ad2SJack F Vogel * 26388cfa0ad2SJack F Vogel * Writes a byte or word to the NVM using the flash access registers. 26398cfa0ad2SJack F Vogel **/ 26408cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 26418cfa0ad2SJack F Vogel u16 *data) 26428cfa0ad2SJack F Vogel { 26438cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 2644daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 26458cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 26468cfa0ad2SJack F Vogel u16 i; 26478cfa0ad2SJack F Vogel 26488cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_nvm_ich8lan"); 26498cfa0ad2SJack F Vogel 26508cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 26518cfa0ad2SJack F Vogel (words == 0)) { 26528cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 26538cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 26548cfa0ad2SJack F Vogel goto out; 26558cfa0ad2SJack F Vogel } 26568cfa0ad2SJack F Vogel 26574edd8523SJack F Vogel nvm->ops.acquire(hw); 26588cfa0ad2SJack F Vogel 26598cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 26608cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].modified = TRUE; 26618cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].value = data[i]; 26628cfa0ad2SJack F Vogel } 26638cfa0ad2SJack F Vogel 26648cfa0ad2SJack F Vogel nvm->ops.release(hw); 26658cfa0ad2SJack F Vogel 26668cfa0ad2SJack F Vogel out: 26678cfa0ad2SJack F Vogel return ret_val; 26688cfa0ad2SJack F Vogel } 26698cfa0ad2SJack F Vogel 26708cfa0ad2SJack F Vogel /** 26718cfa0ad2SJack F Vogel * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM 26728cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 26738cfa0ad2SJack F Vogel * 26748cfa0ad2SJack F Vogel * The NVM checksum is updated by calling the generic update_nvm_checksum, 26758cfa0ad2SJack F Vogel * which writes the checksum to the shadow ram. The changes in the shadow 26768cfa0ad2SJack F Vogel * ram are then committed to the EEPROM by processing each bank at a time 26778cfa0ad2SJack F Vogel * checking for the modified bit and writing only the pending changes. 26788cfa0ad2SJack F Vogel * After a successful commit, the shadow ram is cleared and is ready for 26798cfa0ad2SJack F Vogel * future writes. 26808cfa0ad2SJack F Vogel **/ 26818cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) 26828cfa0ad2SJack F Vogel { 26838cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 2684daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 26858cfa0ad2SJack F Vogel u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 26868cfa0ad2SJack F Vogel s32 ret_val; 26878cfa0ad2SJack F Vogel u16 data; 26888cfa0ad2SJack F Vogel 26898cfa0ad2SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_ich8lan"); 26908cfa0ad2SJack F Vogel 26918cfa0ad2SJack F Vogel ret_val = e1000_update_nvm_checksum_generic(hw); 26928cfa0ad2SJack F Vogel if (ret_val) 26938cfa0ad2SJack F Vogel goto out; 26948cfa0ad2SJack F Vogel 26958cfa0ad2SJack F Vogel if (nvm->type != e1000_nvm_flash_sw) 26968cfa0ad2SJack F Vogel goto out; 26978cfa0ad2SJack F Vogel 26984edd8523SJack F Vogel nvm->ops.acquire(hw); 26998cfa0ad2SJack F Vogel 27008cfa0ad2SJack F Vogel /* 27018cfa0ad2SJack F Vogel * We're writing to the opposite bank so if we're on bank 1, 27028cfa0ad2SJack F Vogel * write to bank 0 etc. We also need to erase the segment that 27038cfa0ad2SJack F Vogel * is going to be written 27048cfa0ad2SJack F Vogel */ 27058cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 2706d035aa2dSJack F Vogel if (ret_val != E1000_SUCCESS) { 27074edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 27084edd8523SJack F Vogel bank = 0; 2709d035aa2dSJack F Vogel } 27108cfa0ad2SJack F Vogel 27118cfa0ad2SJack F Vogel if (bank == 0) { 27128cfa0ad2SJack F Vogel new_bank_offset = nvm->flash_bank_size; 27138cfa0ad2SJack F Vogel old_bank_offset = 0; 2714d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 2715a69ed8dfSJack F Vogel if (ret_val) 2716a69ed8dfSJack F Vogel goto release; 27178cfa0ad2SJack F Vogel } else { 27188cfa0ad2SJack F Vogel old_bank_offset = nvm->flash_bank_size; 27198cfa0ad2SJack F Vogel new_bank_offset = 0; 2720d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 2721a69ed8dfSJack F Vogel if (ret_val) 2722a69ed8dfSJack F Vogel goto release; 27238cfa0ad2SJack F Vogel } 27248cfa0ad2SJack F Vogel 27258cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 27268cfa0ad2SJack F Vogel /* 27278cfa0ad2SJack F Vogel * Determine whether to write the value stored 27288cfa0ad2SJack F Vogel * in the other NVM bank or a modified value stored 27298cfa0ad2SJack F Vogel * in the shadow RAM 27308cfa0ad2SJack F Vogel */ 27318cfa0ad2SJack F Vogel if (dev_spec->shadow_ram[i].modified) { 27328cfa0ad2SJack F Vogel data = dev_spec->shadow_ram[i].value; 27338cfa0ad2SJack F Vogel } else { 2734d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, i + 2735d035aa2dSJack F Vogel old_bank_offset, 27368cfa0ad2SJack F Vogel &data); 2737d035aa2dSJack F Vogel if (ret_val) 2738d035aa2dSJack F Vogel break; 27398cfa0ad2SJack F Vogel } 27408cfa0ad2SJack F Vogel 27418cfa0ad2SJack F Vogel /* 27428cfa0ad2SJack F Vogel * If the word is 0x13, then make sure the signature bits 27438cfa0ad2SJack F Vogel * (15:14) are 11b until the commit has completed. 27448cfa0ad2SJack F Vogel * This will allow us to write 10b which indicates the 27458cfa0ad2SJack F Vogel * signature is valid. We want to do this after the write 27468cfa0ad2SJack F Vogel * has completed so that we don't mark the segment valid 27478cfa0ad2SJack F Vogel * while the write is still in progress 27488cfa0ad2SJack F Vogel */ 27498cfa0ad2SJack F Vogel if (i == E1000_ICH_NVM_SIG_WORD) 27508cfa0ad2SJack F Vogel data |= E1000_ICH_NVM_SIG_MASK; 27518cfa0ad2SJack F Vogel 27528cfa0ad2SJack F Vogel /* Convert offset to bytes. */ 27538cfa0ad2SJack F Vogel act_offset = (i + new_bank_offset) << 1; 27548cfa0ad2SJack F Vogel 27558cfa0ad2SJack F Vogel usec_delay(100); 27568cfa0ad2SJack F Vogel /* Write the bytes to the new bank. */ 27578cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 27588cfa0ad2SJack F Vogel act_offset, 27598cfa0ad2SJack F Vogel (u8)data); 27608cfa0ad2SJack F Vogel if (ret_val) 27618cfa0ad2SJack F Vogel break; 27628cfa0ad2SJack F Vogel 27638cfa0ad2SJack F Vogel usec_delay(100); 27648cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 27658cfa0ad2SJack F Vogel act_offset + 1, 27668cfa0ad2SJack F Vogel (u8)(data >> 8)); 27678cfa0ad2SJack F Vogel if (ret_val) 27688cfa0ad2SJack F Vogel break; 27698cfa0ad2SJack F Vogel } 27708cfa0ad2SJack F Vogel 27718cfa0ad2SJack F Vogel /* 27728cfa0ad2SJack F Vogel * Don't bother writing the segment valid bits if sector 27738cfa0ad2SJack F Vogel * programming failed. 27748cfa0ad2SJack F Vogel */ 27758cfa0ad2SJack F Vogel if (ret_val) { 27768cfa0ad2SJack F Vogel DEBUGOUT("Flash commit failed.\n"); 2777a69ed8dfSJack F Vogel goto release; 27788cfa0ad2SJack F Vogel } 27798cfa0ad2SJack F Vogel 27808cfa0ad2SJack F Vogel /* 27818cfa0ad2SJack F Vogel * Finally validate the new segment by setting bit 15:14 27828cfa0ad2SJack F Vogel * to 10b in word 0x13 , this can be done without an 27838cfa0ad2SJack F Vogel * erase as well since these bits are 11 to start with 27848cfa0ad2SJack F Vogel * and we need to change bit 14 to 0b 27858cfa0ad2SJack F Vogel */ 27868cfa0ad2SJack F Vogel act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 2787d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); 2788a69ed8dfSJack F Vogel if (ret_val) 2789a69ed8dfSJack F Vogel goto release; 27904edd8523SJack F Vogel 27918cfa0ad2SJack F Vogel data &= 0xBFFF; 27928cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 27938cfa0ad2SJack F Vogel act_offset * 2 + 1, 27948cfa0ad2SJack F Vogel (u8)(data >> 8)); 2795a69ed8dfSJack F Vogel if (ret_val) 2796a69ed8dfSJack F Vogel goto release; 27978cfa0ad2SJack F Vogel 27988cfa0ad2SJack F Vogel /* 27998cfa0ad2SJack F Vogel * And invalidate the previously valid segment by setting 28008cfa0ad2SJack F Vogel * its signature word (0x13) high_byte to 0b. This can be 28018cfa0ad2SJack F Vogel * done without an erase because flash erase sets all bits 28028cfa0ad2SJack F Vogel * to 1's. We can write 1's to 0's without an erase 28038cfa0ad2SJack F Vogel */ 28048cfa0ad2SJack F Vogel act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 28058cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); 2806a69ed8dfSJack F Vogel if (ret_val) 2807a69ed8dfSJack F Vogel goto release; 28088cfa0ad2SJack F Vogel 28098cfa0ad2SJack F Vogel /* Great! Everything worked, we can now clear the cached entries. */ 28108cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 28118cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 28128cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 28138cfa0ad2SJack F Vogel } 28148cfa0ad2SJack F Vogel 2815a69ed8dfSJack F Vogel release: 28168cfa0ad2SJack F Vogel nvm->ops.release(hw); 28178cfa0ad2SJack F Vogel 28188cfa0ad2SJack F Vogel /* 28198cfa0ad2SJack F Vogel * Reload the EEPROM, or else modifications will not appear 28208cfa0ad2SJack F Vogel * until after the next adapter reset. 28218cfa0ad2SJack F Vogel */ 2822a69ed8dfSJack F Vogel if (!ret_val) { 28238cfa0ad2SJack F Vogel nvm->ops.reload(hw); 28248cfa0ad2SJack F Vogel msec_delay(10); 2825a69ed8dfSJack F Vogel } 28268cfa0ad2SJack F Vogel 28278cfa0ad2SJack F Vogel out: 2828d035aa2dSJack F Vogel if (ret_val) 2829d035aa2dSJack F Vogel DEBUGOUT1("NVM update error: %d\n", ret_val); 2830d035aa2dSJack F Vogel 28318cfa0ad2SJack F Vogel return ret_val; 28328cfa0ad2SJack F Vogel } 28338cfa0ad2SJack F Vogel 28348cfa0ad2SJack F Vogel /** 28358cfa0ad2SJack F Vogel * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum 28368cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 28378cfa0ad2SJack F Vogel * 28388cfa0ad2SJack F Vogel * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. 2839daf9197cSJack F Vogel * If the bit is 0, that the EEPROM had been modified, but the checksum was not 2840daf9197cSJack F Vogel * calculated, in which case we need to calculate the checksum and set bit 6. 28418cfa0ad2SJack F Vogel **/ 28428cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) 28438cfa0ad2SJack F Vogel { 28448cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 28458cfa0ad2SJack F Vogel u16 data; 28468cfa0ad2SJack F Vogel 28478cfa0ad2SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan"); 28488cfa0ad2SJack F Vogel 28498cfa0ad2SJack F Vogel /* 28508cfa0ad2SJack F Vogel * Read 0x19 and check bit 6. If this bit is 0, the checksum 28518cfa0ad2SJack F Vogel * needs to be fixed. This bit is an indication that the NVM 28528cfa0ad2SJack F Vogel * was prepared by OEM software and did not calculate the 28538cfa0ad2SJack F Vogel * checksum...a likely scenario. 28548cfa0ad2SJack F Vogel */ 28558cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data); 28568cfa0ad2SJack F Vogel if (ret_val) 28578cfa0ad2SJack F Vogel goto out; 28588cfa0ad2SJack F Vogel 28598cfa0ad2SJack F Vogel if ((data & 0x40) == 0) { 28608cfa0ad2SJack F Vogel data |= 0x40; 28618cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data); 28628cfa0ad2SJack F Vogel if (ret_val) 28638cfa0ad2SJack F Vogel goto out; 28648cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.update(hw); 28658cfa0ad2SJack F Vogel if (ret_val) 28668cfa0ad2SJack F Vogel goto out; 28678cfa0ad2SJack F Vogel } 28688cfa0ad2SJack F Vogel 28698cfa0ad2SJack F Vogel ret_val = e1000_validate_nvm_checksum_generic(hw); 28708cfa0ad2SJack F Vogel 28718cfa0ad2SJack F Vogel out: 28728cfa0ad2SJack F Vogel return ret_val; 28738cfa0ad2SJack F Vogel } 28748cfa0ad2SJack F Vogel 28758cfa0ad2SJack F Vogel /** 28768cfa0ad2SJack F Vogel * e1000_write_flash_data_ich8lan - Writes bytes to the NVM 28778cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 28788cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte/word to read. 28798cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 28808cfa0ad2SJack F Vogel * @data: The byte(s) to write to the NVM. 28818cfa0ad2SJack F Vogel * 28828cfa0ad2SJack F Vogel * Writes one/two bytes to the NVM using the flash access registers. 28838cfa0ad2SJack F Vogel **/ 28848cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 28858cfa0ad2SJack F Vogel u8 size, u16 data) 28868cfa0ad2SJack F Vogel { 28878cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 28888cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 28898cfa0ad2SJack F Vogel u32 flash_linear_addr; 28908cfa0ad2SJack F Vogel u32 flash_data = 0; 28918cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 28928cfa0ad2SJack F Vogel u8 count = 0; 28938cfa0ad2SJack F Vogel 28948cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_ich8_data"); 28958cfa0ad2SJack F Vogel 28968cfa0ad2SJack F Vogel if (size < 1 || size > 2 || data > size * 0xff || 28978cfa0ad2SJack F Vogel offset > ICH_FLASH_LINEAR_ADDR_MASK) 28988cfa0ad2SJack F Vogel goto out; 28998cfa0ad2SJack F Vogel 29008cfa0ad2SJack F Vogel flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + 29018cfa0ad2SJack F Vogel hw->nvm.flash_base_addr; 29028cfa0ad2SJack F Vogel 29038cfa0ad2SJack F Vogel do { 29048cfa0ad2SJack F Vogel usec_delay(1); 29058cfa0ad2SJack F Vogel /* Steps */ 29068cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 29078cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 29088cfa0ad2SJack F Vogel break; 29098cfa0ad2SJack F Vogel 29108cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 29118cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 29128cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 29138cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 29148cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 29158cfa0ad2SJack F Vogel 29168cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 29178cfa0ad2SJack F Vogel 29188cfa0ad2SJack F Vogel if (size == 1) 29198cfa0ad2SJack F Vogel flash_data = (u32)data & 0x00FF; 29208cfa0ad2SJack F Vogel else 29218cfa0ad2SJack F Vogel flash_data = (u32)data; 29228cfa0ad2SJack F Vogel 29238cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data); 29248cfa0ad2SJack F Vogel 29258cfa0ad2SJack F Vogel /* 29268cfa0ad2SJack F Vogel * check if FCERR is set to 1 , if set to 1, clear it 29278cfa0ad2SJack F Vogel * and try the whole sequence a few more times else done 29288cfa0ad2SJack F Vogel */ 29298cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 29308cfa0ad2SJack F Vogel ICH_FLASH_WRITE_COMMAND_TIMEOUT); 2931daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 29328cfa0ad2SJack F Vogel break; 2933daf9197cSJack F Vogel 29348cfa0ad2SJack F Vogel /* 29358cfa0ad2SJack F Vogel * If we're here, then things are most likely 29368cfa0ad2SJack F Vogel * completely hosed, but if the error condition 29378cfa0ad2SJack F Vogel * is detected, it won't hurt to give it another 29388cfa0ad2SJack F Vogel * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 29398cfa0ad2SJack F Vogel */ 2940daf9197cSJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 29414edd8523SJack F Vogel if (hsfsts.hsf_status.flcerr == 1) 29428cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 29438cfa0ad2SJack F Vogel continue; 29444edd8523SJack F Vogel if (hsfsts.hsf_status.flcdone == 0) { 2945*4dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 29468cfa0ad2SJack F Vogel break; 29478cfa0ad2SJack F Vogel } 29488cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 29498cfa0ad2SJack F Vogel 29508cfa0ad2SJack F Vogel out: 29518cfa0ad2SJack F Vogel return ret_val; 29528cfa0ad2SJack F Vogel } 29538cfa0ad2SJack F Vogel 29548cfa0ad2SJack F Vogel /** 29558cfa0ad2SJack F Vogel * e1000_write_flash_byte_ich8lan - Write a single byte to NVM 29568cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 29578cfa0ad2SJack F Vogel * @offset: The index of the byte to read. 29588cfa0ad2SJack F Vogel * @data: The byte to write to the NVM. 29598cfa0ad2SJack F Vogel * 29608cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 29618cfa0ad2SJack F Vogel **/ 29628cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 29638cfa0ad2SJack F Vogel u8 data) 29648cfa0ad2SJack F Vogel { 29658cfa0ad2SJack F Vogel u16 word = (u16)data; 29668cfa0ad2SJack F Vogel 29678cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_flash_byte_ich8lan"); 29688cfa0ad2SJack F Vogel 29698cfa0ad2SJack F Vogel return e1000_write_flash_data_ich8lan(hw, offset, 1, word); 29708cfa0ad2SJack F Vogel } 29718cfa0ad2SJack F Vogel 29728cfa0ad2SJack F Vogel /** 29738cfa0ad2SJack F Vogel * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM 29748cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 29758cfa0ad2SJack F Vogel * @offset: The offset of the byte to write. 29768cfa0ad2SJack F Vogel * @byte: The byte to write to the NVM. 29778cfa0ad2SJack F Vogel * 29788cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 29798cfa0ad2SJack F Vogel * Goes through a retry algorithm before giving up. 29808cfa0ad2SJack F Vogel **/ 29818cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 29828cfa0ad2SJack F Vogel u32 offset, u8 byte) 29838cfa0ad2SJack F Vogel { 29848cfa0ad2SJack F Vogel s32 ret_val; 29858cfa0ad2SJack F Vogel u16 program_retries; 29868cfa0ad2SJack F Vogel 29878cfa0ad2SJack F Vogel DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan"); 29888cfa0ad2SJack F Vogel 29898cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 29908cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) 29918cfa0ad2SJack F Vogel goto out; 29928cfa0ad2SJack F Vogel 29938cfa0ad2SJack F Vogel for (program_retries = 0; program_retries < 100; program_retries++) { 29948cfa0ad2SJack F Vogel DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset); 29958cfa0ad2SJack F Vogel usec_delay(100); 29968cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 29978cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) 29988cfa0ad2SJack F Vogel break; 29998cfa0ad2SJack F Vogel } 30008cfa0ad2SJack F Vogel if (program_retries == 100) { 30018cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 30028cfa0ad2SJack F Vogel goto out; 30038cfa0ad2SJack F Vogel } 30048cfa0ad2SJack F Vogel 30058cfa0ad2SJack F Vogel out: 30068cfa0ad2SJack F Vogel return ret_val; 30078cfa0ad2SJack F Vogel } 30088cfa0ad2SJack F Vogel 30098cfa0ad2SJack F Vogel /** 30108cfa0ad2SJack F Vogel * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM 30118cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 30128cfa0ad2SJack F Vogel * @bank: 0 for first bank, 1 for second bank, etc. 30138cfa0ad2SJack F Vogel * 30148cfa0ad2SJack F Vogel * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. 30158cfa0ad2SJack F Vogel * bank N is 4096 * N + flash_reg_addr. 30168cfa0ad2SJack F Vogel **/ 30178cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) 30188cfa0ad2SJack F Vogel { 30198cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 30208cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 30218cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 30228cfa0ad2SJack F Vogel u32 flash_linear_addr; 30238cfa0ad2SJack F Vogel /* bank size is in 16bit words - adjust to bytes */ 30248cfa0ad2SJack F Vogel u32 flash_bank_size = nvm->flash_bank_size * 2; 30258cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 30268cfa0ad2SJack F Vogel s32 count = 0; 30278cfa0ad2SJack F Vogel s32 j, iteration, sector_size; 30288cfa0ad2SJack F Vogel 30298cfa0ad2SJack F Vogel DEBUGFUNC("e1000_erase_flash_bank_ich8lan"); 30308cfa0ad2SJack F Vogel 30318cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 30328cfa0ad2SJack F Vogel 30338cfa0ad2SJack F Vogel /* 30348cfa0ad2SJack F Vogel * Determine HW Sector size: Read BERASE bits of hw flash status 30358cfa0ad2SJack F Vogel * register 30368cfa0ad2SJack F Vogel * 00: The Hw sector is 256 bytes, hence we need to erase 16 30378cfa0ad2SJack F Vogel * consecutive sectors. The start index for the nth Hw sector 30388cfa0ad2SJack F Vogel * can be calculated as = bank * 4096 + n * 256 30398cfa0ad2SJack F Vogel * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. 30408cfa0ad2SJack F Vogel * The start index for the nth Hw sector can be calculated 30418cfa0ad2SJack F Vogel * as = bank * 4096 30428cfa0ad2SJack F Vogel * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 30438cfa0ad2SJack F Vogel * (ich9 only, otherwise error condition) 30448cfa0ad2SJack F Vogel * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 30458cfa0ad2SJack F Vogel */ 30468cfa0ad2SJack F Vogel switch (hsfsts.hsf_status.berasesz) { 30478cfa0ad2SJack F Vogel case 0: 30488cfa0ad2SJack F Vogel /* Hw sector size 256 */ 30498cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_256; 30508cfa0ad2SJack F Vogel iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; 30518cfa0ad2SJack F Vogel break; 30528cfa0ad2SJack F Vogel case 1: 30538cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_4K; 30549d81738fSJack F Vogel iteration = 1; 30558cfa0ad2SJack F Vogel break; 30568cfa0ad2SJack F Vogel case 2: 30578cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_8K; 30588bd0025fSJack F Vogel iteration = 1; 30598cfa0ad2SJack F Vogel break; 30608cfa0ad2SJack F Vogel case 3: 30618cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_64K; 30629d81738fSJack F Vogel iteration = 1; 30638cfa0ad2SJack F Vogel break; 30648cfa0ad2SJack F Vogel default: 30658cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 30668cfa0ad2SJack F Vogel goto out; 30678cfa0ad2SJack F Vogel } 30688cfa0ad2SJack F Vogel 30698cfa0ad2SJack F Vogel /* Start with the base address, then add the sector offset. */ 30708cfa0ad2SJack F Vogel flash_linear_addr = hw->nvm.flash_base_addr; 30714edd8523SJack F Vogel flash_linear_addr += (bank) ? flash_bank_size : 0; 30728cfa0ad2SJack F Vogel 30738cfa0ad2SJack F Vogel for (j = 0; j < iteration ; j++) { 30748cfa0ad2SJack F Vogel do { 30758cfa0ad2SJack F Vogel /* Steps */ 30768cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 30778cfa0ad2SJack F Vogel if (ret_val) 30788cfa0ad2SJack F Vogel goto out; 30798cfa0ad2SJack F Vogel 30808cfa0ad2SJack F Vogel /* 30818cfa0ad2SJack F Vogel * Write a value 11 (block Erase) in Flash 30828cfa0ad2SJack F Vogel * Cycle field in hw flash control 30838cfa0ad2SJack F Vogel */ 30848cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, 30858cfa0ad2SJack F Vogel ICH_FLASH_HSFCTL); 30868cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; 3087daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 30888cfa0ad2SJack F Vogel hsflctl.regval); 30898cfa0ad2SJack F Vogel 30908cfa0ad2SJack F Vogel /* 30918cfa0ad2SJack F Vogel * Write the last 24 bits of an index within the 30928cfa0ad2SJack F Vogel * block into Flash Linear address field in Flash 30938cfa0ad2SJack F Vogel * Address. 30948cfa0ad2SJack F Vogel */ 30958cfa0ad2SJack F Vogel flash_linear_addr += (j * sector_size); 3096daf9197cSJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, 30978cfa0ad2SJack F Vogel flash_linear_addr); 30988cfa0ad2SJack F Vogel 30998cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 31008cfa0ad2SJack F Vogel ICH_FLASH_ERASE_COMMAND_TIMEOUT); 3101daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 31028cfa0ad2SJack F Vogel break; 3103daf9197cSJack F Vogel 31048cfa0ad2SJack F Vogel /* 31058cfa0ad2SJack F Vogel * Check if FCERR is set to 1. If 1, 31068cfa0ad2SJack F Vogel * clear it and try the whole sequence 31078cfa0ad2SJack F Vogel * a few more times else Done 31088cfa0ad2SJack F Vogel */ 31098cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 31108cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 3111daf9197cSJack F Vogel if (hsfsts.hsf_status.flcerr == 1) 3112daf9197cSJack F Vogel /* repeat for some time before giving up */ 31138cfa0ad2SJack F Vogel continue; 3114daf9197cSJack F Vogel else if (hsfsts.hsf_status.flcdone == 0) 31158cfa0ad2SJack F Vogel goto out; 31168cfa0ad2SJack F Vogel } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); 31178cfa0ad2SJack F Vogel } 31188cfa0ad2SJack F Vogel 31198cfa0ad2SJack F Vogel out: 31208cfa0ad2SJack F Vogel return ret_val; 31218cfa0ad2SJack F Vogel } 31228cfa0ad2SJack F Vogel 31238cfa0ad2SJack F Vogel /** 31248cfa0ad2SJack F Vogel * e1000_valid_led_default_ich8lan - Set the default LED settings 31258cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 31268cfa0ad2SJack F Vogel * @data: Pointer to the LED settings 31278cfa0ad2SJack F Vogel * 31288cfa0ad2SJack F Vogel * Reads the LED default settings from the NVM to data. If the NVM LED 31298cfa0ad2SJack F Vogel * settings is all 0's or F's, set the LED default to a valid LED default 31308cfa0ad2SJack F Vogel * setting. 31318cfa0ad2SJack F Vogel **/ 31328cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) 31338cfa0ad2SJack F Vogel { 31348cfa0ad2SJack F Vogel s32 ret_val; 31358cfa0ad2SJack F Vogel 31368cfa0ad2SJack F Vogel DEBUGFUNC("e1000_valid_led_default_ich8lan"); 31378cfa0ad2SJack F Vogel 31388cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 31398cfa0ad2SJack F Vogel if (ret_val) { 31408cfa0ad2SJack F Vogel DEBUGOUT("NVM Read Error\n"); 31418cfa0ad2SJack F Vogel goto out; 31428cfa0ad2SJack F Vogel } 31438cfa0ad2SJack F Vogel 3144*4dab5c37SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) 31458cfa0ad2SJack F Vogel *data = ID_LED_DEFAULT_ICH8LAN; 31468cfa0ad2SJack F Vogel 31478cfa0ad2SJack F Vogel out: 31488cfa0ad2SJack F Vogel return ret_val; 31498cfa0ad2SJack F Vogel } 31508cfa0ad2SJack F Vogel 31518cfa0ad2SJack F Vogel /** 31529d81738fSJack F Vogel * e1000_id_led_init_pchlan - store LED configurations 31539d81738fSJack F Vogel * @hw: pointer to the HW structure 31549d81738fSJack F Vogel * 31559d81738fSJack F Vogel * PCH does not control LEDs via the LEDCTL register, rather it uses 31569d81738fSJack F Vogel * the PHY LED configuration register. 31579d81738fSJack F Vogel * 31589d81738fSJack F Vogel * PCH also does not have an "always on" or "always off" mode which 31599d81738fSJack F Vogel * complicates the ID feature. Instead of using the "on" mode to indicate 31609d81738fSJack F Vogel * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()), 31619d81738fSJack F Vogel * use "link_up" mode. The LEDs will still ID on request if there is no 31629d81738fSJack F Vogel * link based on logic in e1000_led_[on|off]_pchlan(). 31639d81738fSJack F Vogel **/ 31649d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) 31659d81738fSJack F Vogel { 31669d81738fSJack F Vogel struct e1000_mac_info *mac = &hw->mac; 31679d81738fSJack F Vogel s32 ret_val; 31689d81738fSJack F Vogel const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; 31699d81738fSJack F Vogel const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; 31709d81738fSJack F Vogel u16 data, i, temp, shift; 31719d81738fSJack F Vogel 31729d81738fSJack F Vogel DEBUGFUNC("e1000_id_led_init_pchlan"); 31739d81738fSJack F Vogel 31749d81738fSJack F Vogel /* Get default ID LED modes */ 31759d81738fSJack F Vogel ret_val = hw->nvm.ops.valid_led_default(hw, &data); 31769d81738fSJack F Vogel if (ret_val) 31779d81738fSJack F Vogel goto out; 31789d81738fSJack F Vogel 31799d81738fSJack F Vogel mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); 31809d81738fSJack F Vogel mac->ledctl_mode1 = mac->ledctl_default; 31819d81738fSJack F Vogel mac->ledctl_mode2 = mac->ledctl_default; 31829d81738fSJack F Vogel 31839d81738fSJack F Vogel for (i = 0; i < 4; i++) { 31849d81738fSJack F Vogel temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; 31859d81738fSJack F Vogel shift = (i * 5); 31869d81738fSJack F Vogel switch (temp) { 31879d81738fSJack F Vogel case ID_LED_ON1_DEF2: 31889d81738fSJack F Vogel case ID_LED_ON1_ON2: 31899d81738fSJack F Vogel case ID_LED_ON1_OFF2: 31909d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 31919d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_on << shift); 31929d81738fSJack F Vogel break; 31939d81738fSJack F Vogel case ID_LED_OFF1_DEF2: 31949d81738fSJack F Vogel case ID_LED_OFF1_ON2: 31959d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 31969d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 31979d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_off << shift); 31989d81738fSJack F Vogel break; 31999d81738fSJack F Vogel default: 32009d81738fSJack F Vogel /* Do nothing */ 32019d81738fSJack F Vogel break; 32029d81738fSJack F Vogel } 32039d81738fSJack F Vogel switch (temp) { 32049d81738fSJack F Vogel case ID_LED_DEF1_ON2: 32059d81738fSJack F Vogel case ID_LED_ON1_ON2: 32069d81738fSJack F Vogel case ID_LED_OFF1_ON2: 32079d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 32089d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_on << shift); 32099d81738fSJack F Vogel break; 32109d81738fSJack F Vogel case ID_LED_DEF1_OFF2: 32119d81738fSJack F Vogel case ID_LED_ON1_OFF2: 32129d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 32139d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 32149d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_off << shift); 32159d81738fSJack F Vogel break; 32169d81738fSJack F Vogel default: 32179d81738fSJack F Vogel /* Do nothing */ 32189d81738fSJack F Vogel break; 32199d81738fSJack F Vogel } 32209d81738fSJack F Vogel } 32219d81738fSJack F Vogel 32229d81738fSJack F Vogel out: 32239d81738fSJack F Vogel return ret_val; 32249d81738fSJack F Vogel } 32259d81738fSJack F Vogel 32269d81738fSJack F Vogel /** 32278cfa0ad2SJack F Vogel * e1000_get_bus_info_ich8lan - Get/Set the bus type and width 32288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 32298cfa0ad2SJack F Vogel * 32308cfa0ad2SJack F Vogel * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability 3231*4dab5c37SJack F Vogel * register, so the the bus width is hard coded. 32328cfa0ad2SJack F Vogel **/ 32338cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) 32348cfa0ad2SJack F Vogel { 32358cfa0ad2SJack F Vogel struct e1000_bus_info *bus = &hw->bus; 32368cfa0ad2SJack F Vogel s32 ret_val; 32378cfa0ad2SJack F Vogel 32388cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_bus_info_ich8lan"); 32398cfa0ad2SJack F Vogel 32408cfa0ad2SJack F Vogel ret_val = e1000_get_bus_info_pcie_generic(hw); 32418cfa0ad2SJack F Vogel 32428cfa0ad2SJack F Vogel /* 32438cfa0ad2SJack F Vogel * ICH devices are "PCI Express"-ish. They have 32448cfa0ad2SJack F Vogel * a configuration space, but do not contain 32458cfa0ad2SJack F Vogel * PCI Express Capability registers, so bus width 32468cfa0ad2SJack F Vogel * must be hardcoded. 32478cfa0ad2SJack F Vogel */ 32488cfa0ad2SJack F Vogel if (bus->width == e1000_bus_width_unknown) 32498cfa0ad2SJack F Vogel bus->width = e1000_bus_width_pcie_x1; 32508cfa0ad2SJack F Vogel 32518cfa0ad2SJack F Vogel return ret_val; 32528cfa0ad2SJack F Vogel } 32538cfa0ad2SJack F Vogel 32548cfa0ad2SJack F Vogel /** 32558cfa0ad2SJack F Vogel * e1000_reset_hw_ich8lan - Reset the hardware 32568cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 32578cfa0ad2SJack F Vogel * 32588cfa0ad2SJack F Vogel * Does a full reset of the hardware which includes a reset of the PHY and 32598cfa0ad2SJack F Vogel * MAC. 32608cfa0ad2SJack F Vogel **/ 32618cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) 32628cfa0ad2SJack F Vogel { 32634edd8523SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 32644edd8523SJack F Vogel u16 reg; 3265730d3130SJack F Vogel u32 ctrl, kab; 32668cfa0ad2SJack F Vogel s32 ret_val; 32678cfa0ad2SJack F Vogel 32688cfa0ad2SJack F Vogel DEBUGFUNC("e1000_reset_hw_ich8lan"); 32698cfa0ad2SJack F Vogel 32708cfa0ad2SJack F Vogel /* 32718cfa0ad2SJack F Vogel * Prevent the PCI-E bus from sticking if there is no TLP connection 32728cfa0ad2SJack F Vogel * on the last TLP read/write transaction when MAC is reset. 32738cfa0ad2SJack F Vogel */ 32748cfa0ad2SJack F Vogel ret_val = e1000_disable_pcie_master_generic(hw); 3275daf9197cSJack F Vogel if (ret_val) 32768cfa0ad2SJack F Vogel DEBUGOUT("PCI-E Master disable polling has failed.\n"); 32778cfa0ad2SJack F Vogel 32788cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n"); 32798cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 32808cfa0ad2SJack F Vogel 32818cfa0ad2SJack F Vogel /* 32828cfa0ad2SJack F Vogel * Disable the Transmit and Receive units. Then delay to allow 32838cfa0ad2SJack F Vogel * any pending transactions to complete before we hit the MAC 32848cfa0ad2SJack F Vogel * with the global reset. 32858cfa0ad2SJack F Vogel */ 32868cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, 0); 32878cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); 32888cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw); 32898cfa0ad2SJack F Vogel 32908cfa0ad2SJack F Vogel msec_delay(10); 32918cfa0ad2SJack F Vogel 32928cfa0ad2SJack F Vogel /* Workaround for ICH8 bit corruption issue in FIFO memory */ 32938cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 32948cfa0ad2SJack F Vogel /* Set Tx and Rx buffer allocation to 8k apiece. */ 32958cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K); 32968cfa0ad2SJack F Vogel /* Set Packet Buffer Size to 16k. */ 32978cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); 32988cfa0ad2SJack F Vogel } 32998cfa0ad2SJack F Vogel 33004edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) { 33014edd8523SJack F Vogel /* Save the NVM K1 bit setting*/ 33024edd8523SJack F Vogel ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®); 33034edd8523SJack F Vogel if (ret_val) 33044edd8523SJack F Vogel return ret_val; 33054edd8523SJack F Vogel 33064edd8523SJack F Vogel if (reg & E1000_NVM_K1_ENABLE) 33074edd8523SJack F Vogel dev_spec->nvm_k1_enabled = TRUE; 33084edd8523SJack F Vogel else 33094edd8523SJack F Vogel dev_spec->nvm_k1_enabled = FALSE; 33104edd8523SJack F Vogel } 33114edd8523SJack F Vogel 33128cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 33138cfa0ad2SJack F Vogel 33147d9119bdSJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) { 33158cfa0ad2SJack F Vogel /* 33167d9119bdSJack F Vogel * Full-chip reset requires MAC and PHY reset at the same 33178cfa0ad2SJack F Vogel * time to make sure the interface between MAC and the 33188cfa0ad2SJack F Vogel * external PHY is reset. 33198cfa0ad2SJack F Vogel */ 33208cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_PHY_RST; 33217d9119bdSJack F Vogel 33227d9119bdSJack F Vogel /* 33237d9119bdSJack F Vogel * Gate automatic PHY configuration by hardware on 33247d9119bdSJack F Vogel * non-managed 82579 33257d9119bdSJack F Vogel */ 33267d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 33277d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 33287d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 33298cfa0ad2SJack F Vogel } 33308cfa0ad2SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 3331daf9197cSJack F Vogel DEBUGOUT("Issuing a global reset to ich8lan\n"); 33328cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); 3333*4dab5c37SJack F Vogel /* cannot issue a flush here because it hangs the hardware */ 33348cfa0ad2SJack F Vogel msec_delay(20); 33358cfa0ad2SJack F Vogel 33369d81738fSJack F Vogel if (!ret_val) 3337*4dab5c37SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); 33389d81738fSJack F Vogel 33397d9119bdSJack F Vogel if (ctrl & E1000_CTRL_PHY_RST) { 33409d81738fSJack F Vogel ret_val = hw->phy.ops.get_cfg_done(hw); 33414edd8523SJack F Vogel if (ret_val) 33424edd8523SJack F Vogel goto out; 33434edd8523SJack F Vogel 33447d9119bdSJack F Vogel ret_val = e1000_post_phy_reset_ich8lan(hw); 33454edd8523SJack F Vogel if (ret_val) 33464edd8523SJack F Vogel goto out; 33477d9119bdSJack F Vogel } 33487d9119bdSJack F Vogel 33494edd8523SJack F Vogel /* 33504edd8523SJack F Vogel * For PCH, this write will make sure that any noise 33514edd8523SJack F Vogel * will be detected as a CRC error and be dropped rather than show up 33524edd8523SJack F Vogel * as a bad packet to the DMA engine. 33534edd8523SJack F Vogel */ 33544edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) 33554edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565); 33568cfa0ad2SJack F Vogel 33578cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 3358730d3130SJack F Vogel E1000_READ_REG(hw, E1000_ICR); 33598cfa0ad2SJack F Vogel 33608cfa0ad2SJack F Vogel kab = E1000_READ_REG(hw, E1000_KABGTXD); 33618cfa0ad2SJack F Vogel kab |= E1000_KABGTXD_BGSQLBIAS; 33628cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_KABGTXD, kab); 33638cfa0ad2SJack F Vogel 33644edd8523SJack F Vogel out: 33658cfa0ad2SJack F Vogel return ret_val; 33668cfa0ad2SJack F Vogel } 33678cfa0ad2SJack F Vogel 33688cfa0ad2SJack F Vogel /** 33698cfa0ad2SJack F Vogel * e1000_init_hw_ich8lan - Initialize the hardware 33708cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 33718cfa0ad2SJack F Vogel * 33728cfa0ad2SJack F Vogel * Prepares the hardware for transmit and receive by doing the following: 33738cfa0ad2SJack F Vogel * - initialize hardware bits 33748cfa0ad2SJack F Vogel * - initialize LED identification 33758cfa0ad2SJack F Vogel * - setup receive address registers 33768cfa0ad2SJack F Vogel * - setup flow control 33778cfa0ad2SJack F Vogel * - setup transmit descriptors 33788cfa0ad2SJack F Vogel * - clear statistics 33798cfa0ad2SJack F Vogel **/ 33808cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) 33818cfa0ad2SJack F Vogel { 33828cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 33838cfa0ad2SJack F Vogel u32 ctrl_ext, txdctl, snoop; 33848cfa0ad2SJack F Vogel s32 ret_val; 33858cfa0ad2SJack F Vogel u16 i; 33868cfa0ad2SJack F Vogel 33878cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_hw_ich8lan"); 33888cfa0ad2SJack F Vogel 33898cfa0ad2SJack F Vogel e1000_initialize_hw_bits_ich8lan(hw); 33908cfa0ad2SJack F Vogel 33918cfa0ad2SJack F Vogel /* Initialize identification LED */ 3392d035aa2dSJack F Vogel ret_val = mac->ops.id_led_init(hw); 3393d035aa2dSJack F Vogel if (ret_val) 3394d035aa2dSJack F Vogel DEBUGOUT("Error initializing identification LED\n"); 33954edd8523SJack F Vogel /* This is not fatal and we should not stop init due to this */ 33968cfa0ad2SJack F Vogel 33978cfa0ad2SJack F Vogel /* Setup the receive address. */ 33988cfa0ad2SJack F Vogel e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); 33998cfa0ad2SJack F Vogel 34008cfa0ad2SJack F Vogel /* Zero out the Multicast HASH table */ 34018cfa0ad2SJack F Vogel DEBUGOUT("Zeroing the MTA\n"); 34028cfa0ad2SJack F Vogel for (i = 0; i < mac->mta_reg_count; i++) 34038cfa0ad2SJack F Vogel E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 34048cfa0ad2SJack F Vogel 34059d81738fSJack F Vogel /* 34069d81738fSJack F Vogel * The 82578 Rx buffer will stall if wakeup is enabled in host and 3407*4dab5c37SJack F Vogel * the ME. Disable wakeup by clearing the host wakeup bit. 34089d81738fSJack F Vogel * Reset the phy after disabling host wakeup to reset the Rx buffer. 34099d81738fSJack F Vogel */ 34109d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 3411*4dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i); 3412*4dab5c37SJack F Vogel i &= ~BM_WUC_HOST_WU_BIT; 3413*4dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i); 34149d81738fSJack F Vogel ret_val = e1000_phy_hw_reset_ich8lan(hw); 34159d81738fSJack F Vogel if (ret_val) 34169d81738fSJack F Vogel return ret_val; 34179d81738fSJack F Vogel } 34189d81738fSJack F Vogel 34198cfa0ad2SJack F Vogel /* Setup link and flow control */ 34208cfa0ad2SJack F Vogel ret_val = mac->ops.setup_link(hw); 34218cfa0ad2SJack F Vogel 34228cfa0ad2SJack F Vogel /* Set the transmit descriptor write-back policy for both queues */ 34238cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); 34248cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | 34258cfa0ad2SJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB; 34268cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | 34278cfa0ad2SJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH; 34288cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); 34298cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1)); 34308cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | 34318cfa0ad2SJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB; 34328cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | 34338cfa0ad2SJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH; 34348cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl); 34358cfa0ad2SJack F Vogel 34368cfa0ad2SJack F Vogel /* 34378cfa0ad2SJack F Vogel * ICH8 has opposite polarity of no_snoop bits. 34388cfa0ad2SJack F Vogel * By default, we should use snoop behavior. 34398cfa0ad2SJack F Vogel */ 34408cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 34418cfa0ad2SJack F Vogel snoop = PCIE_ICH8_SNOOP_ALL; 34428cfa0ad2SJack F Vogel else 34438cfa0ad2SJack F Vogel snoop = (u32) ~(PCIE_NO_SNOOP_ALL); 34448cfa0ad2SJack F Vogel e1000_set_pcie_no_snoop_generic(hw, snoop); 34458cfa0ad2SJack F Vogel 34468cfa0ad2SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 34478cfa0ad2SJack F Vogel ctrl_ext |= E1000_CTRL_EXT_RO_DIS; 34488cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 34498cfa0ad2SJack F Vogel 34508cfa0ad2SJack F Vogel /* 34518cfa0ad2SJack F Vogel * Clear all of the statistics registers (clear on read). It is 34528cfa0ad2SJack F Vogel * important that we do this after we have tried to establish link 34538cfa0ad2SJack F Vogel * because the symbol error count will increment wildly if there 34548cfa0ad2SJack F Vogel * is no link. 34558cfa0ad2SJack F Vogel */ 34568cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_ich8lan(hw); 34578cfa0ad2SJack F Vogel 34588cfa0ad2SJack F Vogel return ret_val; 34598cfa0ad2SJack F Vogel } 34608cfa0ad2SJack F Vogel /** 34618cfa0ad2SJack F Vogel * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits 34628cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 34638cfa0ad2SJack F Vogel * 34648cfa0ad2SJack F Vogel * Sets/Clears required hardware bits necessary for correctly setting up the 34658cfa0ad2SJack F Vogel * hardware for transmit and receive. 34668cfa0ad2SJack F Vogel **/ 34678cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) 34688cfa0ad2SJack F Vogel { 34698cfa0ad2SJack F Vogel u32 reg; 34708cfa0ad2SJack F Vogel 34718cfa0ad2SJack F Vogel DEBUGFUNC("e1000_initialize_hw_bits_ich8lan"); 34728cfa0ad2SJack F Vogel 34738cfa0ad2SJack F Vogel /* Extended Device Control */ 34748cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 34758cfa0ad2SJack F Vogel reg |= (1 << 22); 34769d81738fSJack F Vogel /* Enable PHY low-power state when MAC is at D3 w/o WoL */ 34779d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan) 34789d81738fSJack F Vogel reg |= E1000_CTRL_EXT_PHYPDEN; 34798cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); 34808cfa0ad2SJack F Vogel 34818cfa0ad2SJack F Vogel /* Transmit Descriptor Control 0 */ 34828cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); 34838cfa0ad2SJack F Vogel reg |= (1 << 22); 34848cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); 34858cfa0ad2SJack F Vogel 34868cfa0ad2SJack F Vogel /* Transmit Descriptor Control 1 */ 34878cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); 34888cfa0ad2SJack F Vogel reg |= (1 << 22); 34898cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); 34908cfa0ad2SJack F Vogel 34918cfa0ad2SJack F Vogel /* Transmit Arbitration Control 0 */ 34928cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(0)); 34938cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 34948cfa0ad2SJack F Vogel reg |= (1 << 28) | (1 << 29); 34958cfa0ad2SJack F Vogel reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); 34968cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(0), reg); 34978cfa0ad2SJack F Vogel 34988cfa0ad2SJack F Vogel /* Transmit Arbitration Control 1 */ 34998cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(1)); 35008cfa0ad2SJack F Vogel if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) 35018cfa0ad2SJack F Vogel reg &= ~(1 << 28); 35028cfa0ad2SJack F Vogel else 35038cfa0ad2SJack F Vogel reg |= (1 << 28); 35048cfa0ad2SJack F Vogel reg |= (1 << 24) | (1 << 26) | (1 << 30); 35058cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(1), reg); 35068cfa0ad2SJack F Vogel 35078cfa0ad2SJack F Vogel /* Device Status */ 35088cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 35098cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_STATUS); 35108cfa0ad2SJack F Vogel reg &= ~(1 << 31); 35118cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, reg); 35128cfa0ad2SJack F Vogel } 35138cfa0ad2SJack F Vogel 35148ec87fc5SJack F Vogel /* 35158ec87fc5SJack F Vogel * work-around descriptor data corruption issue during nfs v2 udp 35168ec87fc5SJack F Vogel * traffic, just disable the nfs filtering capability 35178ec87fc5SJack F Vogel */ 35188ec87fc5SJack F Vogel reg = E1000_READ_REG(hw, E1000_RFCTL); 35198ec87fc5SJack F Vogel reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); 35208ec87fc5SJack F Vogel E1000_WRITE_REG(hw, E1000_RFCTL, reg); 35218ec87fc5SJack F Vogel 35228cfa0ad2SJack F Vogel return; 35238cfa0ad2SJack F Vogel } 35248cfa0ad2SJack F Vogel 35258cfa0ad2SJack F Vogel /** 35268cfa0ad2SJack F Vogel * e1000_setup_link_ich8lan - Setup flow control and link settings 35278cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 35288cfa0ad2SJack F Vogel * 35298cfa0ad2SJack F Vogel * Determines which flow control settings to use, then configures flow 35308cfa0ad2SJack F Vogel * control. Calls the appropriate media-specific link configuration 35318cfa0ad2SJack F Vogel * function. Assuming the adapter has a valid link partner, a valid link 35328cfa0ad2SJack F Vogel * should be established. Assumes the hardware has previously been reset 35338cfa0ad2SJack F Vogel * and the transmitter and receiver are not enabled. 35348cfa0ad2SJack F Vogel **/ 35358cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) 35368cfa0ad2SJack F Vogel { 35378cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 35388cfa0ad2SJack F Vogel 35398cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_link_ich8lan"); 35408cfa0ad2SJack F Vogel 35418cfa0ad2SJack F Vogel if (hw->phy.ops.check_reset_block(hw)) 35428cfa0ad2SJack F Vogel goto out; 35438cfa0ad2SJack F Vogel 35448cfa0ad2SJack F Vogel /* 35458cfa0ad2SJack F Vogel * ICH parts do not have a word in the NVM to determine 35468cfa0ad2SJack F Vogel * the default flow control setting, so we explicitly 35478cfa0ad2SJack F Vogel * set it to full. 35488cfa0ad2SJack F Vogel */ 3549daf9197cSJack F Vogel if (hw->fc.requested_mode == e1000_fc_default) 3550daf9197cSJack F Vogel hw->fc.requested_mode = e1000_fc_full; 35518cfa0ad2SJack F Vogel 3552daf9197cSJack F Vogel /* 3553daf9197cSJack F Vogel * Save off the requested flow control mode for use later. Depending 3554daf9197cSJack F Vogel * on the link partner's capabilities, we may or may not use this mode. 3555daf9197cSJack F Vogel */ 3556daf9197cSJack F Vogel hw->fc.current_mode = hw->fc.requested_mode; 35578cfa0ad2SJack F Vogel 3558daf9197cSJack F Vogel DEBUGOUT1("After fix-ups FlowControl is now = %x\n", 3559daf9197cSJack F Vogel hw->fc.current_mode); 35608cfa0ad2SJack F Vogel 35618cfa0ad2SJack F Vogel /* Continue to configure the copper link. */ 35628cfa0ad2SJack F Vogel ret_val = hw->mac.ops.setup_physical_interface(hw); 35638cfa0ad2SJack F Vogel if (ret_val) 35648cfa0ad2SJack F Vogel goto out; 35658cfa0ad2SJack F Vogel 35668cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); 35679d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 35687d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) || 35699d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 35707d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time); 35717d9119bdSJack F Vogel 35729d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, 35739d81738fSJack F Vogel PHY_REG(BM_PORT_CTRL_PAGE, 27), 35749d81738fSJack F Vogel hw->fc.pause_time); 35759d81738fSJack F Vogel if (ret_val) 35769d81738fSJack F Vogel goto out; 35779d81738fSJack F Vogel } 35788cfa0ad2SJack F Vogel 35798cfa0ad2SJack F Vogel ret_val = e1000_set_fc_watermarks_generic(hw); 35808cfa0ad2SJack F Vogel 35818cfa0ad2SJack F Vogel out: 35828cfa0ad2SJack F Vogel return ret_val; 35838cfa0ad2SJack F Vogel } 35848cfa0ad2SJack F Vogel 35858cfa0ad2SJack F Vogel /** 35868cfa0ad2SJack F Vogel * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface 35878cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 35888cfa0ad2SJack F Vogel * 35898cfa0ad2SJack F Vogel * Configures the kumeran interface to the PHY to wait the appropriate time 35908cfa0ad2SJack F Vogel * when polling the PHY, then call the generic setup_copper_link to finish 35918cfa0ad2SJack F Vogel * configuring the copper link. 35928cfa0ad2SJack F Vogel **/ 35938cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) 35948cfa0ad2SJack F Vogel { 35958cfa0ad2SJack F Vogel u32 ctrl; 35968cfa0ad2SJack F Vogel s32 ret_val; 35978cfa0ad2SJack F Vogel u16 reg_data; 35988cfa0ad2SJack F Vogel 35998cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_ich8lan"); 36008cfa0ad2SJack F Vogel 36018cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 36028cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_SLU; 36038cfa0ad2SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 36048cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 36058cfa0ad2SJack F Vogel 36068cfa0ad2SJack F Vogel /* 36078cfa0ad2SJack F Vogel * Set the mac to wait the maximum time between each iteration 36088cfa0ad2SJack F Vogel * and increase the max iterations when polling the phy; 36098cfa0ad2SJack F Vogel * this fixes erroneous timeouts at 10Mbps. 36108cfa0ad2SJack F Vogel */ 36114edd8523SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS, 36128cfa0ad2SJack F Vogel 0xFFFF); 36138cfa0ad2SJack F Vogel if (ret_val) 36148cfa0ad2SJack F Vogel goto out; 36159d81738fSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 36169d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 36178cfa0ad2SJack F Vogel ®_data); 36188cfa0ad2SJack F Vogel if (ret_val) 36198cfa0ad2SJack F Vogel goto out; 36208cfa0ad2SJack F Vogel reg_data |= 0x3F; 36219d81738fSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 36229d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 36238cfa0ad2SJack F Vogel reg_data); 36248cfa0ad2SJack F Vogel if (ret_val) 36258cfa0ad2SJack F Vogel goto out; 36268cfa0ad2SJack F Vogel 3627d035aa2dSJack F Vogel switch (hw->phy.type) { 3628d035aa2dSJack F Vogel case e1000_phy_igp_3: 36298cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_igp(hw); 36308cfa0ad2SJack F Vogel if (ret_val) 36318cfa0ad2SJack F Vogel goto out; 3632d035aa2dSJack F Vogel break; 3633d035aa2dSJack F Vogel case e1000_phy_bm: 36349d81738fSJack F Vogel case e1000_phy_82578: 36358cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_m88(hw); 36368cfa0ad2SJack F Vogel if (ret_val) 36378cfa0ad2SJack F Vogel goto out; 3638d035aa2dSJack F Vogel break; 36399d81738fSJack F Vogel case e1000_phy_82577: 36407d9119bdSJack F Vogel case e1000_phy_82579: 36419d81738fSJack F Vogel ret_val = e1000_copper_link_setup_82577(hw); 36429d81738fSJack F Vogel if (ret_val) 36439d81738fSJack F Vogel goto out; 36449d81738fSJack F Vogel break; 3645d035aa2dSJack F Vogel case e1000_phy_ife: 36468cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, 36478cfa0ad2SJack F Vogel ®_data); 36488cfa0ad2SJack F Vogel if (ret_val) 36498cfa0ad2SJack F Vogel goto out; 36508cfa0ad2SJack F Vogel 36518cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_AUTO_MDIX; 36528cfa0ad2SJack F Vogel 36538cfa0ad2SJack F Vogel switch (hw->phy.mdix) { 36548cfa0ad2SJack F Vogel case 1: 36558cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_FORCE_MDIX; 36568cfa0ad2SJack F Vogel break; 36578cfa0ad2SJack F Vogel case 2: 36588cfa0ad2SJack F Vogel reg_data |= IFE_PMC_FORCE_MDIX; 36598cfa0ad2SJack F Vogel break; 36608cfa0ad2SJack F Vogel case 0: 36618cfa0ad2SJack F Vogel default: 36628cfa0ad2SJack F Vogel reg_data |= IFE_PMC_AUTO_MDIX; 36638cfa0ad2SJack F Vogel break; 36648cfa0ad2SJack F Vogel } 36658cfa0ad2SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, 36668cfa0ad2SJack F Vogel reg_data); 36678cfa0ad2SJack F Vogel if (ret_val) 36688cfa0ad2SJack F Vogel goto out; 3669d035aa2dSJack F Vogel break; 3670d035aa2dSJack F Vogel default: 3671d035aa2dSJack F Vogel break; 36728cfa0ad2SJack F Vogel } 36738cfa0ad2SJack F Vogel ret_val = e1000_setup_copper_link_generic(hw); 36748cfa0ad2SJack F Vogel 36758cfa0ad2SJack F Vogel out: 36768cfa0ad2SJack F Vogel return ret_val; 36778cfa0ad2SJack F Vogel } 36788cfa0ad2SJack F Vogel 36798cfa0ad2SJack F Vogel /** 36808cfa0ad2SJack F Vogel * e1000_get_link_up_info_ich8lan - Get current link speed and duplex 36818cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 36828cfa0ad2SJack F Vogel * @speed: pointer to store current link speed 36838cfa0ad2SJack F Vogel * @duplex: pointer to store the current link duplex 36848cfa0ad2SJack F Vogel * 36858cfa0ad2SJack F Vogel * Calls the generic get_speed_and_duplex to retrieve the current link 36868cfa0ad2SJack F Vogel * information and then calls the Kumeran lock loss workaround for links at 36878cfa0ad2SJack F Vogel * gigabit speeds. 36888cfa0ad2SJack F Vogel **/ 36898cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, 36908cfa0ad2SJack F Vogel u16 *duplex) 36918cfa0ad2SJack F Vogel { 36928cfa0ad2SJack F Vogel s32 ret_val; 36938cfa0ad2SJack F Vogel 36948cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_link_up_info_ich8lan"); 36958cfa0ad2SJack F Vogel 36968cfa0ad2SJack F Vogel ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); 36978cfa0ad2SJack F Vogel if (ret_val) 36988cfa0ad2SJack F Vogel goto out; 36998cfa0ad2SJack F Vogel 37008cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_ich8lan) && 37018cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3) && 37028cfa0ad2SJack F Vogel (*speed == SPEED_1000)) { 37038cfa0ad2SJack F Vogel ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); 37048cfa0ad2SJack F Vogel } 37058cfa0ad2SJack F Vogel 37068cfa0ad2SJack F Vogel out: 37078cfa0ad2SJack F Vogel return ret_val; 37088cfa0ad2SJack F Vogel } 37098cfa0ad2SJack F Vogel 37108cfa0ad2SJack F Vogel /** 37118cfa0ad2SJack F Vogel * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround 37128cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 37138cfa0ad2SJack F Vogel * 37148cfa0ad2SJack F Vogel * Work-around for 82566 Kumeran PCS lock loss: 37158cfa0ad2SJack F Vogel * On link status change (i.e. PCI reset, speed change) and link is up and 37168cfa0ad2SJack F Vogel * speed is gigabit- 37178cfa0ad2SJack F Vogel * 0) if workaround is optionally disabled do nothing 37188cfa0ad2SJack F Vogel * 1) wait 1ms for Kumeran link to come up 37198cfa0ad2SJack F Vogel * 2) check Kumeran Diagnostic register PCS lock loss bit 37208cfa0ad2SJack F Vogel * 3) if not set the link is locked (all is good), otherwise... 37218cfa0ad2SJack F Vogel * 4) reset the PHY 37228cfa0ad2SJack F Vogel * 5) repeat up to 10 times 37238cfa0ad2SJack F Vogel * Note: this is only called for IGP3 copper when speed is 1gb. 37248cfa0ad2SJack F Vogel **/ 37258cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) 37268cfa0ad2SJack F Vogel { 3727daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 37288cfa0ad2SJack F Vogel u32 phy_ctrl; 37298cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 37308cfa0ad2SJack F Vogel u16 i, data; 37318cfa0ad2SJack F Vogel bool link; 37328cfa0ad2SJack F Vogel 37338cfa0ad2SJack F Vogel DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan"); 37348cfa0ad2SJack F Vogel 3735730d3130SJack F Vogel if (!dev_spec->kmrn_lock_loss_workaround_enabled) 37368cfa0ad2SJack F Vogel goto out; 37378cfa0ad2SJack F Vogel 37388cfa0ad2SJack F Vogel /* 37398cfa0ad2SJack F Vogel * Make sure link is up before proceeding. If not just return. 37408cfa0ad2SJack F Vogel * Attempting this while link is negotiating fouled up link 37418cfa0ad2SJack F Vogel * stability 37428cfa0ad2SJack F Vogel */ 37438cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 37448cfa0ad2SJack F Vogel if (!link) { 37458cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 37468cfa0ad2SJack F Vogel goto out; 37478cfa0ad2SJack F Vogel } 37488cfa0ad2SJack F Vogel 37498cfa0ad2SJack F Vogel for (i = 0; i < 10; i++) { 37508cfa0ad2SJack F Vogel /* read once to clear */ 37518cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 37528cfa0ad2SJack F Vogel if (ret_val) 37538cfa0ad2SJack F Vogel goto out; 37548cfa0ad2SJack F Vogel /* and again to get new status */ 37558cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 37568cfa0ad2SJack F Vogel if (ret_val) 37578cfa0ad2SJack F Vogel goto out; 37588cfa0ad2SJack F Vogel 37598cfa0ad2SJack F Vogel /* check for PCS lock */ 37608cfa0ad2SJack F Vogel if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) { 37618cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 37628cfa0ad2SJack F Vogel goto out; 37638cfa0ad2SJack F Vogel } 37648cfa0ad2SJack F Vogel 37658cfa0ad2SJack F Vogel /* Issue PHY reset */ 37668cfa0ad2SJack F Vogel hw->phy.ops.reset(hw); 37678cfa0ad2SJack F Vogel msec_delay_irq(5); 37688cfa0ad2SJack F Vogel } 37698cfa0ad2SJack F Vogel /* Disable GigE link negotiation */ 37708cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 37718cfa0ad2SJack F Vogel phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | 37728cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 37738cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 37748cfa0ad2SJack F Vogel 37758cfa0ad2SJack F Vogel /* 37768cfa0ad2SJack F Vogel * Call gig speed drop workaround on Gig disable before accessing 37778cfa0ad2SJack F Vogel * any PHY registers 37788cfa0ad2SJack F Vogel */ 37798cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 37808cfa0ad2SJack F Vogel 37818cfa0ad2SJack F Vogel /* unable to acquire PCS lock */ 37828cfa0ad2SJack F Vogel ret_val = -E1000_ERR_PHY; 37838cfa0ad2SJack F Vogel 37848cfa0ad2SJack F Vogel out: 37858cfa0ad2SJack F Vogel return ret_val; 37868cfa0ad2SJack F Vogel } 37878cfa0ad2SJack F Vogel 37888cfa0ad2SJack F Vogel /** 37898cfa0ad2SJack F Vogel * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state 37908cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 37918cfa0ad2SJack F Vogel * @state: boolean value used to set the current Kumeran workaround state 37928cfa0ad2SJack F Vogel * 37938cfa0ad2SJack F Vogel * If ICH8, set the current Kumeran workaround state (enabled - TRUE 37948cfa0ad2SJack F Vogel * /disabled - FALSE). 37958cfa0ad2SJack F Vogel **/ 37968cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, 37978cfa0ad2SJack F Vogel bool state) 37988cfa0ad2SJack F Vogel { 3799daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 38008cfa0ad2SJack F Vogel 38018cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan"); 38028cfa0ad2SJack F Vogel 38038cfa0ad2SJack F Vogel if (hw->mac.type != e1000_ich8lan) { 38048cfa0ad2SJack F Vogel DEBUGOUT("Workaround applies to ICH8 only.\n"); 3805daf9197cSJack F Vogel return; 38068cfa0ad2SJack F Vogel } 38078cfa0ad2SJack F Vogel 38088cfa0ad2SJack F Vogel dev_spec->kmrn_lock_loss_workaround_enabled = state; 38098cfa0ad2SJack F Vogel 38108cfa0ad2SJack F Vogel return; 38118cfa0ad2SJack F Vogel } 38128cfa0ad2SJack F Vogel 38138cfa0ad2SJack F Vogel /** 38148cfa0ad2SJack F Vogel * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 38158cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 38168cfa0ad2SJack F Vogel * 38178cfa0ad2SJack F Vogel * Workaround for 82566 power-down on D3 entry: 38188cfa0ad2SJack F Vogel * 1) disable gigabit link 38198cfa0ad2SJack F Vogel * 2) write VR power-down enable 38208cfa0ad2SJack F Vogel * 3) read it back 38218cfa0ad2SJack F Vogel * Continue if successful, else issue LCD reset and repeat 38228cfa0ad2SJack F Vogel **/ 38238cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) 38248cfa0ad2SJack F Vogel { 38258cfa0ad2SJack F Vogel u32 reg; 38268cfa0ad2SJack F Vogel u16 data; 38278cfa0ad2SJack F Vogel u8 retry = 0; 38288cfa0ad2SJack F Vogel 38298cfa0ad2SJack F Vogel DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan"); 38308cfa0ad2SJack F Vogel 38318cfa0ad2SJack F Vogel if (hw->phy.type != e1000_phy_igp_3) 38328cfa0ad2SJack F Vogel goto out; 38338cfa0ad2SJack F Vogel 38348cfa0ad2SJack F Vogel /* Try the workaround twice (if needed) */ 38358cfa0ad2SJack F Vogel do { 38368cfa0ad2SJack F Vogel /* Disable link */ 38378cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 38388cfa0ad2SJack F Vogel reg |= (E1000_PHY_CTRL_GBE_DISABLE | 38398cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 38408cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg); 38418cfa0ad2SJack F Vogel 38428cfa0ad2SJack F Vogel /* 38438cfa0ad2SJack F Vogel * Call gig speed drop workaround on Gig disable before 38448cfa0ad2SJack F Vogel * accessing any PHY registers 38458cfa0ad2SJack F Vogel */ 38468cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 38478cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 38488cfa0ad2SJack F Vogel 38498cfa0ad2SJack F Vogel /* Write VR power-down enable */ 38508cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 38518cfa0ad2SJack F Vogel data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 3852daf9197cSJack F Vogel hw->phy.ops.write_reg(hw, IGP3_VR_CTRL, 38538cfa0ad2SJack F Vogel data | IGP3_VR_CTRL_MODE_SHUTDOWN); 38548cfa0ad2SJack F Vogel 38558cfa0ad2SJack F Vogel /* Read it back and test */ 38568cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 38578cfa0ad2SJack F Vogel data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 38588cfa0ad2SJack F Vogel if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) 38598cfa0ad2SJack F Vogel break; 38608cfa0ad2SJack F Vogel 38618cfa0ad2SJack F Vogel /* Issue PHY reset and repeat at most one more time */ 38628cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL); 38638cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST); 38648cfa0ad2SJack F Vogel retry++; 38658cfa0ad2SJack F Vogel } while (retry); 38668cfa0ad2SJack F Vogel 38678cfa0ad2SJack F Vogel out: 38688cfa0ad2SJack F Vogel return; 38698cfa0ad2SJack F Vogel } 38708cfa0ad2SJack F Vogel 38718cfa0ad2SJack F Vogel /** 38728cfa0ad2SJack F Vogel * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working 38738cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 38748cfa0ad2SJack F Vogel * 38758cfa0ad2SJack F Vogel * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), 38768cfa0ad2SJack F Vogel * LPLU, Gig disable, MDIC PHY reset): 38778cfa0ad2SJack F Vogel * 1) Set Kumeran Near-end loopback 38788cfa0ad2SJack F Vogel * 2) Clear Kumeran Near-end loopback 3879*4dab5c37SJack F Vogel * Should only be called for ICH8[m] devices with any 1G Phy. 38808cfa0ad2SJack F Vogel **/ 38818cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) 38828cfa0ad2SJack F Vogel { 38838cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 38848cfa0ad2SJack F Vogel u16 reg_data; 38858cfa0ad2SJack F Vogel 38868cfa0ad2SJack F Vogel DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); 38878cfa0ad2SJack F Vogel 38888cfa0ad2SJack F Vogel if ((hw->mac.type != e1000_ich8lan) || 3889*4dab5c37SJack F Vogel (hw->phy.type == e1000_phy_ife)) 38908cfa0ad2SJack F Vogel goto out; 38918cfa0ad2SJack F Vogel 38928cfa0ad2SJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 38938cfa0ad2SJack F Vogel ®_data); 38948cfa0ad2SJack F Vogel if (ret_val) 38958cfa0ad2SJack F Vogel goto out; 38968cfa0ad2SJack F Vogel reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; 38978cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 38988cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET, 38998cfa0ad2SJack F Vogel reg_data); 39008cfa0ad2SJack F Vogel if (ret_val) 39018cfa0ad2SJack F Vogel goto out; 39028cfa0ad2SJack F Vogel reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; 39038cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 39048cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET, 39058cfa0ad2SJack F Vogel reg_data); 39068cfa0ad2SJack F Vogel out: 39078cfa0ad2SJack F Vogel return; 39088cfa0ad2SJack F Vogel } 39098cfa0ad2SJack F Vogel 39108cfa0ad2SJack F Vogel /** 3911*4dab5c37SJack F Vogel * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx 39128cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 39138cfa0ad2SJack F Vogel * 39148cfa0ad2SJack F Vogel * During S0 to Sx transition, it is possible the link remains at gig 39158cfa0ad2SJack F Vogel * instead of negotiating to a lower speed. Before going to Sx, set 3916*4dab5c37SJack F Vogel * 'Gig Disable' to force link speed negotiation to a lower speed based on 3917*4dab5c37SJack F Vogel * the LPLU setting in the NVM or custom setting. For PCH and newer parts, 3918*4dab5c37SJack F Vogel * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also 3919*4dab5c37SJack F Vogel * needs to be written. 39208cfa0ad2SJack F Vogel **/ 3921*4dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) 39228cfa0ad2SJack F Vogel { 39238cfa0ad2SJack F Vogel u32 phy_ctrl; 39247d9119bdSJack F Vogel s32 ret_val; 39258cfa0ad2SJack F Vogel 3926*4dab5c37SJack F Vogel DEBUGFUNC("e1000_suspend_workarounds_ich8lan"); 39277d9119bdSJack F Vogel 39288cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 3929*4dab5c37SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; 39308cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 3931*4dab5c37SJack F Vogel if (hw->mac.type == e1000_ich8lan) 3932*4dab5c37SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 39339d81738fSJack F Vogel 39347d9119bdSJack F Vogel if (hw->mac.type >= e1000_pchlan) { 39357d9119bdSJack F Vogel e1000_oem_bits_config_ich8lan(hw, FALSE); 3936*4dab5c37SJack F Vogel e1000_phy_hw_reset_ich8lan(hw); 39377d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 39387d9119bdSJack F Vogel if (ret_val) 39397d9119bdSJack F Vogel return; 39407d9119bdSJack F Vogel e1000_write_smbus_addr(hw); 39417d9119bdSJack F Vogel hw->phy.ops.release(hw); 39428cfa0ad2SJack F Vogel } 39438cfa0ad2SJack F Vogel 39448cfa0ad2SJack F Vogel return; 39458cfa0ad2SJack F Vogel } 39468cfa0ad2SJack F Vogel 39478cfa0ad2SJack F Vogel /** 3948*4dab5c37SJack F Vogel * e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0 3949*4dab5c37SJack F Vogel * @hw: pointer to the HW structure 3950*4dab5c37SJack F Vogel * 3951*4dab5c37SJack F Vogel * During Sx to S0 transitions on non-managed devices or managed devices 3952*4dab5c37SJack F Vogel * on which PHY resets are not blocked, if the PHY registers cannot be 3953*4dab5c37SJack F Vogel * accessed properly by the s/w toggle the LANPHYPC value to power cycle 3954*4dab5c37SJack F Vogel * the PHY. 3955*4dab5c37SJack F Vogel **/ 3956*4dab5c37SJack F Vogel void e1000_resume_workarounds_pchlan(struct e1000_hw *hw) 3957*4dab5c37SJack F Vogel { 3958*4dab5c37SJack F Vogel u16 phy_id1, phy_id2; 3959*4dab5c37SJack F Vogel s32 ret_val; 3960*4dab5c37SJack F Vogel 3961*4dab5c37SJack F Vogel DEBUGFUNC("e1000_resume_workarounds_pchlan"); 3962*4dab5c37SJack F Vogel 3963*4dab5c37SJack F Vogel if ((hw->mac.type != e1000_pch2lan) || 3964*4dab5c37SJack F Vogel hw->phy.ops.check_reset_block(hw)) 3965*4dab5c37SJack F Vogel return; 3966*4dab5c37SJack F Vogel 3967*4dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 3968*4dab5c37SJack F Vogel if (ret_val) { 3969*4dab5c37SJack F Vogel DEBUGOUT("Failed to acquire PHY semaphore in resume\n"); 3970*4dab5c37SJack F Vogel return; 3971*4dab5c37SJack F Vogel } 3972*4dab5c37SJack F Vogel 3973*4dab5c37SJack F Vogel /* Test access to the PHY registers by reading the ID regs */ 3974*4dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_id1); 3975*4dab5c37SJack F Vogel if (ret_val) 3976*4dab5c37SJack F Vogel goto release; 3977*4dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_id2); 3978*4dab5c37SJack F Vogel if (ret_val) 3979*4dab5c37SJack F Vogel goto release; 3980*4dab5c37SJack F Vogel 3981*4dab5c37SJack F Vogel if (hw->phy.id == ((u32)(phy_id1 << 16) | 3982*4dab5c37SJack F Vogel (u32)(phy_id2 & PHY_REVISION_MASK))) 3983*4dab5c37SJack F Vogel goto release; 3984*4dab5c37SJack F Vogel 3985*4dab5c37SJack F Vogel e1000_toggle_lanphypc_value_ich8lan(hw); 3986*4dab5c37SJack F Vogel 3987*4dab5c37SJack F Vogel hw->phy.ops.release(hw); 3988*4dab5c37SJack F Vogel msec_delay(50); 3989*4dab5c37SJack F Vogel hw->phy.ops.reset(hw); 3990*4dab5c37SJack F Vogel msec_delay(50); 3991*4dab5c37SJack F Vogel return; 3992*4dab5c37SJack F Vogel 3993*4dab5c37SJack F Vogel release: 3994*4dab5c37SJack F Vogel hw->phy.ops.release(hw); 3995*4dab5c37SJack F Vogel 3996*4dab5c37SJack F Vogel return; 3997*4dab5c37SJack F Vogel } 3998*4dab5c37SJack F Vogel 3999*4dab5c37SJack F Vogel /** 40008cfa0ad2SJack F Vogel * e1000_cleanup_led_ich8lan - Restore the default LED operation 40018cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 40028cfa0ad2SJack F Vogel * 40038cfa0ad2SJack F Vogel * Return the LED back to the default configuration. 40048cfa0ad2SJack F Vogel **/ 40058cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) 40068cfa0ad2SJack F Vogel { 40078cfa0ad2SJack F Vogel DEBUGFUNC("e1000_cleanup_led_ich8lan"); 40088cfa0ad2SJack F Vogel 40098cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 4010a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 40118cfa0ad2SJack F Vogel 0); 40128cfa0ad2SJack F Vogel 4013a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); 4014a69ed8dfSJack F Vogel return E1000_SUCCESS; 40158cfa0ad2SJack F Vogel } 40168cfa0ad2SJack F Vogel 40178cfa0ad2SJack F Vogel /** 40188cfa0ad2SJack F Vogel * e1000_led_on_ich8lan - Turn LEDs on 40198cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 40208cfa0ad2SJack F Vogel * 40218cfa0ad2SJack F Vogel * Turn on the LEDs. 40228cfa0ad2SJack F Vogel **/ 40238cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) 40248cfa0ad2SJack F Vogel { 40258cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_on_ich8lan"); 40268cfa0ad2SJack F Vogel 40278cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 4028a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 40298cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); 40308cfa0ad2SJack F Vogel 4031a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); 4032a69ed8dfSJack F Vogel return E1000_SUCCESS; 40338cfa0ad2SJack F Vogel } 40348cfa0ad2SJack F Vogel 40358cfa0ad2SJack F Vogel /** 40368cfa0ad2SJack F Vogel * e1000_led_off_ich8lan - Turn LEDs off 40378cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 40388cfa0ad2SJack F Vogel * 40398cfa0ad2SJack F Vogel * Turn off the LEDs. 40408cfa0ad2SJack F Vogel **/ 40418cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) 40428cfa0ad2SJack F Vogel { 40438cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_off_ich8lan"); 40448cfa0ad2SJack F Vogel 40458cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 4046a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 40478cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); 40488cfa0ad2SJack F Vogel 4049a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); 4050a69ed8dfSJack F Vogel return E1000_SUCCESS; 40518cfa0ad2SJack F Vogel } 40528cfa0ad2SJack F Vogel 40538cfa0ad2SJack F Vogel /** 40549d81738fSJack F Vogel * e1000_setup_led_pchlan - Configures SW controllable LED 40559d81738fSJack F Vogel * @hw: pointer to the HW structure 40569d81738fSJack F Vogel * 40579d81738fSJack F Vogel * This prepares the SW controllable LED for use. 40589d81738fSJack F Vogel **/ 40599d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) 40609d81738fSJack F Vogel { 40619d81738fSJack F Vogel DEBUGFUNC("e1000_setup_led_pchlan"); 40629d81738fSJack F Vogel 40639d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 40649d81738fSJack F Vogel (u16)hw->mac.ledctl_mode1); 40659d81738fSJack F Vogel } 40669d81738fSJack F Vogel 40679d81738fSJack F Vogel /** 40689d81738fSJack F Vogel * e1000_cleanup_led_pchlan - Restore the default LED operation 40699d81738fSJack F Vogel * @hw: pointer to the HW structure 40709d81738fSJack F Vogel * 40719d81738fSJack F Vogel * Return the LED back to the default configuration. 40729d81738fSJack F Vogel **/ 40739d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) 40749d81738fSJack F Vogel { 40759d81738fSJack F Vogel DEBUGFUNC("e1000_cleanup_led_pchlan"); 40769d81738fSJack F Vogel 40779d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 40789d81738fSJack F Vogel (u16)hw->mac.ledctl_default); 40799d81738fSJack F Vogel } 40809d81738fSJack F Vogel 40819d81738fSJack F Vogel /** 40829d81738fSJack F Vogel * e1000_led_on_pchlan - Turn LEDs on 40839d81738fSJack F Vogel * @hw: pointer to the HW structure 40849d81738fSJack F Vogel * 40859d81738fSJack F Vogel * Turn on the LEDs. 40869d81738fSJack F Vogel **/ 40879d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw) 40889d81738fSJack F Vogel { 40899d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode2; 40909d81738fSJack F Vogel u32 i, led; 40919d81738fSJack F Vogel 40929d81738fSJack F Vogel DEBUGFUNC("e1000_led_on_pchlan"); 40939d81738fSJack F Vogel 40949d81738fSJack F Vogel /* 40959d81738fSJack F Vogel * If no link, then turn LED on by setting the invert bit 40969d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode2. 40979d81738fSJack F Vogel */ 40989d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 40999d81738fSJack F Vogel for (i = 0; i < 3; i++) { 41009d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 41019d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 41029d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 41039d81738fSJack F Vogel continue; 41049d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 41059d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 41069d81738fSJack F Vogel else 41079d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 41089d81738fSJack F Vogel } 41099d81738fSJack F Vogel } 41109d81738fSJack F Vogel 41119d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 41129d81738fSJack F Vogel } 41139d81738fSJack F Vogel 41149d81738fSJack F Vogel /** 41159d81738fSJack F Vogel * e1000_led_off_pchlan - Turn LEDs off 41169d81738fSJack F Vogel * @hw: pointer to the HW structure 41179d81738fSJack F Vogel * 41189d81738fSJack F Vogel * Turn off the LEDs. 41199d81738fSJack F Vogel **/ 41209d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw) 41219d81738fSJack F Vogel { 41229d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode1; 41239d81738fSJack F Vogel u32 i, led; 41249d81738fSJack F Vogel 41259d81738fSJack F Vogel DEBUGFUNC("e1000_led_off_pchlan"); 41269d81738fSJack F Vogel 41279d81738fSJack F Vogel /* 41289d81738fSJack F Vogel * If no link, then turn LED off by clearing the invert bit 41299d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode1. 41309d81738fSJack F Vogel */ 41319d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 41329d81738fSJack F Vogel for (i = 0; i < 3; i++) { 41339d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 41349d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 41359d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 41369d81738fSJack F Vogel continue; 41379d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 41389d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 41399d81738fSJack F Vogel else 41409d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 41419d81738fSJack F Vogel } 41429d81738fSJack F Vogel } 41439d81738fSJack F Vogel 41449d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 41459d81738fSJack F Vogel } 41469d81738fSJack F Vogel 41479d81738fSJack F Vogel /** 41487d9119bdSJack F Vogel * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset 41498cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 41508cfa0ad2SJack F Vogel * 41517d9119bdSJack F Vogel * Read appropriate register for the config done bit for completion status 41527d9119bdSJack F Vogel * and configure the PHY through s/w for EEPROM-less parts. 41537d9119bdSJack F Vogel * 41547d9119bdSJack F Vogel * NOTE: some silicon which is EEPROM-less will fail trying to read the 41557d9119bdSJack F Vogel * config done bit, so only an error is logged and continues. If we were 41567d9119bdSJack F Vogel * to return with error, EEPROM-less silicon would not be able to be reset 41577d9119bdSJack F Vogel * or change link. 41588cfa0ad2SJack F Vogel **/ 41598cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) 41608cfa0ad2SJack F Vogel { 41618cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 41628cfa0ad2SJack F Vogel u32 bank = 0; 41637d9119bdSJack F Vogel u32 status; 41648cfa0ad2SJack F Vogel 41657d9119bdSJack F Vogel DEBUGFUNC("e1000_get_cfg_done_ich8lan"); 41669d81738fSJack F Vogel 41678cfa0ad2SJack F Vogel e1000_get_cfg_done_generic(hw); 41688cfa0ad2SJack F Vogel 41697d9119bdSJack F Vogel /* Wait for indication from h/w that it has completed basic config */ 41707d9119bdSJack F Vogel if (hw->mac.type >= e1000_ich10lan) { 41717d9119bdSJack F Vogel e1000_lan_init_done_ich8lan(hw); 41727d9119bdSJack F Vogel } else { 41737d9119bdSJack F Vogel ret_val = e1000_get_auto_rd_done_generic(hw); 41747d9119bdSJack F Vogel if (ret_val) { 41757d9119bdSJack F Vogel /* 41767d9119bdSJack F Vogel * When auto config read does not complete, do not 41777d9119bdSJack F Vogel * return with an error. This can happen in situations 41787d9119bdSJack F Vogel * where there is no eeprom and prevents getting link. 41797d9119bdSJack F Vogel */ 41807d9119bdSJack F Vogel DEBUGOUT("Auto Read Done did not complete\n"); 41817d9119bdSJack F Vogel ret_val = E1000_SUCCESS; 41827d9119bdSJack F Vogel } 41837d9119bdSJack F Vogel } 41847d9119bdSJack F Vogel 41857d9119bdSJack F Vogel /* Clear PHY Reset Asserted bit */ 41867d9119bdSJack F Vogel status = E1000_READ_REG(hw, E1000_STATUS); 41877d9119bdSJack F Vogel if (status & E1000_STATUS_PHYRA) 41887d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA); 41897d9119bdSJack F Vogel else 41907d9119bdSJack F Vogel DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); 41917d9119bdSJack F Vogel 41928cfa0ad2SJack F Vogel /* If EEPROM is not marked present, init the IGP 3 PHY manually */ 41934edd8523SJack F Vogel if (hw->mac.type <= e1000_ich9lan) { 41948cfa0ad2SJack F Vogel if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && 41958cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3)) { 41968cfa0ad2SJack F Vogel e1000_phy_init_script_igp3(hw); 41978cfa0ad2SJack F Vogel } 41988cfa0ad2SJack F Vogel } else { 41998cfa0ad2SJack F Vogel if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { 4200daf9197cSJack F Vogel /* Maybe we should do a basic PHY config */ 42018cfa0ad2SJack F Vogel DEBUGOUT("EEPROM not present\n"); 42028cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 42038cfa0ad2SJack F Vogel } 42048cfa0ad2SJack F Vogel } 42058cfa0ad2SJack F Vogel 42068cfa0ad2SJack F Vogel return ret_val; 42078cfa0ad2SJack F Vogel } 42088cfa0ad2SJack F Vogel 42098cfa0ad2SJack F Vogel /** 42108cfa0ad2SJack F Vogel * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down 42118cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 42128cfa0ad2SJack F Vogel * 42138cfa0ad2SJack F Vogel * In the case of a PHY power down to save power, or to turn off link during a 42148cfa0ad2SJack F Vogel * driver unload, or wake on lan is not enabled, remove the link. 42158cfa0ad2SJack F Vogel **/ 42168cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) 42178cfa0ad2SJack F Vogel { 42188cfa0ad2SJack F Vogel /* If the management interface is not enabled, then power down */ 4219daf9197cSJack F Vogel if (!(hw->mac.ops.check_mng_mode(hw) || 4220daf9197cSJack F Vogel hw->phy.ops.check_reset_block(hw))) 42218cfa0ad2SJack F Vogel e1000_power_down_phy_copper(hw); 42228cfa0ad2SJack F Vogel 42238cfa0ad2SJack F Vogel return; 42248cfa0ad2SJack F Vogel } 42258cfa0ad2SJack F Vogel 42268cfa0ad2SJack F Vogel /** 42278cfa0ad2SJack F Vogel * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters 42288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 42298cfa0ad2SJack F Vogel * 42308cfa0ad2SJack F Vogel * Clears hardware counters specific to the silicon family and calls 42318cfa0ad2SJack F Vogel * clear_hw_cntrs_generic to clear all general purpose counters. 42328cfa0ad2SJack F Vogel **/ 42338cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) 42348cfa0ad2SJack F Vogel { 42359d81738fSJack F Vogel u16 phy_data; 4236*4dab5c37SJack F Vogel s32 ret_val; 42379d81738fSJack F Vogel 42388cfa0ad2SJack F Vogel DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); 42398cfa0ad2SJack F Vogel 42408cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_base_generic(hw); 42418cfa0ad2SJack F Vogel 4242daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ALGNERRC); 4243daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_RXERRC); 4244daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TNCRS); 4245daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_CEXTERR); 4246daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTC); 4247daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTFC); 42488cfa0ad2SJack F Vogel 4249daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPRC); 4250daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPDC); 4251daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPTC); 42528cfa0ad2SJack F Vogel 4253daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_IAC); 4254daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ICRXOC); 42559d81738fSJack F Vogel 42569d81738fSJack F Vogel /* Clear PHY statistics registers */ 42579d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 42587d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) || 42599d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 4260*4dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 4261*4dab5c37SJack F Vogel if (ret_val) 4262*4dab5c37SJack F Vogel return; 4263*4dab5c37SJack F Vogel ret_val = hw->phy.ops.set_page(hw, 4264*4dab5c37SJack F Vogel HV_STATS_PAGE << IGP_PAGE_SHIFT); 4265*4dab5c37SJack F Vogel if (ret_val) 4266*4dab5c37SJack F Vogel goto release; 4267*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data); 4268*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data); 4269*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data); 4270*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data); 4271*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data); 4272*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data); 4273*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data); 4274*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data); 4275*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data); 4276*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data); 4277*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data); 4278*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data); 4279*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data); 4280*4dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data); 4281*4dab5c37SJack F Vogel release: 4282*4dab5c37SJack F Vogel hw->phy.ops.release(hw); 42839d81738fSJack F Vogel } 42848cfa0ad2SJack F Vogel } 42858cfa0ad2SJack F Vogel 4286