18cfa0ad2SJack F Vogel /****************************************************************************** 28cfa0ad2SJack F Vogel 3d035aa2dSJack F Vogel Copyright (c) 2001-2009, 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 618cfa0ad2SJack F Vogel */ 628cfa0ad2SJack F Vogel 638cfa0ad2SJack F Vogel #include "e1000_api.h" 648cfa0ad2SJack F Vogel 658cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw); 669d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw); 678cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw); 688cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw); 698cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); 708cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); 718cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); 728cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); 738cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); 748cfa0ad2SJack F Vogel static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw); 758cfa0ad2SJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, 768cfa0ad2SJack F Vogel bool active); 778cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, 788cfa0ad2SJack F Vogel bool active); 798cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 808cfa0ad2SJack F Vogel u16 words, u16 *data); 818cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 828cfa0ad2SJack F Vogel u16 words, u16 *data); 838cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); 848cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); 858cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, 868cfa0ad2SJack F Vogel u16 *data); 879d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); 888cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); 898cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); 908cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); 918cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); 928cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); 938cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, 948cfa0ad2SJack F Vogel u16 *speed, u16 *duplex); 958cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); 968cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); 978cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); 989d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); 999d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); 1009d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw); 1019d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw); 1028cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); 1038cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); 1048cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); 1058cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw); 1068cfa0ad2SJack F Vogel static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw); 1078cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); 1088cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); 1098cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, 1108cfa0ad2SJack F Vogel u32 offset, u8 *data); 1118cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1128cfa0ad2SJack F Vogel u8 size, u16 *data); 1138cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, 1148cfa0ad2SJack F Vogel u32 offset, u16 *data); 1158cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 1168cfa0ad2SJack F Vogel u32 offset, u8 byte); 1178cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, 1188cfa0ad2SJack F Vogel u32 offset, u8 data); 1198cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1208cfa0ad2SJack F Vogel u8 size, u16 data); 1218cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); 1228cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); 1238cfa0ad2SJack F Vogel 1248cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ 1258cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */ 1268cfa0ad2SJack F Vogel union ich8_hws_flash_status { 1278cfa0ad2SJack F Vogel struct ich8_hsfsts { 1288cfa0ad2SJack F Vogel u16 flcdone :1; /* bit 0 Flash Cycle Done */ 1298cfa0ad2SJack F Vogel u16 flcerr :1; /* bit 1 Flash Cycle Error */ 1308cfa0ad2SJack F Vogel u16 dael :1; /* bit 2 Direct Access error Log */ 1318cfa0ad2SJack F Vogel u16 berasesz :2; /* bit 4:3 Sector Erase Size */ 1328cfa0ad2SJack F Vogel u16 flcinprog :1; /* bit 5 flash cycle in Progress */ 1338cfa0ad2SJack F Vogel u16 reserved1 :2; /* bit 13:6 Reserved */ 1348cfa0ad2SJack F Vogel u16 reserved2 :6; /* bit 13:6 Reserved */ 1358cfa0ad2SJack F Vogel u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */ 1368cfa0ad2SJack F Vogel u16 flockdn :1; /* bit 15 Flash Config Lock-Down */ 1378cfa0ad2SJack F Vogel } hsf_status; 1388cfa0ad2SJack F Vogel u16 regval; 1398cfa0ad2SJack F Vogel }; 1408cfa0ad2SJack F Vogel 1418cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ 1428cfa0ad2SJack F Vogel /* Offset 06h FLCTL */ 1438cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl { 1448cfa0ad2SJack F Vogel struct ich8_hsflctl { 1458cfa0ad2SJack F Vogel u16 flcgo :1; /* 0 Flash Cycle Go */ 1468cfa0ad2SJack F Vogel u16 flcycle :2; /* 2:1 Flash Cycle */ 1478cfa0ad2SJack F Vogel u16 reserved :5; /* 7:3 Reserved */ 1488cfa0ad2SJack F Vogel u16 fldbcount :2; /* 9:8 Flash Data Byte Count */ 1498cfa0ad2SJack F Vogel u16 flockdn :6; /* 15:10 Reserved */ 1508cfa0ad2SJack F Vogel } hsf_ctrl; 1518cfa0ad2SJack F Vogel u16 regval; 1528cfa0ad2SJack F Vogel }; 1538cfa0ad2SJack F Vogel 1548cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */ 1558cfa0ad2SJack F Vogel union ich8_hws_flash_regacc { 1568cfa0ad2SJack F Vogel struct ich8_flracc { 1578cfa0ad2SJack F Vogel u32 grra :8; /* 0:7 GbE region Read Access */ 1588cfa0ad2SJack F Vogel u32 grwa :8; /* 8:15 GbE region Write Access */ 1598cfa0ad2SJack F Vogel u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */ 1608cfa0ad2SJack F Vogel u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */ 1618cfa0ad2SJack F Vogel } hsf_flregacc; 1628cfa0ad2SJack F Vogel u16 regval; 1638cfa0ad2SJack F Vogel }; 1648cfa0ad2SJack F Vogel 1658cfa0ad2SJack F Vogel /** 1669d81738fSJack F Vogel * e1000_init_phy_params_pchlan - Initialize PHY function pointers 1679d81738fSJack F Vogel * @hw: pointer to the HW structure 1689d81738fSJack F Vogel * 1699d81738fSJack F Vogel * Initialize family-specific PHY parameters and function pointers. 1709d81738fSJack F Vogel **/ 1719d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 1729d81738fSJack F Vogel { 1739d81738fSJack F Vogel struct e1000_phy_info *phy = &hw->phy; 1749d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS; 1759d81738fSJack F Vogel 1769d81738fSJack F Vogel DEBUGFUNC("e1000_init_phy_params_pchlan"); 1779d81738fSJack F Vogel 1789d81738fSJack F Vogel phy->addr = 1; 1799d81738fSJack F Vogel phy->reset_delay_us = 100; 1809d81738fSJack F Vogel 1819d81738fSJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 1829d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_ife; 1839d81738fSJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 1849d81738fSJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; 1859d81738fSJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_2; 1869d81738fSJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 1879d81738fSJack F Vogel phy->ops.get_info = e1000_get_phy_info_ich8lan; 1889d81738fSJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_hv; 1899d81738fSJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 1909d81738fSJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 1919d81738fSJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; 1929d81738fSJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; 1939d81738fSJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_hv; 1949d81738fSJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 1959d81738fSJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 1969d81738fSJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 1979d81738fSJack F Vogel 1989d81738fSJack F Vogel phy->id = e1000_phy_unknown; 1999d81738fSJack F Vogel e1000_get_phy_id(hw); 2009d81738fSJack F Vogel phy->type = e1000_get_phy_type_from_id(phy->id); 2019d81738fSJack F Vogel 2029d81738fSJack F Vogel if (phy->type == e1000_phy_82577) { 2039d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_82577; 2049d81738fSJack F Vogel phy->ops.force_speed_duplex = 2059d81738fSJack F Vogel e1000_phy_force_speed_duplex_82577; 2069d81738fSJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_82577; 2079d81738fSJack F Vogel phy->ops.get_info = e1000_get_phy_info_82577; 2089d81738fSJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 2099d81738fSJack F Vogel } 2109d81738fSJack F Vogel 2119d81738fSJack F Vogel return ret_val; 2129d81738fSJack F Vogel } 2139d81738fSJack F Vogel 2149d81738fSJack F Vogel /** 2158cfa0ad2SJack F Vogel * e1000_init_phy_params_ich8lan - Initialize PHY function pointers 2168cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 2178cfa0ad2SJack F Vogel * 2188cfa0ad2SJack F Vogel * Initialize family-specific PHY parameters and function pointers. 2198cfa0ad2SJack F Vogel **/ 2208cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) 2218cfa0ad2SJack F Vogel { 2228cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 2238cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 2248cfa0ad2SJack F Vogel u16 i = 0; 2258cfa0ad2SJack F Vogel 2268cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_phy_params_ich8lan"); 2278cfa0ad2SJack F Vogel 2288cfa0ad2SJack F Vogel phy->addr = 1; 2298cfa0ad2SJack F Vogel phy->reset_delay_us = 100; 2308cfa0ad2SJack F Vogel 2318cfa0ad2SJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 2329d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_ife; 2338cfa0ad2SJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 2349d81738fSJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; 2358cfa0ad2SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_2; 2368cfa0ad2SJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 2378cfa0ad2SJack F Vogel phy->ops.get_info = e1000_get_phy_info_ich8lan; 2388cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_igp; 2398cfa0ad2SJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 2408cfa0ad2SJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 2418cfa0ad2SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; 2428cfa0ad2SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; 2438cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_igp; 2448cfa0ad2SJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 2458cfa0ad2SJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 2468cfa0ad2SJack F Vogel 2478cfa0ad2SJack F Vogel /* 2488cfa0ad2SJack F Vogel * We may need to do this twice - once for IGP and if that fails, 2498cfa0ad2SJack F Vogel * we'll set BM func pointers and try again 2508cfa0ad2SJack F Vogel */ 2518cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 2528cfa0ad2SJack F Vogel if (ret_val) { 2538cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 2548cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 2558cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 2568cfa0ad2SJack F Vogel if (ret_val) { 257d035aa2dSJack F Vogel DEBUGOUT("Cannot determine PHY addr. Erroring out\n"); 2588cfa0ad2SJack F Vogel goto out; 2598cfa0ad2SJack F Vogel } 2608cfa0ad2SJack F Vogel } 2618cfa0ad2SJack F Vogel 2628cfa0ad2SJack F Vogel phy->id = 0; 2638cfa0ad2SJack F Vogel while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) && 2648cfa0ad2SJack F Vogel (i++ < 100)) { 2658cfa0ad2SJack F Vogel msec_delay(1); 2668cfa0ad2SJack F Vogel ret_val = e1000_get_phy_id(hw); 2678cfa0ad2SJack F Vogel if (ret_val) 2688cfa0ad2SJack F Vogel goto out; 2698cfa0ad2SJack F Vogel } 2708cfa0ad2SJack F Vogel 2718cfa0ad2SJack F Vogel /* Verify phy id */ 2728cfa0ad2SJack F Vogel switch (phy->id) { 2738cfa0ad2SJack F Vogel case IGP03E1000_E_PHY_ID: 2748cfa0ad2SJack F Vogel phy->type = e1000_phy_igp_3; 2758cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 2768cfa0ad2SJack F Vogel break; 2778cfa0ad2SJack F Vogel case IFE_E_PHY_ID: 2788cfa0ad2SJack F Vogel case IFE_PLUS_E_PHY_ID: 2798cfa0ad2SJack F Vogel case IFE_C_E_PHY_ID: 2808cfa0ad2SJack F Vogel phy->type = e1000_phy_ife; 2818cfa0ad2SJack F Vogel phy->autoneg_mask = E1000_ALL_NOT_GIG; 2828cfa0ad2SJack F Vogel break; 2838cfa0ad2SJack F Vogel case BME1000_E_PHY_ID: 2848cfa0ad2SJack F Vogel phy->type = e1000_phy_bm; 2858cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 2868cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 2878cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 2888cfa0ad2SJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 2898cfa0ad2SJack F Vogel break; 2908cfa0ad2SJack F Vogel default: 2918cfa0ad2SJack F Vogel ret_val = -E1000_ERR_PHY; 2928cfa0ad2SJack F Vogel goto out; 2938cfa0ad2SJack F Vogel } 2948cfa0ad2SJack F Vogel 2958cfa0ad2SJack F Vogel out: 2968cfa0ad2SJack F Vogel return ret_val; 2978cfa0ad2SJack F Vogel } 2988cfa0ad2SJack F Vogel 2998cfa0ad2SJack F Vogel /** 3008cfa0ad2SJack F Vogel * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers 3018cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 3028cfa0ad2SJack F Vogel * 3038cfa0ad2SJack F Vogel * Initialize family-specific NVM parameters and function 3048cfa0ad2SJack F Vogel * pointers. 3058cfa0ad2SJack F Vogel **/ 3068cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) 3078cfa0ad2SJack F Vogel { 3088cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 309daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 3109d81738fSJack F Vogel union ich8_hws_flash_status hsfsts; 3118cfa0ad2SJack F Vogel u32 gfpreg, sector_base_addr, sector_end_addr; 3128cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 3138cfa0ad2SJack F Vogel u16 i; 3148cfa0ad2SJack F Vogel 3158cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_ich8lan"); 3168cfa0ad2SJack F Vogel 3178cfa0ad2SJack F Vogel /* Can't read flash registers if the register set isn't mapped. */ 3188cfa0ad2SJack F Vogel if (!hw->flash_address) { 3198cfa0ad2SJack F Vogel DEBUGOUT("ERROR: Flash registers not mapped\n"); 3208cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 3218cfa0ad2SJack F Vogel goto out; 3228cfa0ad2SJack F Vogel } 3238cfa0ad2SJack F Vogel 3248cfa0ad2SJack F Vogel nvm->type = e1000_nvm_flash_sw; 3258cfa0ad2SJack F Vogel 3268cfa0ad2SJack F Vogel gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); 3278cfa0ad2SJack F Vogel 3288cfa0ad2SJack F Vogel /* 3298cfa0ad2SJack F Vogel * sector_X_addr is a "sector"-aligned address (4096 bytes) 3308cfa0ad2SJack F Vogel * Add 1 to sector_end_addr since this sector is included in 3318cfa0ad2SJack F Vogel * the overall size. 3328cfa0ad2SJack F Vogel */ 3338cfa0ad2SJack F Vogel sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 3348cfa0ad2SJack F Vogel sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; 3358cfa0ad2SJack F Vogel 3368cfa0ad2SJack F Vogel /* flash_base_addr is byte-aligned */ 3378cfa0ad2SJack F Vogel nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; 3388cfa0ad2SJack F Vogel 3398cfa0ad2SJack F Vogel /* 3408cfa0ad2SJack F Vogel * find total size of the NVM, then cut in half since the total 3418cfa0ad2SJack F Vogel * size represents two separate NVM banks. 3428cfa0ad2SJack F Vogel */ 3438cfa0ad2SJack F Vogel nvm->flash_bank_size = (sector_end_addr - sector_base_addr) 3448cfa0ad2SJack F Vogel << FLASH_SECTOR_ADDR_SHIFT; 3458cfa0ad2SJack F Vogel nvm->flash_bank_size /= 2; 3468cfa0ad2SJack F Vogel /* Adjust to word count */ 3478cfa0ad2SJack F Vogel nvm->flash_bank_size /= sizeof(u16); 3488cfa0ad2SJack F Vogel 3499d81738fSJack F Vogel /* 3509d81738fSJack F Vogel * Make sure the flash bank size does not overwrite the 4k 3519d81738fSJack F Vogel * sector ranges. We may have 64k allotted to us but we only care 3529d81738fSJack F Vogel * about the first 2 4k sectors. Therefore, if we have anything less 3539d81738fSJack F Vogel * than 64k set in the HSFSTS register, we will reduce the bank size 3549d81738fSJack F Vogel * down to 4k and let the rest remain unused. If berasesz == 3, then 3559d81738fSJack F Vogel * we are working in 64k mode. Otherwise we are not. 3569d81738fSJack F Vogel */ 3579d81738fSJack F Vogel if (nvm->flash_bank_size > E1000_SHADOW_RAM_WORDS) { 3589d81738fSJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 3599d81738fSJack F Vogel if (hsfsts.hsf_status.berasesz != 3) 3609d81738fSJack F Vogel nvm->flash_bank_size = E1000_SHADOW_RAM_WORDS; 3619d81738fSJack F Vogel } 3629d81738fSJack F Vogel 3638cfa0ad2SJack F Vogel nvm->word_size = E1000_SHADOW_RAM_WORDS; 3648cfa0ad2SJack F Vogel 3658cfa0ad2SJack F Vogel /* Clear shadow ram */ 3668cfa0ad2SJack F Vogel for (i = 0; i < nvm->word_size; i++) { 3678cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 3688cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 3698cfa0ad2SJack F Vogel } 3708cfa0ad2SJack F Vogel 3718cfa0ad2SJack F Vogel /* Function Pointers */ 3728cfa0ad2SJack F Vogel nvm->ops.acquire = e1000_acquire_swflag_ich8lan; 3738cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_ich8lan; 3748cfa0ad2SJack F Vogel nvm->ops.release = e1000_release_swflag_ich8lan; 3758cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_ich8lan; 3768cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; 3778cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; 3788cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_ich8lan; 3798cfa0ad2SJack F Vogel 3808cfa0ad2SJack F Vogel out: 3818cfa0ad2SJack F Vogel return ret_val; 3828cfa0ad2SJack F Vogel } 3838cfa0ad2SJack F Vogel 3848cfa0ad2SJack F Vogel /** 3858cfa0ad2SJack F Vogel * e1000_init_mac_params_ich8lan - Initialize MAC function pointers 3868cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 3878cfa0ad2SJack F Vogel * 3888cfa0ad2SJack F Vogel * Initialize family-specific MAC parameters and function 3898cfa0ad2SJack F Vogel * pointers. 3908cfa0ad2SJack F Vogel **/ 3918cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) 3928cfa0ad2SJack F Vogel { 3938cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 394d035aa2dSJack F Vogel u16 pci_cfg; 3958cfa0ad2SJack F Vogel 3968cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_mac_params_ich8lan"); 3978cfa0ad2SJack F Vogel 3988cfa0ad2SJack F Vogel /* Set media type function pointer */ 3998cfa0ad2SJack F Vogel hw->phy.media_type = e1000_media_type_copper; 4008cfa0ad2SJack F Vogel 4018cfa0ad2SJack F Vogel /* Set mta register count */ 4028cfa0ad2SJack F Vogel mac->mta_reg_count = 32; 4038cfa0ad2SJack F Vogel /* Set rar entry count */ 4048cfa0ad2SJack F Vogel mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; 4058cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 4068cfa0ad2SJack F Vogel mac->rar_entry_count--; 4078cfa0ad2SJack F Vogel /* Set if part includes ASF firmware */ 4088cfa0ad2SJack F Vogel mac->asf_firmware_present = TRUE; 4098cfa0ad2SJack F Vogel /* Set if manageability features are enabled. */ 4108cfa0ad2SJack F Vogel mac->arc_subsystem_valid = TRUE; 4118cfa0ad2SJack F Vogel 4128cfa0ad2SJack F Vogel /* Function pointers */ 4138cfa0ad2SJack F Vogel 4148cfa0ad2SJack F Vogel /* bus type/speed/width */ 4158cfa0ad2SJack F Vogel mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; 416daf9197cSJack F Vogel /* function id */ 417daf9197cSJack F Vogel mac->ops.set_lan_id = e1000_set_lan_id_single_port; 4188cfa0ad2SJack F Vogel /* reset */ 4198cfa0ad2SJack F Vogel mac->ops.reset_hw = e1000_reset_hw_ich8lan; 4208cfa0ad2SJack F Vogel /* hw initialization */ 4218cfa0ad2SJack F Vogel mac->ops.init_hw = e1000_init_hw_ich8lan; 4228cfa0ad2SJack F Vogel /* link setup */ 4238cfa0ad2SJack F Vogel mac->ops.setup_link = e1000_setup_link_ich8lan; 4248cfa0ad2SJack F Vogel /* physical interface setup */ 4258cfa0ad2SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; 4268cfa0ad2SJack F Vogel /* check for link */ 4278cfa0ad2SJack F Vogel mac->ops.check_for_link = e1000_check_for_copper_link_generic; 4288cfa0ad2SJack F Vogel /* check management mode */ 4298cfa0ad2SJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; 4308cfa0ad2SJack F Vogel /* link info */ 4318cfa0ad2SJack F Vogel mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; 4328cfa0ad2SJack F Vogel /* multicast address update */ 4338cfa0ad2SJack F Vogel mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; 4348cfa0ad2SJack F Vogel /* setting MTA */ 4358cfa0ad2SJack F Vogel mac->ops.mta_set = e1000_mta_set_generic; 436d035aa2dSJack F Vogel /* clear hardware counters */ 437d035aa2dSJack F Vogel mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; 438d035aa2dSJack F Vogel 439d035aa2dSJack F Vogel /* LED operations */ 440d035aa2dSJack F Vogel switch (mac->type) { 441d035aa2dSJack F Vogel case e1000_ich8lan: 442d035aa2dSJack F Vogel case e1000_ich9lan: 443d035aa2dSJack F Vogel case e1000_ich10lan: 444d035aa2dSJack F Vogel /* ID LED init */ 445d035aa2dSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_generic; 4468cfa0ad2SJack F Vogel /* blink LED */ 4478cfa0ad2SJack F Vogel mac->ops.blink_led = e1000_blink_led_generic; 4488cfa0ad2SJack F Vogel /* setup LED */ 4498cfa0ad2SJack F Vogel mac->ops.setup_led = e1000_setup_led_generic; 4508cfa0ad2SJack F Vogel /* cleanup LED */ 4518cfa0ad2SJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; 4528cfa0ad2SJack F Vogel /* turn on/off LED */ 4538cfa0ad2SJack F Vogel mac->ops.led_on = e1000_led_on_ich8lan; 4548cfa0ad2SJack F Vogel mac->ops.led_off = e1000_led_off_ich8lan; 455d035aa2dSJack F Vogel break; 4569d81738fSJack F Vogel case e1000_pchlan: 4579d81738fSJack F Vogel /* save PCH revision_id */ 4589d81738fSJack F Vogel e1000_read_pci_cfg(hw, 0x2, &pci_cfg); 4599d81738fSJack F Vogel hw->revision_id = (u8)(pci_cfg &= 0x000F); 4609d81738fSJack F Vogel /* ID LED init */ 4619d81738fSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_pchlan; 4629d81738fSJack F Vogel /* setup LED */ 4639d81738fSJack F Vogel mac->ops.setup_led = e1000_setup_led_pchlan; 4649d81738fSJack F Vogel /* cleanup LED */ 4659d81738fSJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_pchlan; 4669d81738fSJack F Vogel /* turn on/off LED */ 4679d81738fSJack F Vogel mac->ops.led_on = e1000_led_on_pchlan; 4689d81738fSJack F Vogel mac->ops.led_off = e1000_led_off_pchlan; 4699d81738fSJack F Vogel break; 470d035aa2dSJack F Vogel default: 471d035aa2dSJack F Vogel break; 472d035aa2dSJack F Vogel } 4738cfa0ad2SJack F Vogel 4748cfa0ad2SJack F Vogel /* Enable PCS Lock-loss workaround for ICH8 */ 4758cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 4768cfa0ad2SJack F Vogel e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE); 4778cfa0ad2SJack F Vogel 4788cfa0ad2SJack F Vogel 479daf9197cSJack F Vogel return E1000_SUCCESS; 4808cfa0ad2SJack F Vogel } 4818cfa0ad2SJack F Vogel 4828cfa0ad2SJack F Vogel /** 4838cfa0ad2SJack F Vogel * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers 4848cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 4858cfa0ad2SJack F Vogel * 4868cfa0ad2SJack F Vogel * Initialize family-specific function pointers for PHY, MAC, and NVM. 4878cfa0ad2SJack F Vogel **/ 4888cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) 4898cfa0ad2SJack F Vogel { 4908cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_function_pointers_ich8lan"); 4918cfa0ad2SJack F Vogel 4928cfa0ad2SJack F Vogel hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; 4938cfa0ad2SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; 4949d81738fSJack F Vogel switch (hw->mac.type) { 4959d81738fSJack F Vogel case e1000_ich8lan: 4969d81738fSJack F Vogel case e1000_ich9lan: 4979d81738fSJack F Vogel case e1000_ich10lan: 4988cfa0ad2SJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; 4999d81738fSJack F Vogel break; 5009d81738fSJack F Vogel case e1000_pchlan: 5019d81738fSJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_pchlan; 5029d81738fSJack F Vogel break; 5039d81738fSJack F Vogel default: 5049d81738fSJack F Vogel break; 5059d81738fSJack F Vogel } 5068cfa0ad2SJack F Vogel } 5078cfa0ad2SJack F Vogel 5088cfa0ad2SJack F Vogel /** 5098cfa0ad2SJack F Vogel * e1000_acquire_swflag_ich8lan - Acquire software control flag 5108cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5118cfa0ad2SJack F Vogel * 5128cfa0ad2SJack F Vogel * Acquires the software control flag for performing NVM and PHY 5138cfa0ad2SJack F Vogel * operations. This is a function pointer entry point only called by 5148cfa0ad2SJack F Vogel * read/write routines for the PHY and NVM parts. 5158cfa0ad2SJack F Vogel **/ 5168cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) 5178cfa0ad2SJack F Vogel { 5188cfa0ad2SJack F Vogel u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; 5198cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 5208cfa0ad2SJack F Vogel 5218cfa0ad2SJack F Vogel DEBUGFUNC("e1000_acquire_swflag_ich8lan"); 5228cfa0ad2SJack F Vogel 5238cfa0ad2SJack F Vogel while (timeout) { 5248cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 5259d81738fSJack F Vogel 5269d81738fSJack F Vogel if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) { 5278cfa0ad2SJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; 5288cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 5298cfa0ad2SJack F Vogel 5308cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 5318cfa0ad2SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) 5328cfa0ad2SJack F Vogel break; 5339d81738fSJack F Vogel } 5348cfa0ad2SJack F Vogel msec_delay_irq(1); 5358cfa0ad2SJack F Vogel timeout--; 5368cfa0ad2SJack F Vogel } 5378cfa0ad2SJack F Vogel 5388cfa0ad2SJack F Vogel if (!timeout) { 5399d81738fSJack F Vogel DEBUGOUT("SW/FW/HW has locked the resource for too long.\n"); 5408cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 5418cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 5428cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 5438cfa0ad2SJack F Vogel goto out; 5448cfa0ad2SJack F Vogel } 5458cfa0ad2SJack F Vogel 5468cfa0ad2SJack F Vogel out: 5478cfa0ad2SJack F Vogel return ret_val; 5488cfa0ad2SJack F Vogel } 5498cfa0ad2SJack F Vogel 5508cfa0ad2SJack F Vogel /** 5518cfa0ad2SJack F Vogel * e1000_release_swflag_ich8lan - Release software control flag 5528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5538cfa0ad2SJack F Vogel * 5548cfa0ad2SJack F Vogel * Releases the software control flag for performing NVM and PHY operations. 5558cfa0ad2SJack F Vogel * This is a function pointer entry point only called by read/write 5568cfa0ad2SJack F Vogel * routines for the PHY and NVM parts. 5578cfa0ad2SJack F Vogel **/ 5588cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) 5598cfa0ad2SJack F Vogel { 5608cfa0ad2SJack F Vogel u32 extcnf_ctrl; 5618cfa0ad2SJack F Vogel 5628cfa0ad2SJack F Vogel DEBUGFUNC("e1000_release_swflag_ich8lan"); 5638cfa0ad2SJack F Vogel 5648cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 5658cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 5668cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 5678cfa0ad2SJack F Vogel 5688cfa0ad2SJack F Vogel return; 5698cfa0ad2SJack F Vogel } 5708cfa0ad2SJack F Vogel 5718cfa0ad2SJack F Vogel /** 5728cfa0ad2SJack F Vogel * e1000_check_mng_mode_ich8lan - Checks management mode 5738cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5748cfa0ad2SJack F Vogel * 5758cfa0ad2SJack F Vogel * This checks if the adapter has manageability enabled. 5768cfa0ad2SJack F Vogel * This is a function pointer entry point only called by read/write 5778cfa0ad2SJack F Vogel * routines for the PHY and NVM parts. 5788cfa0ad2SJack F Vogel **/ 5798cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) 5808cfa0ad2SJack F Vogel { 5818cfa0ad2SJack F Vogel u32 fwsm; 5828cfa0ad2SJack F Vogel 5838cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_mng_mode_ich8lan"); 5848cfa0ad2SJack F Vogel 5858cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 5868cfa0ad2SJack F Vogel 587daf9197cSJack F Vogel return (fwsm & E1000_FWSM_MODE_MASK) == 588daf9197cSJack F Vogel (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); 5898cfa0ad2SJack F Vogel } 5908cfa0ad2SJack F Vogel 5918cfa0ad2SJack F Vogel /** 5928cfa0ad2SJack F Vogel * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked 5938cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5948cfa0ad2SJack F Vogel * 5958cfa0ad2SJack F Vogel * Checks if firmware is blocking the reset of the PHY. 5968cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 5978cfa0ad2SJack F Vogel * reset routines. 5988cfa0ad2SJack F Vogel **/ 5998cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) 6008cfa0ad2SJack F Vogel { 6018cfa0ad2SJack F Vogel u32 fwsm; 6028cfa0ad2SJack F Vogel 6038cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_reset_block_ich8lan"); 6048cfa0ad2SJack F Vogel 6058cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 6068cfa0ad2SJack F Vogel 6078cfa0ad2SJack F Vogel return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS 6088cfa0ad2SJack F Vogel : E1000_BLK_PHY_RESET; 6098cfa0ad2SJack F Vogel } 6108cfa0ad2SJack F Vogel 6118cfa0ad2SJack F Vogel /** 6129d81738fSJack F Vogel * e1000_hv_phy_powerdown_workaround_ich8lan - Power down workaround on Sx 6139d81738fSJack F Vogel * @hw: pointer to the HW structure 6149d81738fSJack F Vogel **/ 6159d81738fSJack F Vogel s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) 6169d81738fSJack F Vogel { 6179d81738fSJack F Vogel if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2)) 6189d81738fSJack F Vogel return E1000_SUCCESS; 6199d81738fSJack F Vogel 6209d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0444); 6219d81738fSJack F Vogel } 6229d81738fSJack F Vogel 6239d81738fSJack F Vogel /** 6249d81738fSJack F Vogel * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be 6259d81738fSJack F Vogel * done after every PHY reset. 6269d81738fSJack F Vogel **/ 6279d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) 6289d81738fSJack F Vogel { 6299d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS; 6309d81738fSJack F Vogel 6319d81738fSJack F Vogel if (hw->mac.type != e1000_pchlan) 6329d81738fSJack F Vogel return ret_val; 6339d81738fSJack F Vogel 6349d81738fSJack F Vogel /* Hanksville M Phy init for IEEE. */ 6359d81738fSJack F Vogel if ((hw->revision_id == 2) && 6369d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577) && 6379d81738fSJack F Vogel ((hw->phy.revision == 2) || (hw->phy.revision == 3))) { 6389d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8823); 6399d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0018); 6409d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8824); 6419d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0016); 6429d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8825); 6439d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x001A); 6449d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x888C); 6459d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0007); 6469d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x888D); 6479d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0007); 6489d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x888E); 6499d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0007); 6509d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8827); 6519d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0001); 6529d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8835); 6539d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0001); 6549d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8834); 6559d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0001); 6569d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x10, 0x8833); 6579d81738fSJack F Vogel hw->phy.ops.write_reg(hw, 0x11, 0x0002); 6589d81738fSJack F Vogel } 6599d81738fSJack F Vogel 6609d81738fSJack F Vogel if (((hw->phy.type == e1000_phy_82577) && 6619d81738fSJack F Vogel ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || 6629d81738fSJack F Vogel ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { 6639d81738fSJack F Vogel /* Disable generation of early preamble */ 6649d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); 6659d81738fSJack F Vogel if (ret_val) 6669d81738fSJack F Vogel return ret_val; 6679d81738fSJack F Vogel 6689d81738fSJack F Vogel /* Preamble tuning for SSC */ 6699d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204); 6709d81738fSJack F Vogel if (ret_val) 6719d81738fSJack F Vogel return ret_val; 6729d81738fSJack F Vogel } 6739d81738fSJack F Vogel 6749d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 6759d81738fSJack F Vogel if (hw->revision_id < 3) { 6769d81738fSJack F Vogel /* PHY config */ 6779d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 6789d81738fSJack F Vogel 0x66C0); 6799d81738fSJack F Vogel if (ret_val) 6809d81738fSJack F Vogel return ret_val; 6819d81738fSJack F Vogel 6829d81738fSJack F Vogel /* PHY config */ 6839d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 6849d81738fSJack F Vogel 0xFFFF); 6859d81738fSJack F Vogel if (ret_val) 6869d81738fSJack F Vogel return ret_val; 6879d81738fSJack F Vogel } 6889d81738fSJack F Vogel 6899d81738fSJack F Vogel /* 6909d81738fSJack F Vogel * Return registers to default by doing a soft reset then 6919d81738fSJack F Vogel * writing 0x3140 to the control register. 6929d81738fSJack F Vogel */ 6939d81738fSJack F Vogel if (hw->phy.revision < 2) { 6949d81738fSJack F Vogel e1000_phy_sw_reset_generic(hw); 6959d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, 6969d81738fSJack F Vogel 0x3140); 6979d81738fSJack F Vogel } 6989d81738fSJack F Vogel } 6999d81738fSJack F Vogel 7009d81738fSJack F Vogel if ((hw->revision_id == 2) && 7019d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577) && 7029d81738fSJack F Vogel ((hw->phy.revision == 2) || (hw->phy.revision == 3))) { 7039d81738fSJack F Vogel /* 7049d81738fSJack F Vogel * Workaround for OEM (GbE) not operating after reset - 7059d81738fSJack F Vogel * restart AN (twice) 7069d81738fSJack F Vogel */ 7079d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400); 7089d81738fSJack F Vogel if (ret_val) 7099d81738fSJack F Vogel return ret_val; 7109d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400); 7119d81738fSJack F Vogel if (ret_val) 7129d81738fSJack F Vogel return ret_val; 7139d81738fSJack F Vogel } 7149d81738fSJack F Vogel 7159d81738fSJack F Vogel /* Select page 0 */ 7169d81738fSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 7179d81738fSJack F Vogel if (ret_val) 7189d81738fSJack F Vogel return ret_val; 7199d81738fSJack F Vogel hw->phy.addr = 1; 7209d81738fSJack F Vogel e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); 7219d81738fSJack F Vogel hw->phy.ops.release(hw); 7229d81738fSJack F Vogel 7239d81738fSJack F Vogel return ret_val; 7249d81738fSJack F Vogel } 7259d81738fSJack F Vogel 7269d81738fSJack F Vogel /** 7279d81738fSJack F Vogel * e1000_lan_init_done_ich8lan - Check for PHY config completion 7288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 7298cfa0ad2SJack F Vogel * 7309d81738fSJack F Vogel * Check the appropriate indication the MAC has finished configuring the 7319d81738fSJack F Vogel * PHY after a software reset. 7328cfa0ad2SJack F Vogel **/ 7339d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) 7348cfa0ad2SJack F Vogel { 7359d81738fSJack F Vogel u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; 7368cfa0ad2SJack F Vogel 7379d81738fSJack F Vogel DEBUGFUNC("e1000_lan_init_done_ich8lan"); 7388cfa0ad2SJack F Vogel 7399d81738fSJack F Vogel /* Wait for basic configuration completes before proceeding */ 7409d81738fSJack F Vogel do { 7419d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 7429d81738fSJack F Vogel data &= E1000_STATUS_LAN_INIT_DONE; 7439d81738fSJack F Vogel usec_delay(100); 7449d81738fSJack F Vogel } while ((!data) && --loop); 7458cfa0ad2SJack F Vogel 7469d81738fSJack F Vogel /* 7479d81738fSJack F Vogel * If basic configuration is incomplete before the above loop 7489d81738fSJack F Vogel * count reaches 0, loading the configuration from NVM will 7499d81738fSJack F Vogel * leave the PHY in a bad state possibly resulting in no link. 7509d81738fSJack F Vogel */ 7519d81738fSJack F Vogel if (loop == 0) 7529d81738fSJack F Vogel DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); 7538cfa0ad2SJack F Vogel 7549d81738fSJack F Vogel /* Clear the Init Done bit for the next init event */ 7559d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 7569d81738fSJack F Vogel data &= ~E1000_STATUS_LAN_INIT_DONE; 7579d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, data); 7588cfa0ad2SJack F Vogel } 7598cfa0ad2SJack F Vogel 7608cfa0ad2SJack F Vogel /** 7618cfa0ad2SJack F Vogel * e1000_phy_hw_reset_ich8lan - Performs a PHY reset 7628cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 7638cfa0ad2SJack F Vogel * 7648cfa0ad2SJack F Vogel * Resets the PHY 7658cfa0ad2SJack F Vogel * This is a function pointer entry point called by drivers 7668cfa0ad2SJack F Vogel * or other shared routines. 7678cfa0ad2SJack F Vogel **/ 7688cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) 7698cfa0ad2SJack F Vogel { 7708cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 7718cfa0ad2SJack F Vogel u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; 7728cfa0ad2SJack F Vogel s32 ret_val; 7738cfa0ad2SJack F Vogel u16 word_addr, reg_data, reg_addr, phy_page = 0; 7748cfa0ad2SJack F Vogel 7758cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); 7768cfa0ad2SJack F Vogel 7778cfa0ad2SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 7788cfa0ad2SJack F Vogel if (ret_val) 7798cfa0ad2SJack F Vogel goto out; 7808cfa0ad2SJack F Vogel 7819d81738fSJack F Vogel /* Allow time for h/w to get to a quiescent state after reset */ 7829d81738fSJack F Vogel msec_delay(10); 7839d81738fSJack F Vogel 7849d81738fSJack F Vogel if (hw->mac.type == e1000_pchlan) { 7859d81738fSJack F Vogel ret_val = e1000_hv_phy_workarounds_ich8lan(hw); 7869d81738fSJack F Vogel if (ret_val) 7879d81738fSJack F Vogel goto out; 7889d81738fSJack F Vogel } 7899d81738fSJack F Vogel 7908cfa0ad2SJack F Vogel /* 7918cfa0ad2SJack F Vogel * Initialize the PHY from the NVM on ICH platforms. This 7928cfa0ad2SJack F Vogel * is needed due to an issue where the NVM configuration is 7938cfa0ad2SJack F Vogel * not properly autoloaded after power transitions. 7948cfa0ad2SJack F Vogel * Therefore, after each PHY reset, we will load the 7958cfa0ad2SJack F Vogel * configuration data out of the NVM manually. 7968cfa0ad2SJack F Vogel */ 7978cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { 7988cfa0ad2SJack F Vogel /* Check if SW needs configure the PHY */ 7998cfa0ad2SJack F Vogel if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || 8008cfa0ad2SJack F Vogel (hw->device_id == E1000_DEV_ID_ICH8_IGP_M)) 8018cfa0ad2SJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; 8028cfa0ad2SJack F Vogel else 8038cfa0ad2SJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; 8048cfa0ad2SJack F Vogel 8058cfa0ad2SJack F Vogel data = E1000_READ_REG(hw, E1000_FEXTNVM); 8068cfa0ad2SJack F Vogel if (!(data & sw_cfg_mask)) 8078cfa0ad2SJack F Vogel goto out; 8088cfa0ad2SJack F Vogel 8098cfa0ad2SJack F Vogel /* Wait for basic configuration completes before proceeding */ 8109d81738fSJack F Vogel e1000_lan_init_done_ich8lan(hw); 8118cfa0ad2SJack F Vogel 8128cfa0ad2SJack F Vogel /* 8138cfa0ad2SJack F Vogel * Make sure HW does not configure LCD from PHY 8148cfa0ad2SJack F Vogel * extended configuration before SW configuration 8158cfa0ad2SJack F Vogel */ 8168cfa0ad2SJack F Vogel data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 8178cfa0ad2SJack F Vogel if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) 8188cfa0ad2SJack F Vogel goto out; 8198cfa0ad2SJack F Vogel 8208cfa0ad2SJack F Vogel cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); 8218cfa0ad2SJack F Vogel cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; 8228cfa0ad2SJack F Vogel cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; 8238cfa0ad2SJack F Vogel if (!cnf_size) 8248cfa0ad2SJack F Vogel goto out; 8258cfa0ad2SJack F Vogel 8268cfa0ad2SJack F Vogel cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; 8278cfa0ad2SJack F Vogel cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; 8288cfa0ad2SJack F Vogel 829daf9197cSJack F Vogel /* Configure LCD from extended configuration region. */ 8308cfa0ad2SJack F Vogel 8318cfa0ad2SJack F Vogel /* cnf_base_addr is in DWORD */ 8328cfa0ad2SJack F Vogel word_addr = (u16)(cnf_base_addr << 1); 8338cfa0ad2SJack F Vogel 8348cfa0ad2SJack F Vogel for (i = 0; i < cnf_size; i++) { 835daf9197cSJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, 8368cfa0ad2SJack F Vogel ®_data); 8378cfa0ad2SJack F Vogel if (ret_val) 8388cfa0ad2SJack F Vogel goto out; 8398cfa0ad2SJack F Vogel 840daf9197cSJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), 841daf9197cSJack F Vogel 1, ®_addr); 8428cfa0ad2SJack F Vogel if (ret_val) 8438cfa0ad2SJack F Vogel goto out; 8448cfa0ad2SJack F Vogel 8458cfa0ad2SJack F Vogel /* Save off the PHY page for future writes. */ 8468cfa0ad2SJack F Vogel if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { 8478cfa0ad2SJack F Vogel phy_page = reg_data; 8488cfa0ad2SJack F Vogel continue; 8498cfa0ad2SJack F Vogel } 8508cfa0ad2SJack F Vogel 8518cfa0ad2SJack F Vogel reg_addr |= phy_page; 8528cfa0ad2SJack F Vogel 853daf9197cSJack F Vogel ret_val = phy->ops.write_reg(hw, (u32)reg_addr, reg_data); 8548cfa0ad2SJack F Vogel if (ret_val) 8558cfa0ad2SJack F Vogel goto out; 8568cfa0ad2SJack F Vogel } 8578cfa0ad2SJack F Vogel } 8588cfa0ad2SJack F Vogel 8598cfa0ad2SJack F Vogel out: 8608cfa0ad2SJack F Vogel return ret_val; 8618cfa0ad2SJack F Vogel } 8628cfa0ad2SJack F Vogel 8638cfa0ad2SJack F Vogel /** 8648cfa0ad2SJack F Vogel * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info 8658cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 8668cfa0ad2SJack F Vogel * 8678cfa0ad2SJack F Vogel * Wrapper for calling the get_phy_info routines for the appropriate phy type. 8688cfa0ad2SJack F Vogel **/ 8698cfa0ad2SJack F Vogel static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) 8708cfa0ad2SJack F Vogel { 8718cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_PHY_TYPE; 8728cfa0ad2SJack F Vogel 8738cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_phy_info_ich8lan"); 8748cfa0ad2SJack F Vogel 8758cfa0ad2SJack F Vogel switch (hw->phy.type) { 8768cfa0ad2SJack F Vogel case e1000_phy_ife: 8778cfa0ad2SJack F Vogel ret_val = e1000_get_phy_info_ife_ich8lan(hw); 8788cfa0ad2SJack F Vogel break; 8798cfa0ad2SJack F Vogel case e1000_phy_igp_3: 8808cfa0ad2SJack F Vogel case e1000_phy_bm: 8819d81738fSJack F Vogel case e1000_phy_82578: 8829d81738fSJack F Vogel case e1000_phy_82577: 8838cfa0ad2SJack F Vogel ret_val = e1000_get_phy_info_igp(hw); 8848cfa0ad2SJack F Vogel break; 8858cfa0ad2SJack F Vogel default: 8868cfa0ad2SJack F Vogel break; 8878cfa0ad2SJack F Vogel } 8888cfa0ad2SJack F Vogel 8898cfa0ad2SJack F Vogel return ret_val; 8908cfa0ad2SJack F Vogel } 8918cfa0ad2SJack F Vogel 8928cfa0ad2SJack F Vogel /** 8938cfa0ad2SJack F Vogel * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states 8948cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 8958cfa0ad2SJack F Vogel * 8968cfa0ad2SJack F Vogel * Populates "phy" structure with various feature states. 8978cfa0ad2SJack F Vogel * This function is only called by other family-specific 8988cfa0ad2SJack F Vogel * routines. 8998cfa0ad2SJack F Vogel **/ 9008cfa0ad2SJack F Vogel static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) 9018cfa0ad2SJack F Vogel { 9028cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 9038cfa0ad2SJack F Vogel s32 ret_val; 9048cfa0ad2SJack F Vogel u16 data; 9058cfa0ad2SJack F Vogel bool link; 9068cfa0ad2SJack F Vogel 9078cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_phy_info_ife_ich8lan"); 9088cfa0ad2SJack F Vogel 9098cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 9108cfa0ad2SJack F Vogel if (ret_val) 9118cfa0ad2SJack F Vogel goto out; 9128cfa0ad2SJack F Vogel 9138cfa0ad2SJack F Vogel if (!link) { 9148cfa0ad2SJack F Vogel DEBUGOUT("Phy info is only valid if link is up\n"); 9158cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 9168cfa0ad2SJack F Vogel goto out; 9178cfa0ad2SJack F Vogel } 9188cfa0ad2SJack F Vogel 9198cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data); 9208cfa0ad2SJack F Vogel if (ret_val) 9218cfa0ad2SJack F Vogel goto out; 9228cfa0ad2SJack F Vogel phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) 9238cfa0ad2SJack F Vogel ? FALSE : TRUE; 9248cfa0ad2SJack F Vogel 9258cfa0ad2SJack F Vogel if (phy->polarity_correction) { 9269d81738fSJack F Vogel ret_val = e1000_check_polarity_ife(hw); 9278cfa0ad2SJack F Vogel if (ret_val) 9288cfa0ad2SJack F Vogel goto out; 9298cfa0ad2SJack F Vogel } else { 9308cfa0ad2SJack F Vogel /* Polarity is forced */ 9318cfa0ad2SJack F Vogel phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) 9328cfa0ad2SJack F Vogel ? e1000_rev_polarity_reversed 9338cfa0ad2SJack F Vogel : e1000_rev_polarity_normal; 9348cfa0ad2SJack F Vogel } 9358cfa0ad2SJack F Vogel 9368cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); 9378cfa0ad2SJack F Vogel if (ret_val) 9388cfa0ad2SJack F Vogel goto out; 9398cfa0ad2SJack F Vogel 9408cfa0ad2SJack F Vogel phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE; 9418cfa0ad2SJack F Vogel 9428cfa0ad2SJack F Vogel /* The following parameters are undefined for 10/100 operation. */ 9438cfa0ad2SJack F Vogel phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; 9448cfa0ad2SJack F Vogel phy->local_rx = e1000_1000t_rx_status_undefined; 9458cfa0ad2SJack F Vogel phy->remote_rx = e1000_1000t_rx_status_undefined; 9468cfa0ad2SJack F Vogel 9478cfa0ad2SJack F Vogel out: 9488cfa0ad2SJack F Vogel return ret_val; 9498cfa0ad2SJack F Vogel } 9508cfa0ad2SJack F Vogel 9518cfa0ad2SJack F Vogel /** 9528cfa0ad2SJack F Vogel * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state 9538cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 9548cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 9558cfa0ad2SJack F Vogel * 9568cfa0ad2SJack F Vogel * Sets the LPLU D0 state according to the active flag. When 9578cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 9588cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 9598cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 9608cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 9618cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 9628cfa0ad2SJack F Vogel * PHY setup routines. 9638cfa0ad2SJack F Vogel **/ 964daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 9658cfa0ad2SJack F Vogel { 9668cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 9678cfa0ad2SJack F Vogel u32 phy_ctrl; 9688cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 9698cfa0ad2SJack F Vogel u16 data; 9708cfa0ad2SJack F Vogel 9718cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); 9728cfa0ad2SJack F Vogel 9738cfa0ad2SJack F Vogel if (phy->type == e1000_phy_ife) 9748cfa0ad2SJack F Vogel goto out; 9758cfa0ad2SJack F Vogel 9768cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 9778cfa0ad2SJack F Vogel 9788cfa0ad2SJack F Vogel if (active) { 9798cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; 9808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 9818cfa0ad2SJack F Vogel 9829d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 9839d81738fSJack F Vogel goto out; 9849d81738fSJack F Vogel 9858cfa0ad2SJack F Vogel /* 9868cfa0ad2SJack F Vogel * Call gig speed drop workaround on LPLU before accessing 9878cfa0ad2SJack F Vogel * any PHY registers 9888cfa0ad2SJack F Vogel */ 9899d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 9908cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 9918cfa0ad2SJack F Vogel 9928cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 9938cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 9948cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 9958cfa0ad2SJack F Vogel &data); 9968cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 9978cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 9988cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 9998cfa0ad2SJack F Vogel data); 10008cfa0ad2SJack F Vogel if (ret_val) 10018cfa0ad2SJack F Vogel goto out; 10028cfa0ad2SJack F Vogel } else { 10038cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; 10048cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 10058cfa0ad2SJack F Vogel 10069d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 10079d81738fSJack F Vogel goto out; 10089d81738fSJack F Vogel 10098cfa0ad2SJack F Vogel /* 10108cfa0ad2SJack F Vogel * LPLU and SmartSpeed are mutually exclusive. LPLU is used 10118cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 10128cfa0ad2SJack F Vogel * important. During driver activity we should enable 10138cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 10148cfa0ad2SJack F Vogel */ 10158cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 10168cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 10178cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10188cfa0ad2SJack F Vogel &data); 10198cfa0ad2SJack F Vogel if (ret_val) 10208cfa0ad2SJack F Vogel goto out; 10218cfa0ad2SJack F Vogel 10228cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 10238cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 10248cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10258cfa0ad2SJack F Vogel data); 10268cfa0ad2SJack F Vogel if (ret_val) 10278cfa0ad2SJack F Vogel goto out; 10288cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 10298cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 10308cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10318cfa0ad2SJack F Vogel &data); 10328cfa0ad2SJack F Vogel if (ret_val) 10338cfa0ad2SJack F Vogel goto out; 10348cfa0ad2SJack F Vogel 10358cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 10368cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 10378cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10388cfa0ad2SJack F Vogel data); 10398cfa0ad2SJack F Vogel if (ret_val) 10408cfa0ad2SJack F Vogel goto out; 10418cfa0ad2SJack F Vogel } 10428cfa0ad2SJack F Vogel } 10438cfa0ad2SJack F Vogel 10448cfa0ad2SJack F Vogel out: 10458cfa0ad2SJack F Vogel return ret_val; 10468cfa0ad2SJack F Vogel } 10478cfa0ad2SJack F Vogel 10488cfa0ad2SJack F Vogel /** 10498cfa0ad2SJack F Vogel * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state 10508cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 10518cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 10528cfa0ad2SJack F Vogel * 10538cfa0ad2SJack F Vogel * Sets the LPLU D3 state according to the active flag. When 10548cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 10558cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 10568cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 10578cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 10588cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 10598cfa0ad2SJack F Vogel * PHY setup routines. 10608cfa0ad2SJack F Vogel **/ 1061daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 10628cfa0ad2SJack F Vogel { 10638cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 10648cfa0ad2SJack F Vogel u32 phy_ctrl; 10658cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 10668cfa0ad2SJack F Vogel u16 data; 10678cfa0ad2SJack F Vogel 10688cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan"); 10698cfa0ad2SJack F Vogel 10708cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 10718cfa0ad2SJack F Vogel 10728cfa0ad2SJack F Vogel if (!active) { 10738cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; 10748cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 10759d81738fSJack F Vogel 10769d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 10779d81738fSJack F Vogel goto out; 10789d81738fSJack F Vogel 10798cfa0ad2SJack F Vogel /* 10808cfa0ad2SJack F Vogel * LPLU and SmartSpeed are mutually exclusive. LPLU is used 10818cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 10828cfa0ad2SJack F Vogel * important. During driver activity we should enable 10838cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 10848cfa0ad2SJack F Vogel */ 10858cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 10868cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 10878cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10888cfa0ad2SJack F Vogel &data); 10898cfa0ad2SJack F Vogel if (ret_val) 10908cfa0ad2SJack F Vogel goto out; 10918cfa0ad2SJack F Vogel 10928cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 10938cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 10948cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 10958cfa0ad2SJack F Vogel data); 10968cfa0ad2SJack F Vogel if (ret_val) 10978cfa0ad2SJack F Vogel goto out; 10988cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 10998cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 11008cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 11018cfa0ad2SJack F Vogel &data); 11028cfa0ad2SJack F Vogel if (ret_val) 11038cfa0ad2SJack F Vogel goto out; 11048cfa0ad2SJack F Vogel 11058cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 11068cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 11078cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 11088cfa0ad2SJack F Vogel data); 11098cfa0ad2SJack F Vogel if (ret_val) 11108cfa0ad2SJack F Vogel goto out; 11118cfa0ad2SJack F Vogel } 11128cfa0ad2SJack F Vogel } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 11138cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 11148cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 11158cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; 11168cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 11178cfa0ad2SJack F Vogel 11189d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 11199d81738fSJack F Vogel goto out; 11209d81738fSJack F Vogel 11218cfa0ad2SJack F Vogel /* 11228cfa0ad2SJack F Vogel * Call gig speed drop workaround on LPLU before accessing 11238cfa0ad2SJack F Vogel * any PHY registers 11248cfa0ad2SJack F Vogel */ 11259d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 11268cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 11278cfa0ad2SJack F Vogel 11288cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 11298cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 11308cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 11318cfa0ad2SJack F Vogel &data); 11328cfa0ad2SJack F Vogel if (ret_val) 11338cfa0ad2SJack F Vogel goto out; 11348cfa0ad2SJack F Vogel 11358cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 11368cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 11378cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 11388cfa0ad2SJack F Vogel data); 11398cfa0ad2SJack F Vogel } 11408cfa0ad2SJack F Vogel 11418cfa0ad2SJack F Vogel out: 11428cfa0ad2SJack F Vogel return ret_val; 11438cfa0ad2SJack F Vogel } 11448cfa0ad2SJack F Vogel 11458cfa0ad2SJack F Vogel /** 11468cfa0ad2SJack F Vogel * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 11478cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 11488cfa0ad2SJack F Vogel * @bank: pointer to the variable that returns the active bank 11498cfa0ad2SJack F Vogel * 11508cfa0ad2SJack F Vogel * Reads signature byte from the NVM using the flash access registers. 1151d035aa2dSJack F Vogel * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. 11528cfa0ad2SJack F Vogel **/ 11538cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) 11548cfa0ad2SJack F Vogel { 1155d035aa2dSJack F Vogel u32 eecd; 11568cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 11578cfa0ad2SJack F Vogel u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); 11588cfa0ad2SJack F Vogel u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; 1159d035aa2dSJack F Vogel u8 sig_byte = 0; 1160d035aa2dSJack F Vogel s32 ret_val = E1000_SUCCESS; 11618cfa0ad2SJack F Vogel 1162d035aa2dSJack F Vogel switch (hw->mac.type) { 1163d035aa2dSJack F Vogel case e1000_ich8lan: 1164d035aa2dSJack F Vogel case e1000_ich9lan: 1165d035aa2dSJack F Vogel eecd = E1000_READ_REG(hw, E1000_EECD); 1166d035aa2dSJack F Vogel if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == 1167d035aa2dSJack F Vogel E1000_EECD_SEC1VAL_VALID_MASK) { 1168d035aa2dSJack F Vogel if (eecd & E1000_EECD_SEC1VAL) 11698cfa0ad2SJack F Vogel *bank = 1; 11708cfa0ad2SJack F Vogel else 11718cfa0ad2SJack F Vogel *bank = 0; 1172d035aa2dSJack F Vogel 1173d035aa2dSJack F Vogel goto out; 1174d035aa2dSJack F Vogel } 1175d035aa2dSJack F Vogel DEBUGOUT("Unable to determine valid NVM bank via EEC - " 1176d035aa2dSJack F Vogel "reading flash signature\n"); 1177d035aa2dSJack F Vogel /* fall-thru */ 1178d035aa2dSJack F Vogel default: 1179d035aa2dSJack F Vogel /* set bank to 0 in case flash read fails */ 11808cfa0ad2SJack F Vogel *bank = 0; 11818cfa0ad2SJack F Vogel 1182d035aa2dSJack F Vogel /* Check bank 0 */ 1183d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, 1184d035aa2dSJack F Vogel &sig_byte); 1185d035aa2dSJack F Vogel if (ret_val) 1186d035aa2dSJack F Vogel goto out; 1187d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 1188d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 1189d035aa2dSJack F Vogel *bank = 0; 1190d035aa2dSJack F Vogel goto out; 1191d035aa2dSJack F Vogel } 1192d035aa2dSJack F Vogel 1193d035aa2dSJack F Vogel /* Check bank 1 */ 1194d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + 1195d035aa2dSJack F Vogel bank1_offset, 1196d035aa2dSJack F Vogel &sig_byte); 1197d035aa2dSJack F Vogel if (ret_val) 1198d035aa2dSJack F Vogel goto out; 1199d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 1200d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 12018cfa0ad2SJack F Vogel *bank = 1; 1202d035aa2dSJack F Vogel goto out; 12038cfa0ad2SJack F Vogel } 12048cfa0ad2SJack F Vogel 1205d035aa2dSJack F Vogel DEBUGOUT("ERROR: No valid NVM bank present\n"); 1206d035aa2dSJack F Vogel ret_val = -E1000_ERR_NVM; 1207d035aa2dSJack F Vogel break; 1208d035aa2dSJack F Vogel } 1209d035aa2dSJack F Vogel out: 12108cfa0ad2SJack F Vogel return ret_val; 12118cfa0ad2SJack F Vogel } 12128cfa0ad2SJack F Vogel 12138cfa0ad2SJack F Vogel /** 12148cfa0ad2SJack F Vogel * e1000_read_nvm_ich8lan - Read word(s) from the NVM 12158cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 12168cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to read. 12178cfa0ad2SJack F Vogel * @words: Size of data to read in words 12188cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to read at offset. 12198cfa0ad2SJack F Vogel * 12208cfa0ad2SJack F Vogel * Reads a word(s) from the NVM using the flash access registers. 12218cfa0ad2SJack F Vogel **/ 12228cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 12238cfa0ad2SJack F Vogel u16 *data) 12248cfa0ad2SJack F Vogel { 12258cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 1226daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 12278cfa0ad2SJack F Vogel u32 act_offset; 12288cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 12298cfa0ad2SJack F Vogel u32 bank = 0; 12308cfa0ad2SJack F Vogel u16 i, word; 12318cfa0ad2SJack F Vogel 12328cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_nvm_ich8lan"); 12338cfa0ad2SJack F Vogel 12348cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 12358cfa0ad2SJack F Vogel (words == 0)) { 12368cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 12378cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 12388cfa0ad2SJack F Vogel goto out; 12398cfa0ad2SJack F Vogel } 12408cfa0ad2SJack F Vogel 12418cfa0ad2SJack F Vogel ret_val = nvm->ops.acquire(hw); 12428cfa0ad2SJack F Vogel if (ret_val) 12438cfa0ad2SJack F Vogel goto out; 12448cfa0ad2SJack F Vogel 12458cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 12468cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 1247d035aa2dSJack F Vogel goto release; 12488cfa0ad2SJack F Vogel 12498cfa0ad2SJack F Vogel act_offset = (bank) ? nvm->flash_bank_size : 0; 12508cfa0ad2SJack F Vogel act_offset += offset; 12518cfa0ad2SJack F Vogel 12528cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 12538cfa0ad2SJack F Vogel if ((dev_spec->shadow_ram) && 12548cfa0ad2SJack F Vogel (dev_spec->shadow_ram[offset+i].modified)) { 12558cfa0ad2SJack F Vogel data[i] = dev_spec->shadow_ram[offset+i].value; 12568cfa0ad2SJack F Vogel } else { 12578cfa0ad2SJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, 12588cfa0ad2SJack F Vogel act_offset + i, 12598cfa0ad2SJack F Vogel &word); 12608cfa0ad2SJack F Vogel if (ret_val) 12618cfa0ad2SJack F Vogel break; 12628cfa0ad2SJack F Vogel data[i] = word; 12638cfa0ad2SJack F Vogel } 12648cfa0ad2SJack F Vogel } 12658cfa0ad2SJack F Vogel 1266d035aa2dSJack F Vogel release: 12678cfa0ad2SJack F Vogel nvm->ops.release(hw); 12688cfa0ad2SJack F Vogel 12698cfa0ad2SJack F Vogel out: 1270d035aa2dSJack F Vogel if (ret_val) 1271d035aa2dSJack F Vogel DEBUGOUT1("NVM read error: %d\n", ret_val); 1272d035aa2dSJack F Vogel 12738cfa0ad2SJack F Vogel return ret_val; 12748cfa0ad2SJack F Vogel } 12758cfa0ad2SJack F Vogel 12768cfa0ad2SJack F Vogel /** 12778cfa0ad2SJack F Vogel * e1000_flash_cycle_init_ich8lan - Initialize flash 12788cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 12798cfa0ad2SJack F Vogel * 12808cfa0ad2SJack F Vogel * This function does initial flash setup so that a new read/write/erase cycle 12818cfa0ad2SJack F Vogel * can be started. 12828cfa0ad2SJack F Vogel **/ 12838cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) 12848cfa0ad2SJack F Vogel { 12858cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 12868cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 12878cfa0ad2SJack F Vogel s32 i = 0; 12888cfa0ad2SJack F Vogel 12898cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_init_ich8lan"); 12908cfa0ad2SJack F Vogel 12918cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 12928cfa0ad2SJack F Vogel 12938cfa0ad2SJack F Vogel /* Check if the flash descriptor is valid */ 12948cfa0ad2SJack F Vogel if (hsfsts.hsf_status.fldesvalid == 0) { 12958cfa0ad2SJack F Vogel DEBUGOUT("Flash descriptor invalid. " 12968cfa0ad2SJack F Vogel "SW Sequencing must be used."); 12978cfa0ad2SJack F Vogel goto out; 12988cfa0ad2SJack F Vogel } 12998cfa0ad2SJack F Vogel 13008cfa0ad2SJack F Vogel /* Clear FCERR and DAEL in hw status by writing 1 */ 13018cfa0ad2SJack F Vogel hsfsts.hsf_status.flcerr = 1; 13028cfa0ad2SJack F Vogel hsfsts.hsf_status.dael = 1; 13038cfa0ad2SJack F Vogel 13048cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); 13058cfa0ad2SJack F Vogel 13068cfa0ad2SJack F Vogel /* 13078cfa0ad2SJack F Vogel * Either we should have a hardware SPI cycle in progress 13088cfa0ad2SJack F Vogel * bit to check against, in order to start a new cycle or 13098cfa0ad2SJack F Vogel * FDONE bit should be changed in the hardware so that it 13108cfa0ad2SJack F Vogel * is 1 after hardware reset, which can then be used as an 13118cfa0ad2SJack F Vogel * indication whether a cycle is in progress or has been 13128cfa0ad2SJack F Vogel * completed. 13138cfa0ad2SJack F Vogel */ 13148cfa0ad2SJack F Vogel 13158cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcinprog == 0) { 13168cfa0ad2SJack F Vogel /* 13178cfa0ad2SJack F Vogel * There is no cycle running at present, 13188cfa0ad2SJack F Vogel * so we can start a cycle. 13198cfa0ad2SJack F Vogel * Begin by setting Flash Cycle Done. 13208cfa0ad2SJack F Vogel */ 13218cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 13228cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); 13238cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 13248cfa0ad2SJack F Vogel } else { 13258cfa0ad2SJack F Vogel /* 13268cfa0ad2SJack F Vogel * Otherwise poll for sometime so the current 13278cfa0ad2SJack F Vogel * cycle has a chance to end before giving up. 13288cfa0ad2SJack F Vogel */ 13298cfa0ad2SJack F Vogel for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 13308cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 13318cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 13328cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcinprog == 0) { 13338cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 13348cfa0ad2SJack F Vogel break; 13358cfa0ad2SJack F Vogel } 13368cfa0ad2SJack F Vogel usec_delay(1); 13378cfa0ad2SJack F Vogel } 13388cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 13398cfa0ad2SJack F Vogel /* 13408cfa0ad2SJack F Vogel * Successful in waiting for previous cycle to timeout, 13418cfa0ad2SJack F Vogel * now set the Flash Cycle Done. 13428cfa0ad2SJack F Vogel */ 13438cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 1344daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, 13458cfa0ad2SJack F Vogel hsfsts.regval); 13468cfa0ad2SJack F Vogel } else { 13478cfa0ad2SJack F Vogel DEBUGOUT("Flash controller busy, cannot get access"); 13488cfa0ad2SJack F Vogel } 13498cfa0ad2SJack F Vogel } 13508cfa0ad2SJack F Vogel 13518cfa0ad2SJack F Vogel out: 13528cfa0ad2SJack F Vogel return ret_val; 13538cfa0ad2SJack F Vogel } 13548cfa0ad2SJack F Vogel 13558cfa0ad2SJack F Vogel /** 13568cfa0ad2SJack F Vogel * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) 13578cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 13588cfa0ad2SJack F Vogel * @timeout: maximum time to wait for completion 13598cfa0ad2SJack F Vogel * 13608cfa0ad2SJack F Vogel * This function starts a flash cycle and waits for its completion. 13618cfa0ad2SJack F Vogel **/ 13628cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) 13638cfa0ad2SJack F Vogel { 13648cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 13658cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 13668cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 13678cfa0ad2SJack F Vogel u32 i = 0; 13688cfa0ad2SJack F Vogel 13698cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_ich8lan"); 13708cfa0ad2SJack F Vogel 13718cfa0ad2SJack F Vogel /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 13728cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 13738cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcgo = 1; 13748cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 13758cfa0ad2SJack F Vogel 13768cfa0ad2SJack F Vogel /* wait till FDONE bit is set to 1 */ 13778cfa0ad2SJack F Vogel do { 13788cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 13798cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcdone == 1) 13808cfa0ad2SJack F Vogel break; 13818cfa0ad2SJack F Vogel usec_delay(1); 13828cfa0ad2SJack F Vogel } while (i++ < timeout); 13838cfa0ad2SJack F Vogel 13848cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) 13858cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 13868cfa0ad2SJack F Vogel 13878cfa0ad2SJack F Vogel return ret_val; 13888cfa0ad2SJack F Vogel } 13898cfa0ad2SJack F Vogel 13908cfa0ad2SJack F Vogel /** 13918cfa0ad2SJack F Vogel * e1000_read_flash_word_ich8lan - Read word from flash 13928cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 13938cfa0ad2SJack F Vogel * @offset: offset to data location 13948cfa0ad2SJack F Vogel * @data: pointer to the location for storing the data 13958cfa0ad2SJack F Vogel * 13968cfa0ad2SJack F Vogel * Reads the flash word at offset into data. Offset is converted 13978cfa0ad2SJack F Vogel * to bytes before read. 13988cfa0ad2SJack F Vogel **/ 13998cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, 14008cfa0ad2SJack F Vogel u16 *data) 14018cfa0ad2SJack F Vogel { 14028cfa0ad2SJack F Vogel s32 ret_val; 14038cfa0ad2SJack F Vogel 14048cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_word_ich8lan"); 14058cfa0ad2SJack F Vogel 14068cfa0ad2SJack F Vogel if (!data) { 14078cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 14088cfa0ad2SJack F Vogel goto out; 14098cfa0ad2SJack F Vogel } 14108cfa0ad2SJack F Vogel 14118cfa0ad2SJack F Vogel /* Must convert offset into bytes. */ 14128cfa0ad2SJack F Vogel offset <<= 1; 14138cfa0ad2SJack F Vogel 14148cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data); 14158cfa0ad2SJack F Vogel 14168cfa0ad2SJack F Vogel out: 14178cfa0ad2SJack F Vogel return ret_val; 14188cfa0ad2SJack F Vogel } 14198cfa0ad2SJack F Vogel 14208cfa0ad2SJack F Vogel /** 14218cfa0ad2SJack F Vogel * e1000_read_flash_byte_ich8lan - Read byte from flash 14228cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 14238cfa0ad2SJack F Vogel * @offset: The offset of the byte to read. 14248cfa0ad2SJack F Vogel * @data: Pointer to a byte to store the value read. 14258cfa0ad2SJack F Vogel * 14268cfa0ad2SJack F Vogel * Reads a single byte from the NVM using the flash access registers. 14278cfa0ad2SJack F Vogel **/ 14288cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 14298cfa0ad2SJack F Vogel u8 *data) 14308cfa0ad2SJack F Vogel { 14318cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 14328cfa0ad2SJack F Vogel u16 word = 0; 14338cfa0ad2SJack F Vogel 14348cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); 14358cfa0ad2SJack F Vogel if (ret_val) 14368cfa0ad2SJack F Vogel goto out; 14378cfa0ad2SJack F Vogel 14388cfa0ad2SJack F Vogel *data = (u8)word; 14398cfa0ad2SJack F Vogel 14408cfa0ad2SJack F Vogel out: 14418cfa0ad2SJack F Vogel return ret_val; 14428cfa0ad2SJack F Vogel } 14438cfa0ad2SJack F Vogel 14448cfa0ad2SJack F Vogel /** 14458cfa0ad2SJack F Vogel * e1000_read_flash_data_ich8lan - Read byte or word from NVM 14468cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 14478cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte or word to read. 14488cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 14498cfa0ad2SJack F Vogel * @data: Pointer to the word to store the value read. 14508cfa0ad2SJack F Vogel * 14518cfa0ad2SJack F Vogel * Reads a byte or word from the NVM using the flash access registers. 14528cfa0ad2SJack F Vogel **/ 14538cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 14548cfa0ad2SJack F Vogel u8 size, u16 *data) 14558cfa0ad2SJack F Vogel { 14568cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 14578cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 14588cfa0ad2SJack F Vogel u32 flash_linear_addr; 14598cfa0ad2SJack F Vogel u32 flash_data = 0; 14608cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 14618cfa0ad2SJack F Vogel u8 count = 0; 14628cfa0ad2SJack F Vogel 14638cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_data_ich8lan"); 14648cfa0ad2SJack F Vogel 14658cfa0ad2SJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 14668cfa0ad2SJack F Vogel goto out; 14678cfa0ad2SJack F Vogel 14688cfa0ad2SJack F Vogel flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + 14698cfa0ad2SJack F Vogel hw->nvm.flash_base_addr; 14708cfa0ad2SJack F Vogel 14718cfa0ad2SJack F Vogel do { 14728cfa0ad2SJack F Vogel usec_delay(1); 14738cfa0ad2SJack F Vogel /* Steps */ 14748cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 14758cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 14768cfa0ad2SJack F Vogel break; 14778cfa0ad2SJack F Vogel 14788cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 14798cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 14808cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 14818cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 14828cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 14838cfa0ad2SJack F Vogel 14848cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 14858cfa0ad2SJack F Vogel 14868cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 14878cfa0ad2SJack F Vogel ICH_FLASH_READ_COMMAND_TIMEOUT); 14888cfa0ad2SJack F Vogel 14898cfa0ad2SJack F Vogel /* 14908cfa0ad2SJack F Vogel * Check if FCERR is set to 1, if set to 1, clear it 14918cfa0ad2SJack F Vogel * and try the whole sequence a few more times, else 14928cfa0ad2SJack F Vogel * read in (shift in) the Flash Data0, the order is 14938cfa0ad2SJack F Vogel * least significant byte first msb to lsb 14948cfa0ad2SJack F Vogel */ 14958cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 14968cfa0ad2SJack F Vogel flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); 1497daf9197cSJack F Vogel if (size == 1) 14988cfa0ad2SJack F Vogel *data = (u8)(flash_data & 0x000000FF); 1499daf9197cSJack F Vogel else if (size == 2) 15008cfa0ad2SJack F Vogel *data = (u16)(flash_data & 0x0000FFFF); 15018cfa0ad2SJack F Vogel break; 15028cfa0ad2SJack F Vogel } else { 15038cfa0ad2SJack F Vogel /* 15048cfa0ad2SJack F Vogel * If we've gotten here, then things are probably 15058cfa0ad2SJack F Vogel * completely hosed, but if the error condition is 15068cfa0ad2SJack F Vogel * detected, it won't hurt to give it another try... 15078cfa0ad2SJack F Vogel * ICH_FLASH_CYCLE_REPEAT_COUNT times. 15088cfa0ad2SJack F Vogel */ 15098cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 15108cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 15118cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcerr == 1) { 15128cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 15138cfa0ad2SJack F Vogel continue; 15148cfa0ad2SJack F Vogel } else if (hsfsts.hsf_status.flcdone == 0) { 15158cfa0ad2SJack F Vogel DEBUGOUT("Timeout error - flash cycle " 15168cfa0ad2SJack F Vogel "did not complete."); 15178cfa0ad2SJack F Vogel break; 15188cfa0ad2SJack F Vogel } 15198cfa0ad2SJack F Vogel } 15208cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 15218cfa0ad2SJack F Vogel 15228cfa0ad2SJack F Vogel out: 15238cfa0ad2SJack F Vogel return ret_val; 15248cfa0ad2SJack F Vogel } 15258cfa0ad2SJack F Vogel 15268cfa0ad2SJack F Vogel /** 15278cfa0ad2SJack F Vogel * e1000_write_nvm_ich8lan - Write word(s) to the NVM 15288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 15298cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to write. 15308cfa0ad2SJack F Vogel * @words: Size of data to write in words 15318cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to write at offset. 15328cfa0ad2SJack F Vogel * 15338cfa0ad2SJack F Vogel * Writes a byte or word to the NVM using the flash access registers. 15348cfa0ad2SJack F Vogel **/ 15358cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 15368cfa0ad2SJack F Vogel u16 *data) 15378cfa0ad2SJack F Vogel { 15388cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 1539daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 15408cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 15418cfa0ad2SJack F Vogel u16 i; 15428cfa0ad2SJack F Vogel 15438cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_nvm_ich8lan"); 15448cfa0ad2SJack F Vogel 15458cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 15468cfa0ad2SJack F Vogel (words == 0)) { 15478cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 15488cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 15498cfa0ad2SJack F Vogel goto out; 15508cfa0ad2SJack F Vogel } 15518cfa0ad2SJack F Vogel 15528cfa0ad2SJack F Vogel ret_val = nvm->ops.acquire(hw); 15538cfa0ad2SJack F Vogel if (ret_val) 15548cfa0ad2SJack F Vogel goto out; 15558cfa0ad2SJack F Vogel 15568cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 15578cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].modified = TRUE; 15588cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].value = data[i]; 15598cfa0ad2SJack F Vogel } 15608cfa0ad2SJack F Vogel 15618cfa0ad2SJack F Vogel nvm->ops.release(hw); 15628cfa0ad2SJack F Vogel 15638cfa0ad2SJack F Vogel out: 15648cfa0ad2SJack F Vogel return ret_val; 15658cfa0ad2SJack F Vogel } 15668cfa0ad2SJack F Vogel 15678cfa0ad2SJack F Vogel /** 15688cfa0ad2SJack F Vogel * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM 15698cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 15708cfa0ad2SJack F Vogel * 15718cfa0ad2SJack F Vogel * The NVM checksum is updated by calling the generic update_nvm_checksum, 15728cfa0ad2SJack F Vogel * which writes the checksum to the shadow ram. The changes in the shadow 15738cfa0ad2SJack F Vogel * ram are then committed to the EEPROM by processing each bank at a time 15748cfa0ad2SJack F Vogel * checking for the modified bit and writing only the pending changes. 15758cfa0ad2SJack F Vogel * After a successful commit, the shadow ram is cleared and is ready for 15768cfa0ad2SJack F Vogel * future writes. 15778cfa0ad2SJack F Vogel **/ 15788cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) 15798cfa0ad2SJack F Vogel { 15808cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 1581daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 15828cfa0ad2SJack F Vogel u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 15838cfa0ad2SJack F Vogel s32 ret_val; 15848cfa0ad2SJack F Vogel u16 data; 15858cfa0ad2SJack F Vogel 15868cfa0ad2SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_ich8lan"); 15878cfa0ad2SJack F Vogel 15888cfa0ad2SJack F Vogel ret_val = e1000_update_nvm_checksum_generic(hw); 15898cfa0ad2SJack F Vogel if (ret_val) 15908cfa0ad2SJack F Vogel goto out; 15918cfa0ad2SJack F Vogel 15928cfa0ad2SJack F Vogel if (nvm->type != e1000_nvm_flash_sw) 15938cfa0ad2SJack F Vogel goto out; 15948cfa0ad2SJack F Vogel 15958cfa0ad2SJack F Vogel ret_val = nvm->ops.acquire(hw); 15968cfa0ad2SJack F Vogel if (ret_val) 15978cfa0ad2SJack F Vogel goto out; 15988cfa0ad2SJack F Vogel 15998cfa0ad2SJack F Vogel /* 16008cfa0ad2SJack F Vogel * We're writing to the opposite bank so if we're on bank 1, 16018cfa0ad2SJack F Vogel * write to bank 0 etc. We also need to erase the segment that 16028cfa0ad2SJack F Vogel * is going to be written 16038cfa0ad2SJack F Vogel */ 16048cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 1605d035aa2dSJack F Vogel if (ret_val != E1000_SUCCESS) { 1606d035aa2dSJack F Vogel nvm->ops.release(hw); 16078cfa0ad2SJack F Vogel goto out; 1608d035aa2dSJack F Vogel } 16098cfa0ad2SJack F Vogel 16108cfa0ad2SJack F Vogel if (bank == 0) { 16118cfa0ad2SJack F Vogel new_bank_offset = nvm->flash_bank_size; 16128cfa0ad2SJack F Vogel old_bank_offset = 0; 1613d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 1614d035aa2dSJack F Vogel if (ret_val) { 1615d035aa2dSJack F Vogel nvm->ops.release(hw); 1616d035aa2dSJack F Vogel goto out; 1617d035aa2dSJack F Vogel } 16188cfa0ad2SJack F Vogel } else { 16198cfa0ad2SJack F Vogel old_bank_offset = nvm->flash_bank_size; 16208cfa0ad2SJack F Vogel new_bank_offset = 0; 1621d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 1622d035aa2dSJack F Vogel if (ret_val) { 1623d035aa2dSJack F Vogel nvm->ops.release(hw); 1624d035aa2dSJack F Vogel goto out; 1625d035aa2dSJack F Vogel } 16268cfa0ad2SJack F Vogel } 16278cfa0ad2SJack F Vogel 16288cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 16298cfa0ad2SJack F Vogel /* 16308cfa0ad2SJack F Vogel * Determine whether to write the value stored 16318cfa0ad2SJack F Vogel * in the other NVM bank or a modified value stored 16328cfa0ad2SJack F Vogel * in the shadow RAM 16338cfa0ad2SJack F Vogel */ 16348cfa0ad2SJack F Vogel if (dev_spec->shadow_ram[i].modified) { 16358cfa0ad2SJack F Vogel data = dev_spec->shadow_ram[i].value; 16368cfa0ad2SJack F Vogel } else { 1637d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, i + 1638d035aa2dSJack F Vogel old_bank_offset, 16398cfa0ad2SJack F Vogel &data); 1640d035aa2dSJack F Vogel if (ret_val) 1641d035aa2dSJack F Vogel break; 16428cfa0ad2SJack F Vogel } 16438cfa0ad2SJack F Vogel 16448cfa0ad2SJack F Vogel /* 16458cfa0ad2SJack F Vogel * If the word is 0x13, then make sure the signature bits 16468cfa0ad2SJack F Vogel * (15:14) are 11b until the commit has completed. 16478cfa0ad2SJack F Vogel * This will allow us to write 10b which indicates the 16488cfa0ad2SJack F Vogel * signature is valid. We want to do this after the write 16498cfa0ad2SJack F Vogel * has completed so that we don't mark the segment valid 16508cfa0ad2SJack F Vogel * while the write is still in progress 16518cfa0ad2SJack F Vogel */ 16528cfa0ad2SJack F Vogel if (i == E1000_ICH_NVM_SIG_WORD) 16538cfa0ad2SJack F Vogel data |= E1000_ICH_NVM_SIG_MASK; 16548cfa0ad2SJack F Vogel 16558cfa0ad2SJack F Vogel /* Convert offset to bytes. */ 16568cfa0ad2SJack F Vogel act_offset = (i + new_bank_offset) << 1; 16578cfa0ad2SJack F Vogel 16588cfa0ad2SJack F Vogel usec_delay(100); 16598cfa0ad2SJack F Vogel /* Write the bytes to the new bank. */ 16608cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 16618cfa0ad2SJack F Vogel act_offset, 16628cfa0ad2SJack F Vogel (u8)data); 16638cfa0ad2SJack F Vogel if (ret_val) 16648cfa0ad2SJack F Vogel break; 16658cfa0ad2SJack F Vogel 16668cfa0ad2SJack F Vogel usec_delay(100); 16678cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 16688cfa0ad2SJack F Vogel act_offset + 1, 16698cfa0ad2SJack F Vogel (u8)(data >> 8)); 16708cfa0ad2SJack F Vogel if (ret_val) 16718cfa0ad2SJack F Vogel break; 16728cfa0ad2SJack F Vogel } 16738cfa0ad2SJack F Vogel 16748cfa0ad2SJack F Vogel /* 16758cfa0ad2SJack F Vogel * Don't bother writing the segment valid bits if sector 16768cfa0ad2SJack F Vogel * programming failed. 16778cfa0ad2SJack F Vogel */ 16788cfa0ad2SJack F Vogel if (ret_val) { 16798cfa0ad2SJack F Vogel DEBUGOUT("Flash commit failed.\n"); 16808cfa0ad2SJack F Vogel nvm->ops.release(hw); 16818cfa0ad2SJack F Vogel goto out; 16828cfa0ad2SJack F Vogel } 16838cfa0ad2SJack F Vogel 16848cfa0ad2SJack F Vogel /* 16858cfa0ad2SJack F Vogel * Finally validate the new segment by setting bit 15:14 16868cfa0ad2SJack F Vogel * to 10b in word 0x13 , this can be done without an 16878cfa0ad2SJack F Vogel * erase as well since these bits are 11 to start with 16888cfa0ad2SJack F Vogel * and we need to change bit 14 to 0b 16898cfa0ad2SJack F Vogel */ 16908cfa0ad2SJack F Vogel act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 1691d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); 1692d035aa2dSJack F Vogel if (ret_val) { 1693d035aa2dSJack F Vogel nvm->ops.release(hw); 1694d035aa2dSJack F Vogel goto out; 1695d035aa2dSJack F Vogel } 16968cfa0ad2SJack F Vogel data &= 0xBFFF; 16978cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 16988cfa0ad2SJack F Vogel act_offset * 2 + 1, 16998cfa0ad2SJack F Vogel (u8)(data >> 8)); 17008cfa0ad2SJack F Vogel if (ret_val) { 17018cfa0ad2SJack F Vogel nvm->ops.release(hw); 17028cfa0ad2SJack F Vogel goto out; 17038cfa0ad2SJack F Vogel } 17048cfa0ad2SJack F Vogel 17058cfa0ad2SJack F Vogel /* 17068cfa0ad2SJack F Vogel * And invalidate the previously valid segment by setting 17078cfa0ad2SJack F Vogel * its signature word (0x13) high_byte to 0b. This can be 17088cfa0ad2SJack F Vogel * done without an erase because flash erase sets all bits 17098cfa0ad2SJack F Vogel * to 1's. We can write 1's to 0's without an erase 17108cfa0ad2SJack F Vogel */ 17118cfa0ad2SJack F Vogel act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 17128cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); 17138cfa0ad2SJack F Vogel if (ret_val) { 17148cfa0ad2SJack F Vogel nvm->ops.release(hw); 17158cfa0ad2SJack F Vogel goto out; 17168cfa0ad2SJack F Vogel } 17178cfa0ad2SJack F Vogel 17188cfa0ad2SJack F Vogel /* Great! Everything worked, we can now clear the cached entries. */ 17198cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 17208cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 17218cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 17228cfa0ad2SJack F Vogel } 17238cfa0ad2SJack F Vogel 17248cfa0ad2SJack F Vogel nvm->ops.release(hw); 17258cfa0ad2SJack F Vogel 17268cfa0ad2SJack F Vogel /* 17278cfa0ad2SJack F Vogel * Reload the EEPROM, or else modifications will not appear 17288cfa0ad2SJack F Vogel * until after the next adapter reset. 17298cfa0ad2SJack F Vogel */ 17308cfa0ad2SJack F Vogel nvm->ops.reload(hw); 17318cfa0ad2SJack F Vogel msec_delay(10); 17328cfa0ad2SJack F Vogel 17338cfa0ad2SJack F Vogel out: 1734d035aa2dSJack F Vogel if (ret_val) 1735d035aa2dSJack F Vogel DEBUGOUT1("NVM update error: %d\n", ret_val); 1736d035aa2dSJack F Vogel 17378cfa0ad2SJack F Vogel return ret_val; 17388cfa0ad2SJack F Vogel } 17398cfa0ad2SJack F Vogel 17408cfa0ad2SJack F Vogel /** 17418cfa0ad2SJack F Vogel * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum 17428cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 17438cfa0ad2SJack F Vogel * 17448cfa0ad2SJack F Vogel * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. 1745daf9197cSJack F Vogel * If the bit is 0, that the EEPROM had been modified, but the checksum was not 1746daf9197cSJack F Vogel * calculated, in which case we need to calculate the checksum and set bit 6. 17478cfa0ad2SJack F Vogel **/ 17488cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) 17498cfa0ad2SJack F Vogel { 17508cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 17518cfa0ad2SJack F Vogel u16 data; 17528cfa0ad2SJack F Vogel 17538cfa0ad2SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan"); 17548cfa0ad2SJack F Vogel 17558cfa0ad2SJack F Vogel /* 17568cfa0ad2SJack F Vogel * Read 0x19 and check bit 6. If this bit is 0, the checksum 17578cfa0ad2SJack F Vogel * needs to be fixed. This bit is an indication that the NVM 17588cfa0ad2SJack F Vogel * was prepared by OEM software and did not calculate the 17598cfa0ad2SJack F Vogel * checksum...a likely scenario. 17608cfa0ad2SJack F Vogel */ 17618cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data); 17628cfa0ad2SJack F Vogel if (ret_val) 17638cfa0ad2SJack F Vogel goto out; 17648cfa0ad2SJack F Vogel 17658cfa0ad2SJack F Vogel if ((data & 0x40) == 0) { 17668cfa0ad2SJack F Vogel data |= 0x40; 17678cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data); 17688cfa0ad2SJack F Vogel if (ret_val) 17698cfa0ad2SJack F Vogel goto out; 17708cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.update(hw); 17718cfa0ad2SJack F Vogel if (ret_val) 17728cfa0ad2SJack F Vogel goto out; 17738cfa0ad2SJack F Vogel } 17748cfa0ad2SJack F Vogel 17758cfa0ad2SJack F Vogel ret_val = e1000_validate_nvm_checksum_generic(hw); 17768cfa0ad2SJack F Vogel 17778cfa0ad2SJack F Vogel out: 17788cfa0ad2SJack F Vogel return ret_val; 17798cfa0ad2SJack F Vogel } 17808cfa0ad2SJack F Vogel 17818cfa0ad2SJack F Vogel /** 17828cfa0ad2SJack F Vogel * e1000_write_flash_data_ich8lan - Writes bytes to the NVM 17838cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 17848cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte/word to read. 17858cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 17868cfa0ad2SJack F Vogel * @data: The byte(s) to write to the NVM. 17878cfa0ad2SJack F Vogel * 17888cfa0ad2SJack F Vogel * Writes one/two bytes to the NVM using the flash access registers. 17898cfa0ad2SJack F Vogel **/ 17908cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 17918cfa0ad2SJack F Vogel u8 size, u16 data) 17928cfa0ad2SJack F Vogel { 17938cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 17948cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 17958cfa0ad2SJack F Vogel u32 flash_linear_addr; 17968cfa0ad2SJack F Vogel u32 flash_data = 0; 17978cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 17988cfa0ad2SJack F Vogel u8 count = 0; 17998cfa0ad2SJack F Vogel 18008cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_ich8_data"); 18018cfa0ad2SJack F Vogel 18028cfa0ad2SJack F Vogel if (size < 1 || size > 2 || data > size * 0xff || 18038cfa0ad2SJack F Vogel offset > ICH_FLASH_LINEAR_ADDR_MASK) 18048cfa0ad2SJack F Vogel goto out; 18058cfa0ad2SJack F Vogel 18068cfa0ad2SJack F Vogel flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + 18078cfa0ad2SJack F Vogel hw->nvm.flash_base_addr; 18088cfa0ad2SJack F Vogel 18098cfa0ad2SJack F Vogel do { 18108cfa0ad2SJack F Vogel usec_delay(1); 18118cfa0ad2SJack F Vogel /* Steps */ 18128cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 18138cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 18148cfa0ad2SJack F Vogel break; 18158cfa0ad2SJack F Vogel 18168cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 18178cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 18188cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 18198cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 18208cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 18218cfa0ad2SJack F Vogel 18228cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 18238cfa0ad2SJack F Vogel 18248cfa0ad2SJack F Vogel if (size == 1) 18258cfa0ad2SJack F Vogel flash_data = (u32)data & 0x00FF; 18268cfa0ad2SJack F Vogel else 18278cfa0ad2SJack F Vogel flash_data = (u32)data; 18288cfa0ad2SJack F Vogel 18298cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data); 18308cfa0ad2SJack F Vogel 18318cfa0ad2SJack F Vogel /* 18328cfa0ad2SJack F Vogel * check if FCERR is set to 1 , if set to 1, clear it 18338cfa0ad2SJack F Vogel * and try the whole sequence a few more times else done 18348cfa0ad2SJack F Vogel */ 18358cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 18368cfa0ad2SJack F Vogel ICH_FLASH_WRITE_COMMAND_TIMEOUT); 1837daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 18388cfa0ad2SJack F Vogel break; 1839daf9197cSJack F Vogel 18408cfa0ad2SJack F Vogel /* 18418cfa0ad2SJack F Vogel * If we're here, then things are most likely 18428cfa0ad2SJack F Vogel * completely hosed, but if the error condition 18438cfa0ad2SJack F Vogel * is detected, it won't hurt to give it another 18448cfa0ad2SJack F Vogel * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 18458cfa0ad2SJack F Vogel */ 1846daf9197cSJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 18478cfa0ad2SJack F Vogel if (hsfsts.hsf_status.flcerr == 1) { 18488cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 18498cfa0ad2SJack F Vogel continue; 18508cfa0ad2SJack F Vogel } else if (hsfsts.hsf_status.flcdone == 0) { 18518cfa0ad2SJack F Vogel DEBUGOUT("Timeout error - flash cycle " 18528cfa0ad2SJack F Vogel "did not complete."); 18538cfa0ad2SJack F Vogel break; 18548cfa0ad2SJack F Vogel } 18558cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 18568cfa0ad2SJack F Vogel 18578cfa0ad2SJack F Vogel out: 18588cfa0ad2SJack F Vogel return ret_val; 18598cfa0ad2SJack F Vogel } 18608cfa0ad2SJack F Vogel 18618cfa0ad2SJack F Vogel /** 18628cfa0ad2SJack F Vogel * e1000_write_flash_byte_ich8lan - Write a single byte to NVM 18638cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 18648cfa0ad2SJack F Vogel * @offset: The index of the byte to read. 18658cfa0ad2SJack F Vogel * @data: The byte to write to the NVM. 18668cfa0ad2SJack F Vogel * 18678cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 18688cfa0ad2SJack F Vogel **/ 18698cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 18708cfa0ad2SJack F Vogel u8 data) 18718cfa0ad2SJack F Vogel { 18728cfa0ad2SJack F Vogel u16 word = (u16)data; 18738cfa0ad2SJack F Vogel 18748cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_flash_byte_ich8lan"); 18758cfa0ad2SJack F Vogel 18768cfa0ad2SJack F Vogel return e1000_write_flash_data_ich8lan(hw, offset, 1, word); 18778cfa0ad2SJack F Vogel } 18788cfa0ad2SJack F Vogel 18798cfa0ad2SJack F Vogel /** 18808cfa0ad2SJack F Vogel * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM 18818cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 18828cfa0ad2SJack F Vogel * @offset: The offset of the byte to write. 18838cfa0ad2SJack F Vogel * @byte: The byte to write to the NVM. 18848cfa0ad2SJack F Vogel * 18858cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 18868cfa0ad2SJack F Vogel * Goes through a retry algorithm before giving up. 18878cfa0ad2SJack F Vogel **/ 18888cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 18898cfa0ad2SJack F Vogel u32 offset, u8 byte) 18908cfa0ad2SJack F Vogel { 18918cfa0ad2SJack F Vogel s32 ret_val; 18928cfa0ad2SJack F Vogel u16 program_retries; 18938cfa0ad2SJack F Vogel 18948cfa0ad2SJack F Vogel DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan"); 18958cfa0ad2SJack F Vogel 18968cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 18978cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) 18988cfa0ad2SJack F Vogel goto out; 18998cfa0ad2SJack F Vogel 19008cfa0ad2SJack F Vogel for (program_retries = 0; program_retries < 100; program_retries++) { 19018cfa0ad2SJack F Vogel DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset); 19028cfa0ad2SJack F Vogel usec_delay(100); 19038cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 19048cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) 19058cfa0ad2SJack F Vogel break; 19068cfa0ad2SJack F Vogel } 19078cfa0ad2SJack F Vogel if (program_retries == 100) { 19088cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 19098cfa0ad2SJack F Vogel goto out; 19108cfa0ad2SJack F Vogel } 19118cfa0ad2SJack F Vogel 19128cfa0ad2SJack F Vogel out: 19138cfa0ad2SJack F Vogel return ret_val; 19148cfa0ad2SJack F Vogel } 19158cfa0ad2SJack F Vogel 19168cfa0ad2SJack F Vogel /** 19178cfa0ad2SJack F Vogel * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM 19188cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 19198cfa0ad2SJack F Vogel * @bank: 0 for first bank, 1 for second bank, etc. 19208cfa0ad2SJack F Vogel * 19218cfa0ad2SJack F Vogel * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. 19228cfa0ad2SJack F Vogel * bank N is 4096 * N + flash_reg_addr. 19238cfa0ad2SJack F Vogel **/ 19248cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) 19258cfa0ad2SJack F Vogel { 19268cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 19278cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 19288cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 19298cfa0ad2SJack F Vogel u32 flash_linear_addr; 19308cfa0ad2SJack F Vogel /* bank size is in 16bit words - adjust to bytes */ 19318cfa0ad2SJack F Vogel u32 flash_bank_size = nvm->flash_bank_size * 2; 19328cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 19338cfa0ad2SJack F Vogel s32 count = 0; 19348cfa0ad2SJack F Vogel s32 j, iteration, sector_size; 19358cfa0ad2SJack F Vogel 19368cfa0ad2SJack F Vogel DEBUGFUNC("e1000_erase_flash_bank_ich8lan"); 19378cfa0ad2SJack F Vogel 19388cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 19398cfa0ad2SJack F Vogel 19408cfa0ad2SJack F Vogel /* 19418cfa0ad2SJack F Vogel * Determine HW Sector size: Read BERASE bits of hw flash status 19428cfa0ad2SJack F Vogel * register 19438cfa0ad2SJack F Vogel * 00: The Hw sector is 256 bytes, hence we need to erase 16 19448cfa0ad2SJack F Vogel * consecutive sectors. The start index for the nth Hw sector 19458cfa0ad2SJack F Vogel * can be calculated as = bank * 4096 + n * 256 19468cfa0ad2SJack F Vogel * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. 19478cfa0ad2SJack F Vogel * The start index for the nth Hw sector can be calculated 19488cfa0ad2SJack F Vogel * as = bank * 4096 19498cfa0ad2SJack F Vogel * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 19508cfa0ad2SJack F Vogel * (ich9 only, otherwise error condition) 19518cfa0ad2SJack F Vogel * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 19528cfa0ad2SJack F Vogel */ 19538cfa0ad2SJack F Vogel switch (hsfsts.hsf_status.berasesz) { 19548cfa0ad2SJack F Vogel case 0: 19558cfa0ad2SJack F Vogel /* Hw sector size 256 */ 19568cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_256; 19578cfa0ad2SJack F Vogel iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; 19588cfa0ad2SJack F Vogel break; 19598cfa0ad2SJack F Vogel case 1: 19608cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_4K; 19619d81738fSJack F Vogel iteration = 1; 19628cfa0ad2SJack F Vogel break; 19638cfa0ad2SJack F Vogel case 2: 19648cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich9lan) { 19658cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_8K; 19668cfa0ad2SJack F Vogel iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; 19678cfa0ad2SJack F Vogel } else { 19688cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 19698cfa0ad2SJack F Vogel goto out; 19708cfa0ad2SJack F Vogel } 19718cfa0ad2SJack F Vogel break; 19728cfa0ad2SJack F Vogel case 3: 19738cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_64K; 19749d81738fSJack F Vogel iteration = 1; 19758cfa0ad2SJack F Vogel break; 19768cfa0ad2SJack F Vogel default: 19778cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 19788cfa0ad2SJack F Vogel goto out; 19798cfa0ad2SJack F Vogel } 19808cfa0ad2SJack F Vogel 19818cfa0ad2SJack F Vogel /* Start with the base address, then add the sector offset. */ 19828cfa0ad2SJack F Vogel flash_linear_addr = hw->nvm.flash_base_addr; 19838cfa0ad2SJack F Vogel flash_linear_addr += (bank) ? (sector_size * iteration) : 0; 19848cfa0ad2SJack F Vogel 19858cfa0ad2SJack F Vogel for (j = 0; j < iteration ; j++) { 19868cfa0ad2SJack F Vogel do { 19878cfa0ad2SJack F Vogel /* Steps */ 19888cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 19898cfa0ad2SJack F Vogel if (ret_val) 19908cfa0ad2SJack F Vogel goto out; 19918cfa0ad2SJack F Vogel 19928cfa0ad2SJack F Vogel /* 19938cfa0ad2SJack F Vogel * Write a value 11 (block Erase) in Flash 19948cfa0ad2SJack F Vogel * Cycle field in hw flash control 19958cfa0ad2SJack F Vogel */ 19968cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, 19978cfa0ad2SJack F Vogel ICH_FLASH_HSFCTL); 19988cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; 1999daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 20008cfa0ad2SJack F Vogel hsflctl.regval); 20018cfa0ad2SJack F Vogel 20028cfa0ad2SJack F Vogel /* 20038cfa0ad2SJack F Vogel * Write the last 24 bits of an index within the 20048cfa0ad2SJack F Vogel * block into Flash Linear address field in Flash 20058cfa0ad2SJack F Vogel * Address. 20068cfa0ad2SJack F Vogel */ 20078cfa0ad2SJack F Vogel flash_linear_addr += (j * sector_size); 2008daf9197cSJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, 20098cfa0ad2SJack F Vogel flash_linear_addr); 20108cfa0ad2SJack F Vogel 20118cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 20128cfa0ad2SJack F Vogel ICH_FLASH_ERASE_COMMAND_TIMEOUT); 2013daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 20148cfa0ad2SJack F Vogel break; 2015daf9197cSJack F Vogel 20168cfa0ad2SJack F Vogel /* 20178cfa0ad2SJack F Vogel * Check if FCERR is set to 1. If 1, 20188cfa0ad2SJack F Vogel * clear it and try the whole sequence 20198cfa0ad2SJack F Vogel * a few more times else Done 20208cfa0ad2SJack F Vogel */ 20218cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 20228cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 2023daf9197cSJack F Vogel if (hsfsts.hsf_status.flcerr == 1) 2024daf9197cSJack F Vogel /* repeat for some time before giving up */ 20258cfa0ad2SJack F Vogel continue; 2026daf9197cSJack F Vogel else if (hsfsts.hsf_status.flcdone == 0) 20278cfa0ad2SJack F Vogel goto out; 20288cfa0ad2SJack F Vogel } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); 20298cfa0ad2SJack F Vogel } 20308cfa0ad2SJack F Vogel 20318cfa0ad2SJack F Vogel out: 20328cfa0ad2SJack F Vogel return ret_val; 20338cfa0ad2SJack F Vogel } 20348cfa0ad2SJack F Vogel 20358cfa0ad2SJack F Vogel /** 20368cfa0ad2SJack F Vogel * e1000_valid_led_default_ich8lan - Set the default LED settings 20378cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 20388cfa0ad2SJack F Vogel * @data: Pointer to the LED settings 20398cfa0ad2SJack F Vogel * 20408cfa0ad2SJack F Vogel * Reads the LED default settings from the NVM to data. If the NVM LED 20418cfa0ad2SJack F Vogel * settings is all 0's or F's, set the LED default to a valid LED default 20428cfa0ad2SJack F Vogel * setting. 20438cfa0ad2SJack F Vogel **/ 20448cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) 20458cfa0ad2SJack F Vogel { 20468cfa0ad2SJack F Vogel s32 ret_val; 20478cfa0ad2SJack F Vogel 20488cfa0ad2SJack F Vogel DEBUGFUNC("e1000_valid_led_default_ich8lan"); 20498cfa0ad2SJack F Vogel 20508cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 20518cfa0ad2SJack F Vogel if (ret_val) { 20528cfa0ad2SJack F Vogel DEBUGOUT("NVM Read Error\n"); 20538cfa0ad2SJack F Vogel goto out; 20548cfa0ad2SJack F Vogel } 20558cfa0ad2SJack F Vogel 20568cfa0ad2SJack F Vogel if (*data == ID_LED_RESERVED_0000 || 20578cfa0ad2SJack F Vogel *data == ID_LED_RESERVED_FFFF) 20588cfa0ad2SJack F Vogel *data = ID_LED_DEFAULT_ICH8LAN; 20598cfa0ad2SJack F Vogel 20608cfa0ad2SJack F Vogel out: 20618cfa0ad2SJack F Vogel return ret_val; 20628cfa0ad2SJack F Vogel } 20638cfa0ad2SJack F Vogel 20648cfa0ad2SJack F Vogel /** 20659d81738fSJack F Vogel * e1000_id_led_init_pchlan - store LED configurations 20669d81738fSJack F Vogel * @hw: pointer to the HW structure 20679d81738fSJack F Vogel * 20689d81738fSJack F Vogel * PCH does not control LEDs via the LEDCTL register, rather it uses 20699d81738fSJack F Vogel * the PHY LED configuration register. 20709d81738fSJack F Vogel * 20719d81738fSJack F Vogel * PCH also does not have an "always on" or "always off" mode which 20729d81738fSJack F Vogel * complicates the ID feature. Instead of using the "on" mode to indicate 20739d81738fSJack F Vogel * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()), 20749d81738fSJack F Vogel * use "link_up" mode. The LEDs will still ID on request if there is no 20759d81738fSJack F Vogel * link based on logic in e1000_led_[on|off]_pchlan(). 20769d81738fSJack F Vogel **/ 20779d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) 20789d81738fSJack F Vogel { 20799d81738fSJack F Vogel struct e1000_mac_info *mac = &hw->mac; 20809d81738fSJack F Vogel s32 ret_val; 20819d81738fSJack F Vogel const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; 20829d81738fSJack F Vogel const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; 20839d81738fSJack F Vogel u16 data, i, temp, shift; 20849d81738fSJack F Vogel 20859d81738fSJack F Vogel DEBUGFUNC("e1000_id_led_init_pchlan"); 20869d81738fSJack F Vogel 20879d81738fSJack F Vogel /* Get default ID LED modes */ 20889d81738fSJack F Vogel ret_val = hw->nvm.ops.valid_led_default(hw, &data); 20899d81738fSJack F Vogel if (ret_val) 20909d81738fSJack F Vogel goto out; 20919d81738fSJack F Vogel 20929d81738fSJack F Vogel mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); 20939d81738fSJack F Vogel mac->ledctl_mode1 = mac->ledctl_default; 20949d81738fSJack F Vogel mac->ledctl_mode2 = mac->ledctl_default; 20959d81738fSJack F Vogel 20969d81738fSJack F Vogel for (i = 0; i < 4; i++) { 20979d81738fSJack F Vogel temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; 20989d81738fSJack F Vogel shift = (i * 5); 20999d81738fSJack F Vogel switch (temp) { 21009d81738fSJack F Vogel case ID_LED_ON1_DEF2: 21019d81738fSJack F Vogel case ID_LED_ON1_ON2: 21029d81738fSJack F Vogel case ID_LED_ON1_OFF2: 21039d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 21049d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_on << shift); 21059d81738fSJack F Vogel break; 21069d81738fSJack F Vogel case ID_LED_OFF1_DEF2: 21079d81738fSJack F Vogel case ID_LED_OFF1_ON2: 21089d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 21099d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 21109d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_off << shift); 21119d81738fSJack F Vogel break; 21129d81738fSJack F Vogel default: 21139d81738fSJack F Vogel /* Do nothing */ 21149d81738fSJack F Vogel break; 21159d81738fSJack F Vogel } 21169d81738fSJack F Vogel switch (temp) { 21179d81738fSJack F Vogel case ID_LED_DEF1_ON2: 21189d81738fSJack F Vogel case ID_LED_ON1_ON2: 21199d81738fSJack F Vogel case ID_LED_OFF1_ON2: 21209d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 21219d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_on << shift); 21229d81738fSJack F Vogel break; 21239d81738fSJack F Vogel case ID_LED_DEF1_OFF2: 21249d81738fSJack F Vogel case ID_LED_ON1_OFF2: 21259d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 21269d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 21279d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_off << shift); 21289d81738fSJack F Vogel break; 21299d81738fSJack F Vogel default: 21309d81738fSJack F Vogel /* Do nothing */ 21319d81738fSJack F Vogel break; 21329d81738fSJack F Vogel } 21339d81738fSJack F Vogel } 21349d81738fSJack F Vogel 21359d81738fSJack F Vogel out: 21369d81738fSJack F Vogel return ret_val; 21379d81738fSJack F Vogel } 21389d81738fSJack F Vogel 21399d81738fSJack F Vogel /** 21408cfa0ad2SJack F Vogel * e1000_get_bus_info_ich8lan - Get/Set the bus type and width 21418cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 21428cfa0ad2SJack F Vogel * 21438cfa0ad2SJack F Vogel * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability 21448cfa0ad2SJack F Vogel * register, so the the bus width is hard coded. 21458cfa0ad2SJack F Vogel **/ 21468cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) 21478cfa0ad2SJack F Vogel { 21488cfa0ad2SJack F Vogel struct e1000_bus_info *bus = &hw->bus; 21498cfa0ad2SJack F Vogel s32 ret_val; 21508cfa0ad2SJack F Vogel 21518cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_bus_info_ich8lan"); 21528cfa0ad2SJack F Vogel 21538cfa0ad2SJack F Vogel ret_val = e1000_get_bus_info_pcie_generic(hw); 21548cfa0ad2SJack F Vogel 21558cfa0ad2SJack F Vogel /* 21568cfa0ad2SJack F Vogel * ICH devices are "PCI Express"-ish. They have 21578cfa0ad2SJack F Vogel * a configuration space, but do not contain 21588cfa0ad2SJack F Vogel * PCI Express Capability registers, so bus width 21598cfa0ad2SJack F Vogel * must be hardcoded. 21608cfa0ad2SJack F Vogel */ 21618cfa0ad2SJack F Vogel if (bus->width == e1000_bus_width_unknown) 21628cfa0ad2SJack F Vogel bus->width = e1000_bus_width_pcie_x1; 21638cfa0ad2SJack F Vogel 21648cfa0ad2SJack F Vogel return ret_val; 21658cfa0ad2SJack F Vogel } 21668cfa0ad2SJack F Vogel 21678cfa0ad2SJack F Vogel /** 21688cfa0ad2SJack F Vogel * e1000_reset_hw_ich8lan - Reset the hardware 21698cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 21708cfa0ad2SJack F Vogel * 21718cfa0ad2SJack F Vogel * Does a full reset of the hardware which includes a reset of the PHY and 21728cfa0ad2SJack F Vogel * MAC. 21738cfa0ad2SJack F Vogel **/ 21748cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) 21758cfa0ad2SJack F Vogel { 21768cfa0ad2SJack F Vogel u32 ctrl, icr, kab; 21778cfa0ad2SJack F Vogel s32 ret_val; 21788cfa0ad2SJack F Vogel 21798cfa0ad2SJack F Vogel DEBUGFUNC("e1000_reset_hw_ich8lan"); 21808cfa0ad2SJack F Vogel 21818cfa0ad2SJack F Vogel /* 21828cfa0ad2SJack F Vogel * Prevent the PCI-E bus from sticking if there is no TLP connection 21838cfa0ad2SJack F Vogel * on the last TLP read/write transaction when MAC is reset. 21848cfa0ad2SJack F Vogel */ 21858cfa0ad2SJack F Vogel ret_val = e1000_disable_pcie_master_generic(hw); 2186daf9197cSJack F Vogel if (ret_val) 21878cfa0ad2SJack F Vogel DEBUGOUT("PCI-E Master disable polling has failed.\n"); 21888cfa0ad2SJack F Vogel 21898cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n"); 21908cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 21918cfa0ad2SJack F Vogel 21928cfa0ad2SJack F Vogel /* 21938cfa0ad2SJack F Vogel * Disable the Transmit and Receive units. Then delay to allow 21948cfa0ad2SJack F Vogel * any pending transactions to complete before we hit the MAC 21958cfa0ad2SJack F Vogel * with the global reset. 21968cfa0ad2SJack F Vogel */ 21978cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, 0); 21988cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); 21998cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw); 22008cfa0ad2SJack F Vogel 22018cfa0ad2SJack F Vogel msec_delay(10); 22028cfa0ad2SJack F Vogel 22038cfa0ad2SJack F Vogel /* Workaround for ICH8 bit corruption issue in FIFO memory */ 22048cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 22058cfa0ad2SJack F Vogel /* Set Tx and Rx buffer allocation to 8k apiece. */ 22068cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K); 22078cfa0ad2SJack F Vogel /* Set Packet Buffer Size to 16k. */ 22088cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); 22098cfa0ad2SJack F Vogel } 22108cfa0ad2SJack F Vogel 22118cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 22128cfa0ad2SJack F Vogel 22138cfa0ad2SJack F Vogel if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { 22149d81738fSJack F Vogel /* Clear PHY Reset Asserted bit */ 22159d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan) { 22169d81738fSJack F Vogel u32 status = E1000_READ_REG(hw, E1000_STATUS); 22179d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, status & 22189d81738fSJack F Vogel ~E1000_STATUS_PHYRA); 22199d81738fSJack F Vogel } 22209d81738fSJack F Vogel 22218cfa0ad2SJack F Vogel /* 22228cfa0ad2SJack F Vogel * PHY HW reset requires MAC CORE reset at the same 22238cfa0ad2SJack F Vogel * time to make sure the interface between MAC and the 22248cfa0ad2SJack F Vogel * external PHY is reset. 22258cfa0ad2SJack F Vogel */ 22268cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_PHY_RST; 22278cfa0ad2SJack F Vogel } 22288cfa0ad2SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 2229daf9197cSJack F Vogel DEBUGOUT("Issuing a global reset to ich8lan\n"); 22308cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); 22318cfa0ad2SJack F Vogel msec_delay(20); 22328cfa0ad2SJack F Vogel 22339d81738fSJack F Vogel if (!ret_val) 22349d81738fSJack F Vogel e1000_release_swflag_ich8lan(hw); 22359d81738fSJack F Vogel 22369d81738fSJack F Vogel if (ctrl & E1000_CTRL_PHY_RST) 22379d81738fSJack F Vogel ret_val = hw->phy.ops.get_cfg_done(hw); 22389d81738fSJack F Vogel 22399d81738fSJack F Vogel if (hw->mac.type >= e1000_ich10lan) { 22409d81738fSJack F Vogel e1000_lan_init_done_ich8lan(hw); 22419d81738fSJack F Vogel } else { 22428cfa0ad2SJack F Vogel ret_val = e1000_get_auto_rd_done_generic(hw); 22438cfa0ad2SJack F Vogel if (ret_val) { 22448cfa0ad2SJack F Vogel /* 22458cfa0ad2SJack F Vogel * When auto config read does not complete, do not 22468cfa0ad2SJack F Vogel * return with an error. This can happen in situations 22478cfa0ad2SJack F Vogel * where there is no eeprom and prevents getting link. 22488cfa0ad2SJack F Vogel */ 22498cfa0ad2SJack F Vogel DEBUGOUT("Auto Read Done did not complete\n"); 22508cfa0ad2SJack F Vogel } 22519d81738fSJack F Vogel } 22528cfa0ad2SJack F Vogel 22538cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 22548cfa0ad2SJack F Vogel icr = E1000_READ_REG(hw, E1000_ICR); 22558cfa0ad2SJack F Vogel 22568cfa0ad2SJack F Vogel kab = E1000_READ_REG(hw, E1000_KABGTXD); 22578cfa0ad2SJack F Vogel kab |= E1000_KABGTXD_BGSQLBIAS; 22588cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_KABGTXD, kab); 22598cfa0ad2SJack F Vogel 22609d81738fSJack F Vogel if (hw->mac.type == e1000_pchlan) 22619d81738fSJack F Vogel ret_val = e1000_hv_phy_workarounds_ich8lan(hw); 22629d81738fSJack F Vogel 22638cfa0ad2SJack F Vogel return ret_val; 22648cfa0ad2SJack F Vogel } 22658cfa0ad2SJack F Vogel 22668cfa0ad2SJack F Vogel /** 22678cfa0ad2SJack F Vogel * e1000_init_hw_ich8lan - Initialize the hardware 22688cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 22698cfa0ad2SJack F Vogel * 22708cfa0ad2SJack F Vogel * Prepares the hardware for transmit and receive by doing the following: 22718cfa0ad2SJack F Vogel * - initialize hardware bits 22728cfa0ad2SJack F Vogel * - initialize LED identification 22738cfa0ad2SJack F Vogel * - setup receive address registers 22748cfa0ad2SJack F Vogel * - setup flow control 22758cfa0ad2SJack F Vogel * - setup transmit descriptors 22768cfa0ad2SJack F Vogel * - clear statistics 22778cfa0ad2SJack F Vogel **/ 22788cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) 22798cfa0ad2SJack F Vogel { 22808cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 22818cfa0ad2SJack F Vogel u32 ctrl_ext, txdctl, snoop; 22828cfa0ad2SJack F Vogel s32 ret_val; 22838cfa0ad2SJack F Vogel u16 i; 22848cfa0ad2SJack F Vogel 22858cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_hw_ich8lan"); 22868cfa0ad2SJack F Vogel 22878cfa0ad2SJack F Vogel e1000_initialize_hw_bits_ich8lan(hw); 22888cfa0ad2SJack F Vogel 22898cfa0ad2SJack F Vogel /* Initialize identification LED */ 2290d035aa2dSJack F Vogel ret_val = mac->ops.id_led_init(hw); 2291d035aa2dSJack F Vogel if (ret_val) 22928cfa0ad2SJack F Vogel /* This is not fatal and we should not stop init due to this */ 2293d035aa2dSJack F Vogel DEBUGOUT("Error initializing identification LED\n"); 22948cfa0ad2SJack F Vogel 22958cfa0ad2SJack F Vogel /* Setup the receive address. */ 22968cfa0ad2SJack F Vogel e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); 22978cfa0ad2SJack F Vogel 22988cfa0ad2SJack F Vogel /* Zero out the Multicast HASH table */ 22998cfa0ad2SJack F Vogel DEBUGOUT("Zeroing the MTA\n"); 23008cfa0ad2SJack F Vogel for (i = 0; i < mac->mta_reg_count; i++) 23018cfa0ad2SJack F Vogel E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 23028cfa0ad2SJack F Vogel 23039d81738fSJack F Vogel /* 23049d81738fSJack F Vogel * The 82578 Rx buffer will stall if wakeup is enabled in host and 23059d81738fSJack F Vogel * the ME. Reading the BM_WUC register will clear the host wakeup bit. 23069d81738fSJack F Vogel * Reset the phy after disabling host wakeup to reset the Rx buffer. 23079d81738fSJack F Vogel */ 23089d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 23099d81738fSJack F Vogel hw->phy.ops.read_reg(hw, BM_WUC, &i); 23109d81738fSJack F Vogel ret_val = e1000_phy_hw_reset_ich8lan(hw); 23119d81738fSJack F Vogel if (ret_val) 23129d81738fSJack F Vogel return ret_val; 23139d81738fSJack F Vogel } 23149d81738fSJack F Vogel 23158cfa0ad2SJack F Vogel /* Setup link and flow control */ 23168cfa0ad2SJack F Vogel ret_val = mac->ops.setup_link(hw); 23178cfa0ad2SJack F Vogel 23188cfa0ad2SJack F Vogel /* Set the transmit descriptor write-back policy for both queues */ 23198cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); 23208cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | 23218cfa0ad2SJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB; 23228cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | 23238cfa0ad2SJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH; 23248cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); 23258cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1)); 23268cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | 23278cfa0ad2SJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB; 23288cfa0ad2SJack F Vogel txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | 23298cfa0ad2SJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH; 23308cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl); 23318cfa0ad2SJack F Vogel 23328cfa0ad2SJack F Vogel /* 23338cfa0ad2SJack F Vogel * ICH8 has opposite polarity of no_snoop bits. 23348cfa0ad2SJack F Vogel * By default, we should use snoop behavior. 23358cfa0ad2SJack F Vogel */ 23368cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 23378cfa0ad2SJack F Vogel snoop = PCIE_ICH8_SNOOP_ALL; 23388cfa0ad2SJack F Vogel else 23398cfa0ad2SJack F Vogel snoop = (u32)~(PCIE_NO_SNOOP_ALL); 23408cfa0ad2SJack F Vogel e1000_set_pcie_no_snoop_generic(hw, snoop); 23418cfa0ad2SJack F Vogel 23428cfa0ad2SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 23438cfa0ad2SJack F Vogel ctrl_ext |= E1000_CTRL_EXT_RO_DIS; 23448cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 23458cfa0ad2SJack F Vogel 23468cfa0ad2SJack F Vogel /* 23478cfa0ad2SJack F Vogel * Clear all of the statistics registers (clear on read). It is 23488cfa0ad2SJack F Vogel * important that we do this after we have tried to establish link 23498cfa0ad2SJack F Vogel * because the symbol error count will increment wildly if there 23508cfa0ad2SJack F Vogel * is no link. 23518cfa0ad2SJack F Vogel */ 23528cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_ich8lan(hw); 23538cfa0ad2SJack F Vogel 23548cfa0ad2SJack F Vogel return ret_val; 23558cfa0ad2SJack F Vogel } 23568cfa0ad2SJack F Vogel /** 23578cfa0ad2SJack F Vogel * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits 23588cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 23598cfa0ad2SJack F Vogel * 23608cfa0ad2SJack F Vogel * Sets/Clears required hardware bits necessary for correctly setting up the 23618cfa0ad2SJack F Vogel * hardware for transmit and receive. 23628cfa0ad2SJack F Vogel **/ 23638cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) 23648cfa0ad2SJack F Vogel { 23658cfa0ad2SJack F Vogel u32 reg; 23668cfa0ad2SJack F Vogel 23678cfa0ad2SJack F Vogel DEBUGFUNC("e1000_initialize_hw_bits_ich8lan"); 23688cfa0ad2SJack F Vogel 23698cfa0ad2SJack F Vogel /* Extended Device Control */ 23708cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 23718cfa0ad2SJack F Vogel reg |= (1 << 22); 23729d81738fSJack F Vogel /* Enable PHY low-power state when MAC is at D3 w/o WoL */ 23739d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan) 23749d81738fSJack F Vogel reg |= E1000_CTRL_EXT_PHYPDEN; 23758cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); 23768cfa0ad2SJack F Vogel 23778cfa0ad2SJack F Vogel /* Transmit Descriptor Control 0 */ 23788cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); 23798cfa0ad2SJack F Vogel reg |= (1 << 22); 23808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); 23818cfa0ad2SJack F Vogel 23828cfa0ad2SJack F Vogel /* Transmit Descriptor Control 1 */ 23838cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); 23848cfa0ad2SJack F Vogel reg |= (1 << 22); 23858cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); 23868cfa0ad2SJack F Vogel 23878cfa0ad2SJack F Vogel /* Transmit Arbitration Control 0 */ 23888cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(0)); 23898cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 23908cfa0ad2SJack F Vogel reg |= (1 << 28) | (1 << 29); 23918cfa0ad2SJack F Vogel reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); 23928cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(0), reg); 23938cfa0ad2SJack F Vogel 23948cfa0ad2SJack F Vogel /* Transmit Arbitration Control 1 */ 23958cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(1)); 23968cfa0ad2SJack F Vogel if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) 23978cfa0ad2SJack F Vogel reg &= ~(1 << 28); 23988cfa0ad2SJack F Vogel else 23998cfa0ad2SJack F Vogel reg |= (1 << 28); 24008cfa0ad2SJack F Vogel reg |= (1 << 24) | (1 << 26) | (1 << 30); 24018cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(1), reg); 24028cfa0ad2SJack F Vogel 24038cfa0ad2SJack F Vogel /* Device Status */ 24048cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 24058cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_STATUS); 24068cfa0ad2SJack F Vogel reg &= ~(1 << 31); 24078cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, reg); 24088cfa0ad2SJack F Vogel } 24098cfa0ad2SJack F Vogel 24108cfa0ad2SJack F Vogel return; 24118cfa0ad2SJack F Vogel } 24128cfa0ad2SJack F Vogel 24138cfa0ad2SJack F Vogel /** 24148cfa0ad2SJack F Vogel * e1000_setup_link_ich8lan - Setup flow control and link settings 24158cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 24168cfa0ad2SJack F Vogel * 24178cfa0ad2SJack F Vogel * Determines which flow control settings to use, then configures flow 24188cfa0ad2SJack F Vogel * control. Calls the appropriate media-specific link configuration 24198cfa0ad2SJack F Vogel * function. Assuming the adapter has a valid link partner, a valid link 24208cfa0ad2SJack F Vogel * should be established. Assumes the hardware has previously been reset 24218cfa0ad2SJack F Vogel * and the transmitter and receiver are not enabled. 24228cfa0ad2SJack F Vogel **/ 24238cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) 24248cfa0ad2SJack F Vogel { 24258cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 24268cfa0ad2SJack F Vogel 24278cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_link_ich8lan"); 24288cfa0ad2SJack F Vogel 24298cfa0ad2SJack F Vogel if (hw->phy.ops.check_reset_block(hw)) 24308cfa0ad2SJack F Vogel goto out; 24318cfa0ad2SJack F Vogel 24328cfa0ad2SJack F Vogel /* 24338cfa0ad2SJack F Vogel * ICH parts do not have a word in the NVM to determine 24348cfa0ad2SJack F Vogel * the default flow control setting, so we explicitly 24358cfa0ad2SJack F Vogel * set it to full. 24368cfa0ad2SJack F Vogel */ 2437daf9197cSJack F Vogel if (hw->fc.requested_mode == e1000_fc_default) 2438daf9197cSJack F Vogel hw->fc.requested_mode = e1000_fc_full; 24398cfa0ad2SJack F Vogel 2440daf9197cSJack F Vogel /* 2441daf9197cSJack F Vogel * Save off the requested flow control mode for use later. Depending 2442daf9197cSJack F Vogel * on the link partner's capabilities, we may or may not use this mode. 2443daf9197cSJack F Vogel */ 2444daf9197cSJack F Vogel hw->fc.current_mode = hw->fc.requested_mode; 24458cfa0ad2SJack F Vogel 2446daf9197cSJack F Vogel DEBUGOUT1("After fix-ups FlowControl is now = %x\n", 2447daf9197cSJack F Vogel hw->fc.current_mode); 24488cfa0ad2SJack F Vogel 24498cfa0ad2SJack F Vogel /* Continue to configure the copper link. */ 24508cfa0ad2SJack F Vogel ret_val = hw->mac.ops.setup_physical_interface(hw); 24518cfa0ad2SJack F Vogel if (ret_val) 24528cfa0ad2SJack F Vogel goto out; 24538cfa0ad2SJack F Vogel 24548cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); 24559d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 24569d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 24579d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, 24589d81738fSJack F Vogel PHY_REG(BM_PORT_CTRL_PAGE, 27), 24599d81738fSJack F Vogel hw->fc.pause_time); 24609d81738fSJack F Vogel if (ret_val) 24619d81738fSJack F Vogel goto out; 24629d81738fSJack F Vogel } 24638cfa0ad2SJack F Vogel 24648cfa0ad2SJack F Vogel ret_val = e1000_set_fc_watermarks_generic(hw); 24658cfa0ad2SJack F Vogel 24668cfa0ad2SJack F Vogel out: 24678cfa0ad2SJack F Vogel return ret_val; 24688cfa0ad2SJack F Vogel } 24698cfa0ad2SJack F Vogel 24708cfa0ad2SJack F Vogel /** 24718cfa0ad2SJack F Vogel * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface 24728cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 24738cfa0ad2SJack F Vogel * 24748cfa0ad2SJack F Vogel * Configures the kumeran interface to the PHY to wait the appropriate time 24758cfa0ad2SJack F Vogel * when polling the PHY, then call the generic setup_copper_link to finish 24768cfa0ad2SJack F Vogel * configuring the copper link. 24778cfa0ad2SJack F Vogel **/ 24788cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) 24798cfa0ad2SJack F Vogel { 24808cfa0ad2SJack F Vogel u32 ctrl; 24818cfa0ad2SJack F Vogel s32 ret_val; 24828cfa0ad2SJack F Vogel u16 reg_data; 24838cfa0ad2SJack F Vogel 24848cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_ich8lan"); 24858cfa0ad2SJack F Vogel 24868cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 24878cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_SLU; 24888cfa0ad2SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 24898cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 24908cfa0ad2SJack F Vogel 24918cfa0ad2SJack F Vogel /* 24928cfa0ad2SJack F Vogel * Set the mac to wait the maximum time between each iteration 24938cfa0ad2SJack F Vogel * and increase the max iterations when polling the phy; 24948cfa0ad2SJack F Vogel * this fixes erroneous timeouts at 10Mbps. 24958cfa0ad2SJack F Vogel */ 24969d81738fSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 24979d81738fSJack F Vogel E1000_KMRNCTRLSTA_TIMEOUTS, 24988cfa0ad2SJack F Vogel 0xFFFF); 24998cfa0ad2SJack F Vogel if (ret_val) 25008cfa0ad2SJack F Vogel goto out; 25019d81738fSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 25029d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 25038cfa0ad2SJack F Vogel ®_data); 25048cfa0ad2SJack F Vogel if (ret_val) 25058cfa0ad2SJack F Vogel goto out; 25068cfa0ad2SJack F Vogel reg_data |= 0x3F; 25079d81738fSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 25089d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 25098cfa0ad2SJack F Vogel reg_data); 25108cfa0ad2SJack F Vogel if (ret_val) 25118cfa0ad2SJack F Vogel goto out; 25128cfa0ad2SJack F Vogel 2513d035aa2dSJack F Vogel switch (hw->phy.type) { 2514d035aa2dSJack F Vogel case e1000_phy_igp_3: 25158cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_igp(hw); 25168cfa0ad2SJack F Vogel if (ret_val) 25178cfa0ad2SJack F Vogel goto out; 2518d035aa2dSJack F Vogel break; 2519d035aa2dSJack F Vogel case e1000_phy_bm: 25209d81738fSJack F Vogel case e1000_phy_82578: 25218cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_m88(hw); 25228cfa0ad2SJack F Vogel if (ret_val) 25238cfa0ad2SJack F Vogel goto out; 2524d035aa2dSJack F Vogel break; 25259d81738fSJack F Vogel case e1000_phy_82577: 25269d81738fSJack F Vogel ret_val = e1000_copper_link_setup_82577(hw); 25279d81738fSJack F Vogel if (ret_val) 25289d81738fSJack F Vogel goto out; 25299d81738fSJack F Vogel break; 2530d035aa2dSJack F Vogel case e1000_phy_ife: 25318cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, 25328cfa0ad2SJack F Vogel ®_data); 25338cfa0ad2SJack F Vogel if (ret_val) 25348cfa0ad2SJack F Vogel goto out; 25358cfa0ad2SJack F Vogel 25368cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_AUTO_MDIX; 25378cfa0ad2SJack F Vogel 25388cfa0ad2SJack F Vogel switch (hw->phy.mdix) { 25398cfa0ad2SJack F Vogel case 1: 25408cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_FORCE_MDIX; 25418cfa0ad2SJack F Vogel break; 25428cfa0ad2SJack F Vogel case 2: 25438cfa0ad2SJack F Vogel reg_data |= IFE_PMC_FORCE_MDIX; 25448cfa0ad2SJack F Vogel break; 25458cfa0ad2SJack F Vogel case 0: 25468cfa0ad2SJack F Vogel default: 25478cfa0ad2SJack F Vogel reg_data |= IFE_PMC_AUTO_MDIX; 25488cfa0ad2SJack F Vogel break; 25498cfa0ad2SJack F Vogel } 25508cfa0ad2SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, 25518cfa0ad2SJack F Vogel reg_data); 25528cfa0ad2SJack F Vogel if (ret_val) 25538cfa0ad2SJack F Vogel goto out; 2554d035aa2dSJack F Vogel break; 2555d035aa2dSJack F Vogel default: 2556d035aa2dSJack F Vogel break; 25578cfa0ad2SJack F Vogel } 25588cfa0ad2SJack F Vogel ret_val = e1000_setup_copper_link_generic(hw); 25598cfa0ad2SJack F Vogel 25608cfa0ad2SJack F Vogel out: 25618cfa0ad2SJack F Vogel return ret_val; 25628cfa0ad2SJack F Vogel } 25638cfa0ad2SJack F Vogel 25648cfa0ad2SJack F Vogel /** 25658cfa0ad2SJack F Vogel * e1000_get_link_up_info_ich8lan - Get current link speed and duplex 25668cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 25678cfa0ad2SJack F Vogel * @speed: pointer to store current link speed 25688cfa0ad2SJack F Vogel * @duplex: pointer to store the current link duplex 25698cfa0ad2SJack F Vogel * 25708cfa0ad2SJack F Vogel * Calls the generic get_speed_and_duplex to retrieve the current link 25718cfa0ad2SJack F Vogel * information and then calls the Kumeran lock loss workaround for links at 25728cfa0ad2SJack F Vogel * gigabit speeds. 25738cfa0ad2SJack F Vogel **/ 25748cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, 25758cfa0ad2SJack F Vogel u16 *duplex) 25768cfa0ad2SJack F Vogel { 25778cfa0ad2SJack F Vogel s32 ret_val; 25788cfa0ad2SJack F Vogel 25798cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_link_up_info_ich8lan"); 25808cfa0ad2SJack F Vogel 25818cfa0ad2SJack F Vogel ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); 25828cfa0ad2SJack F Vogel if (ret_val) 25838cfa0ad2SJack F Vogel goto out; 25848cfa0ad2SJack F Vogel 25858cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_ich8lan) && 25868cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3) && 25878cfa0ad2SJack F Vogel (*speed == SPEED_1000)) { 25888cfa0ad2SJack F Vogel ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); 25898cfa0ad2SJack F Vogel } 25908cfa0ad2SJack F Vogel 25918cfa0ad2SJack F Vogel out: 25928cfa0ad2SJack F Vogel return ret_val; 25938cfa0ad2SJack F Vogel } 25948cfa0ad2SJack F Vogel 25958cfa0ad2SJack F Vogel /** 25968cfa0ad2SJack F Vogel * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround 25978cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 25988cfa0ad2SJack F Vogel * 25998cfa0ad2SJack F Vogel * Work-around for 82566 Kumeran PCS lock loss: 26008cfa0ad2SJack F Vogel * On link status change (i.e. PCI reset, speed change) and link is up and 26018cfa0ad2SJack F Vogel * speed is gigabit- 26028cfa0ad2SJack F Vogel * 0) if workaround is optionally disabled do nothing 26038cfa0ad2SJack F Vogel * 1) wait 1ms for Kumeran link to come up 26048cfa0ad2SJack F Vogel * 2) check Kumeran Diagnostic register PCS lock loss bit 26058cfa0ad2SJack F Vogel * 3) if not set the link is locked (all is good), otherwise... 26068cfa0ad2SJack F Vogel * 4) reset the PHY 26078cfa0ad2SJack F Vogel * 5) repeat up to 10 times 26088cfa0ad2SJack F Vogel * Note: this is only called for IGP3 copper when speed is 1gb. 26098cfa0ad2SJack F Vogel **/ 26108cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) 26118cfa0ad2SJack F Vogel { 2612daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 26138cfa0ad2SJack F Vogel u32 phy_ctrl; 26148cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 26158cfa0ad2SJack F Vogel u16 i, data; 26168cfa0ad2SJack F Vogel bool link; 26178cfa0ad2SJack F Vogel 26188cfa0ad2SJack F Vogel DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan"); 26198cfa0ad2SJack F Vogel 26208cfa0ad2SJack F Vogel if (!(dev_spec->kmrn_lock_loss_workaround_enabled)) 26218cfa0ad2SJack F Vogel goto out; 26228cfa0ad2SJack F Vogel 26238cfa0ad2SJack F Vogel /* 26248cfa0ad2SJack F Vogel * Make sure link is up before proceeding. If not just return. 26258cfa0ad2SJack F Vogel * Attempting this while link is negotiating fouled up link 26268cfa0ad2SJack F Vogel * stability 26278cfa0ad2SJack F Vogel */ 26288cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 26298cfa0ad2SJack F Vogel if (!link) { 26308cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 26318cfa0ad2SJack F Vogel goto out; 26328cfa0ad2SJack F Vogel } 26338cfa0ad2SJack F Vogel 26348cfa0ad2SJack F Vogel for (i = 0; i < 10; i++) { 26358cfa0ad2SJack F Vogel /* read once to clear */ 26368cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 26378cfa0ad2SJack F Vogel if (ret_val) 26388cfa0ad2SJack F Vogel goto out; 26398cfa0ad2SJack F Vogel /* and again to get new status */ 26408cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 26418cfa0ad2SJack F Vogel if (ret_val) 26428cfa0ad2SJack F Vogel goto out; 26438cfa0ad2SJack F Vogel 26448cfa0ad2SJack F Vogel /* check for PCS lock */ 26458cfa0ad2SJack F Vogel if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) { 26468cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 26478cfa0ad2SJack F Vogel goto out; 26488cfa0ad2SJack F Vogel } 26498cfa0ad2SJack F Vogel 26508cfa0ad2SJack F Vogel /* Issue PHY reset */ 26518cfa0ad2SJack F Vogel hw->phy.ops.reset(hw); 26528cfa0ad2SJack F Vogel msec_delay_irq(5); 26538cfa0ad2SJack F Vogel } 26548cfa0ad2SJack F Vogel /* Disable GigE link negotiation */ 26558cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 26568cfa0ad2SJack F Vogel phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | 26578cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 26588cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 26598cfa0ad2SJack F Vogel 26608cfa0ad2SJack F Vogel /* 26618cfa0ad2SJack F Vogel * Call gig speed drop workaround on Gig disable before accessing 26628cfa0ad2SJack F Vogel * any PHY registers 26638cfa0ad2SJack F Vogel */ 26648cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 26658cfa0ad2SJack F Vogel 26668cfa0ad2SJack F Vogel /* unable to acquire PCS lock */ 26678cfa0ad2SJack F Vogel ret_val = -E1000_ERR_PHY; 26688cfa0ad2SJack F Vogel 26698cfa0ad2SJack F Vogel out: 26708cfa0ad2SJack F Vogel return ret_val; 26718cfa0ad2SJack F Vogel } 26728cfa0ad2SJack F Vogel 26738cfa0ad2SJack F Vogel /** 26748cfa0ad2SJack F Vogel * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state 26758cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 26768cfa0ad2SJack F Vogel * @state: boolean value used to set the current Kumeran workaround state 26778cfa0ad2SJack F Vogel * 26788cfa0ad2SJack F Vogel * If ICH8, set the current Kumeran workaround state (enabled - TRUE 26798cfa0ad2SJack F Vogel * /disabled - FALSE). 26808cfa0ad2SJack F Vogel **/ 26818cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, 26828cfa0ad2SJack F Vogel bool state) 26838cfa0ad2SJack F Vogel { 2684daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 26858cfa0ad2SJack F Vogel 26868cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan"); 26878cfa0ad2SJack F Vogel 26888cfa0ad2SJack F Vogel if (hw->mac.type != e1000_ich8lan) { 26898cfa0ad2SJack F Vogel DEBUGOUT("Workaround applies to ICH8 only.\n"); 2690daf9197cSJack F Vogel return; 26918cfa0ad2SJack F Vogel } 26928cfa0ad2SJack F Vogel 26938cfa0ad2SJack F Vogel dev_spec->kmrn_lock_loss_workaround_enabled = state; 26948cfa0ad2SJack F Vogel 26958cfa0ad2SJack F Vogel return; 26968cfa0ad2SJack F Vogel } 26978cfa0ad2SJack F Vogel 26988cfa0ad2SJack F Vogel /** 26998cfa0ad2SJack F Vogel * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 27008cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 27018cfa0ad2SJack F Vogel * 27028cfa0ad2SJack F Vogel * Workaround for 82566 power-down on D3 entry: 27038cfa0ad2SJack F Vogel * 1) disable gigabit link 27048cfa0ad2SJack F Vogel * 2) write VR power-down enable 27058cfa0ad2SJack F Vogel * 3) read it back 27068cfa0ad2SJack F Vogel * Continue if successful, else issue LCD reset and repeat 27078cfa0ad2SJack F Vogel **/ 27088cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) 27098cfa0ad2SJack F Vogel { 27108cfa0ad2SJack F Vogel u32 reg; 27118cfa0ad2SJack F Vogel u16 data; 27128cfa0ad2SJack F Vogel u8 retry = 0; 27138cfa0ad2SJack F Vogel 27148cfa0ad2SJack F Vogel DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan"); 27158cfa0ad2SJack F Vogel 27168cfa0ad2SJack F Vogel if (hw->phy.type != e1000_phy_igp_3) 27178cfa0ad2SJack F Vogel goto out; 27188cfa0ad2SJack F Vogel 27198cfa0ad2SJack F Vogel /* Try the workaround twice (if needed) */ 27208cfa0ad2SJack F Vogel do { 27218cfa0ad2SJack F Vogel /* Disable link */ 27228cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 27238cfa0ad2SJack F Vogel reg |= (E1000_PHY_CTRL_GBE_DISABLE | 27248cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 27258cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg); 27268cfa0ad2SJack F Vogel 27278cfa0ad2SJack F Vogel /* 27288cfa0ad2SJack F Vogel * Call gig speed drop workaround on Gig disable before 27298cfa0ad2SJack F Vogel * accessing any PHY registers 27308cfa0ad2SJack F Vogel */ 27318cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 27328cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 27338cfa0ad2SJack F Vogel 27348cfa0ad2SJack F Vogel /* Write VR power-down enable */ 27358cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 27368cfa0ad2SJack F Vogel data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 2737daf9197cSJack F Vogel hw->phy.ops.write_reg(hw, IGP3_VR_CTRL, 27388cfa0ad2SJack F Vogel data | IGP3_VR_CTRL_MODE_SHUTDOWN); 27398cfa0ad2SJack F Vogel 27408cfa0ad2SJack F Vogel /* Read it back and test */ 27418cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 27428cfa0ad2SJack F Vogel data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 27438cfa0ad2SJack F Vogel if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) 27448cfa0ad2SJack F Vogel break; 27458cfa0ad2SJack F Vogel 27468cfa0ad2SJack F Vogel /* Issue PHY reset and repeat at most one more time */ 27478cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL); 27488cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST); 27498cfa0ad2SJack F Vogel retry++; 27508cfa0ad2SJack F Vogel } while (retry); 27518cfa0ad2SJack F Vogel 27528cfa0ad2SJack F Vogel out: 27538cfa0ad2SJack F Vogel return; 27548cfa0ad2SJack F Vogel } 27558cfa0ad2SJack F Vogel 27568cfa0ad2SJack F Vogel /** 27578cfa0ad2SJack F Vogel * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working 27588cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 27598cfa0ad2SJack F Vogel * 27608cfa0ad2SJack F Vogel * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), 27618cfa0ad2SJack F Vogel * LPLU, Gig disable, MDIC PHY reset): 27628cfa0ad2SJack F Vogel * 1) Set Kumeran Near-end loopback 27638cfa0ad2SJack F Vogel * 2) Clear Kumeran Near-end loopback 27648cfa0ad2SJack F Vogel * Should only be called for ICH8[m] devices with IGP_3 Phy. 27658cfa0ad2SJack F Vogel **/ 27668cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) 27678cfa0ad2SJack F Vogel { 27688cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 27698cfa0ad2SJack F Vogel u16 reg_data; 27708cfa0ad2SJack F Vogel 27718cfa0ad2SJack F Vogel DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); 27728cfa0ad2SJack F Vogel 27738cfa0ad2SJack F Vogel if ((hw->mac.type != e1000_ich8lan) || 27748cfa0ad2SJack F Vogel (hw->phy.type != e1000_phy_igp_3)) 27758cfa0ad2SJack F Vogel goto out; 27768cfa0ad2SJack F Vogel 27778cfa0ad2SJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 27788cfa0ad2SJack F Vogel ®_data); 27798cfa0ad2SJack F Vogel if (ret_val) 27808cfa0ad2SJack F Vogel goto out; 27818cfa0ad2SJack F Vogel reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; 27828cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 27838cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET, 27848cfa0ad2SJack F Vogel reg_data); 27858cfa0ad2SJack F Vogel if (ret_val) 27868cfa0ad2SJack F Vogel goto out; 27878cfa0ad2SJack F Vogel reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; 27888cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 27898cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET, 27908cfa0ad2SJack F Vogel reg_data); 27918cfa0ad2SJack F Vogel out: 27928cfa0ad2SJack F Vogel return; 27938cfa0ad2SJack F Vogel } 27948cfa0ad2SJack F Vogel 27958cfa0ad2SJack F Vogel /** 27968cfa0ad2SJack F Vogel * e1000_disable_gig_wol_ich8lan - disable gig during WoL 27978cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 27988cfa0ad2SJack F Vogel * 27998cfa0ad2SJack F Vogel * During S0 to Sx transition, it is possible the link remains at gig 28008cfa0ad2SJack F Vogel * instead of negotiating to a lower speed. Before going to Sx, set 28018cfa0ad2SJack F Vogel * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation 28028cfa0ad2SJack F Vogel * to a lower speed. 28038cfa0ad2SJack F Vogel * 2804d035aa2dSJack F Vogel * Should only be called for applicable parts. 28058cfa0ad2SJack F Vogel **/ 28068cfa0ad2SJack F Vogel void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) 28078cfa0ad2SJack F Vogel { 28088cfa0ad2SJack F Vogel u32 phy_ctrl; 28098cfa0ad2SJack F Vogel 2810d035aa2dSJack F Vogel switch (hw->mac.type) { 2811d035aa2dSJack F Vogel case e1000_ich9lan: 2812d035aa2dSJack F Vogel case e1000_ich10lan: 28139d81738fSJack F Vogel case e1000_pchlan: 28148cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 28158cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | 28168cfa0ad2SJack F Vogel E1000_PHY_CTRL_GBE_DISABLE; 28178cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 28189d81738fSJack F Vogel 28199d81738fSJack F Vogel /* Workaround SWFLAG unexpectedly set during S0->Sx */ 28209d81738fSJack F Vogel if (hw->mac.type == e1000_pchlan) 28219d81738fSJack F Vogel usec_delay(500); 2822d035aa2dSJack F Vogel default: 2823d035aa2dSJack F Vogel break; 28248cfa0ad2SJack F Vogel } 28258cfa0ad2SJack F Vogel 28268cfa0ad2SJack F Vogel return; 28278cfa0ad2SJack F Vogel } 28288cfa0ad2SJack F Vogel 28298cfa0ad2SJack F Vogel /** 28308cfa0ad2SJack F Vogel * e1000_cleanup_led_ich8lan - Restore the default LED operation 28318cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 28328cfa0ad2SJack F Vogel * 28338cfa0ad2SJack F Vogel * Return the LED back to the default configuration. 28348cfa0ad2SJack F Vogel **/ 28358cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) 28368cfa0ad2SJack F Vogel { 28378cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 28388cfa0ad2SJack F Vogel 28398cfa0ad2SJack F Vogel DEBUGFUNC("e1000_cleanup_led_ich8lan"); 28408cfa0ad2SJack F Vogel 28418cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 2842daf9197cSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 28438cfa0ad2SJack F Vogel 0); 28448cfa0ad2SJack F Vogel else 28458cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); 28468cfa0ad2SJack F Vogel 28478cfa0ad2SJack F Vogel return ret_val; 28488cfa0ad2SJack F Vogel } 28498cfa0ad2SJack F Vogel 28508cfa0ad2SJack F Vogel /** 28518cfa0ad2SJack F Vogel * e1000_led_on_ich8lan - Turn LEDs on 28528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 28538cfa0ad2SJack F Vogel * 28548cfa0ad2SJack F Vogel * Turn on the LEDs. 28558cfa0ad2SJack F Vogel **/ 28568cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) 28578cfa0ad2SJack F Vogel { 28588cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 28598cfa0ad2SJack F Vogel 28608cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_on_ich8lan"); 28618cfa0ad2SJack F Vogel 28628cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 2863daf9197cSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 28648cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); 28658cfa0ad2SJack F Vogel else 28668cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); 28678cfa0ad2SJack F Vogel 28688cfa0ad2SJack F Vogel return ret_val; 28698cfa0ad2SJack F Vogel } 28708cfa0ad2SJack F Vogel 28718cfa0ad2SJack F Vogel /** 28728cfa0ad2SJack F Vogel * e1000_led_off_ich8lan - Turn LEDs off 28738cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 28748cfa0ad2SJack F Vogel * 28758cfa0ad2SJack F Vogel * Turn off the LEDs. 28768cfa0ad2SJack F Vogel **/ 28778cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) 28788cfa0ad2SJack F Vogel { 28798cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 28808cfa0ad2SJack F Vogel 28818cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_off_ich8lan"); 28828cfa0ad2SJack F Vogel 28838cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 28848cfa0ad2SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, 28858cfa0ad2SJack F Vogel IFE_PHY_SPECIAL_CONTROL_LED, 28868cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); 28878cfa0ad2SJack F Vogel else 28888cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); 28898cfa0ad2SJack F Vogel 28908cfa0ad2SJack F Vogel return ret_val; 28918cfa0ad2SJack F Vogel } 28928cfa0ad2SJack F Vogel 28938cfa0ad2SJack F Vogel /** 28949d81738fSJack F Vogel * e1000_setup_led_pchlan - Configures SW controllable LED 28959d81738fSJack F Vogel * @hw: pointer to the HW structure 28969d81738fSJack F Vogel * 28979d81738fSJack F Vogel * This prepares the SW controllable LED for use. 28989d81738fSJack F Vogel **/ 28999d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) 29009d81738fSJack F Vogel { 29019d81738fSJack F Vogel DEBUGFUNC("e1000_setup_led_pchlan"); 29029d81738fSJack F Vogel 29039d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 29049d81738fSJack F Vogel (u16)hw->mac.ledctl_mode1); 29059d81738fSJack F Vogel } 29069d81738fSJack F Vogel 29079d81738fSJack F Vogel /** 29089d81738fSJack F Vogel * e1000_cleanup_led_pchlan - Restore the default LED operation 29099d81738fSJack F Vogel * @hw: pointer to the HW structure 29109d81738fSJack F Vogel * 29119d81738fSJack F Vogel * Return the LED back to the default configuration. 29129d81738fSJack F Vogel **/ 29139d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) 29149d81738fSJack F Vogel { 29159d81738fSJack F Vogel DEBUGFUNC("e1000_cleanup_led_pchlan"); 29169d81738fSJack F Vogel 29179d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 29189d81738fSJack F Vogel (u16)hw->mac.ledctl_default); 29199d81738fSJack F Vogel } 29209d81738fSJack F Vogel 29219d81738fSJack F Vogel /** 29229d81738fSJack F Vogel * e1000_led_on_pchlan - Turn LEDs on 29239d81738fSJack F Vogel * @hw: pointer to the HW structure 29249d81738fSJack F Vogel * 29259d81738fSJack F Vogel * Turn on the LEDs. 29269d81738fSJack F Vogel **/ 29279d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw) 29289d81738fSJack F Vogel { 29299d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode2; 29309d81738fSJack F Vogel u32 i, led; 29319d81738fSJack F Vogel 29329d81738fSJack F Vogel DEBUGFUNC("e1000_led_on_pchlan"); 29339d81738fSJack F Vogel 29349d81738fSJack F Vogel /* 29359d81738fSJack F Vogel * If no link, then turn LED on by setting the invert bit 29369d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode2. 29379d81738fSJack F Vogel */ 29389d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 29399d81738fSJack F Vogel for (i = 0; i < 3; i++) { 29409d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 29419d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 29429d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 29439d81738fSJack F Vogel continue; 29449d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 29459d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 29469d81738fSJack F Vogel else 29479d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 29489d81738fSJack F Vogel } 29499d81738fSJack F Vogel } 29509d81738fSJack F Vogel 29519d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 29529d81738fSJack F Vogel } 29539d81738fSJack F Vogel 29549d81738fSJack F Vogel /** 29559d81738fSJack F Vogel * e1000_led_off_pchlan - Turn LEDs off 29569d81738fSJack F Vogel * @hw: pointer to the HW structure 29579d81738fSJack F Vogel * 29589d81738fSJack F Vogel * Turn off the LEDs. 29599d81738fSJack F Vogel **/ 29609d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw) 29619d81738fSJack F Vogel { 29629d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode1; 29639d81738fSJack F Vogel u32 i, led; 29649d81738fSJack F Vogel 29659d81738fSJack F Vogel DEBUGFUNC("e1000_led_off_pchlan"); 29669d81738fSJack F Vogel 29679d81738fSJack F Vogel /* 29689d81738fSJack F Vogel * If no link, then turn LED off by clearing the invert bit 29699d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode1. 29709d81738fSJack F Vogel */ 29719d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 29729d81738fSJack F Vogel for (i = 0; i < 3; i++) { 29739d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 29749d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 29759d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 29769d81738fSJack F Vogel continue; 29779d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 29789d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 29799d81738fSJack F Vogel else 29809d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 29819d81738fSJack F Vogel } 29829d81738fSJack F Vogel } 29839d81738fSJack F Vogel 29849d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 29859d81738fSJack F Vogel } 29869d81738fSJack F Vogel 29879d81738fSJack F Vogel /** 29888cfa0ad2SJack F Vogel * e1000_get_cfg_done_ich8lan - Read config done bit 29898cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 29908cfa0ad2SJack F Vogel * 29918cfa0ad2SJack F Vogel * Read the management control register for the config done bit for 29928cfa0ad2SJack F Vogel * completion status. NOTE: silicon which is EEPROM-less will fail trying 29938cfa0ad2SJack F Vogel * to read the config done bit, so an error is *ONLY* logged and returns 29948cfa0ad2SJack F Vogel * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon 29958cfa0ad2SJack F Vogel * would not be able to be reset or change link. 29968cfa0ad2SJack F Vogel **/ 29978cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) 29988cfa0ad2SJack F Vogel { 29998cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 30008cfa0ad2SJack F Vogel u32 bank = 0; 30018cfa0ad2SJack F Vogel 30029d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan) { 30039d81738fSJack F Vogel u32 status = E1000_READ_REG(hw, E1000_STATUS); 30049d81738fSJack F Vogel 30059d81738fSJack F Vogel if (status & E1000_STATUS_PHYRA) { 30069d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, status & 30079d81738fSJack F Vogel ~E1000_STATUS_PHYRA); 30089d81738fSJack F Vogel } else 30099d81738fSJack F Vogel DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); 30109d81738fSJack F Vogel } 30119d81738fSJack F Vogel 30128cfa0ad2SJack F Vogel e1000_get_cfg_done_generic(hw); 30138cfa0ad2SJack F Vogel 30148cfa0ad2SJack F Vogel /* If EEPROM is not marked present, init the IGP 3 PHY manually */ 30159d81738fSJack F Vogel if ((hw->mac.type != e1000_ich10lan) && 30169d81738fSJack F Vogel (hw->mac.type != e1000_pchlan)) { 30178cfa0ad2SJack F Vogel if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && 30188cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3)) { 30198cfa0ad2SJack F Vogel e1000_phy_init_script_igp3(hw); 30208cfa0ad2SJack F Vogel } 30218cfa0ad2SJack F Vogel } else { 30228cfa0ad2SJack F Vogel if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { 3023daf9197cSJack F Vogel /* Maybe we should do a basic PHY config */ 30248cfa0ad2SJack F Vogel DEBUGOUT("EEPROM not present\n"); 30258cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 30268cfa0ad2SJack F Vogel } 30278cfa0ad2SJack F Vogel } 30288cfa0ad2SJack F Vogel 30298cfa0ad2SJack F Vogel return ret_val; 30308cfa0ad2SJack F Vogel } 30318cfa0ad2SJack F Vogel 30328cfa0ad2SJack F Vogel /** 30338cfa0ad2SJack F Vogel * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down 30348cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 30358cfa0ad2SJack F Vogel * 30368cfa0ad2SJack F Vogel * In the case of a PHY power down to save power, or to turn off link during a 30378cfa0ad2SJack F Vogel * driver unload, or wake on lan is not enabled, remove the link. 30388cfa0ad2SJack F Vogel **/ 30398cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) 30408cfa0ad2SJack F Vogel { 30418cfa0ad2SJack F Vogel /* If the management interface is not enabled, then power down */ 3042daf9197cSJack F Vogel if (!(hw->mac.ops.check_mng_mode(hw) || 3043daf9197cSJack F Vogel hw->phy.ops.check_reset_block(hw))) 30448cfa0ad2SJack F Vogel e1000_power_down_phy_copper(hw); 30458cfa0ad2SJack F Vogel 30468cfa0ad2SJack F Vogel return; 30478cfa0ad2SJack F Vogel } 30488cfa0ad2SJack F Vogel 30498cfa0ad2SJack F Vogel /** 30508cfa0ad2SJack F Vogel * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters 30518cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 30528cfa0ad2SJack F Vogel * 30538cfa0ad2SJack F Vogel * Clears hardware counters specific to the silicon family and calls 30548cfa0ad2SJack F Vogel * clear_hw_cntrs_generic to clear all general purpose counters. 30558cfa0ad2SJack F Vogel **/ 30568cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) 30578cfa0ad2SJack F Vogel { 30589d81738fSJack F Vogel u16 phy_data; 30599d81738fSJack F Vogel 30608cfa0ad2SJack F Vogel DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); 30618cfa0ad2SJack F Vogel 30628cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_base_generic(hw); 30638cfa0ad2SJack F Vogel 3064daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ALGNERRC); 3065daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_RXERRC); 3066daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TNCRS); 3067daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_CEXTERR); 3068daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTC); 3069daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTFC); 30708cfa0ad2SJack F Vogel 3071daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPRC); 3072daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPDC); 3073daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPTC); 30748cfa0ad2SJack F Vogel 3075daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_IAC); 3076daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ICRXOC); 30779d81738fSJack F Vogel 30789d81738fSJack F Vogel /* Clear PHY statistics registers */ 30799d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 30809d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 30819d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data); 30829d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data); 30839d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data); 30849d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data); 30859d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data); 30869d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data); 30879d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data); 30889d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data); 30899d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data); 30909d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data); 30919d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data); 30929d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data); 30939d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data); 30949d81738fSJack F Vogel hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data); 30959d81738fSJack F Vogel } 30968cfa0ad2SJack F Vogel } 30978cfa0ad2SJack F Vogel 3098