18cfa0ad2SJack F Vogel /****************************************************************************** 28cfa0ad2SJack F Vogel 37c669ab6SSean Bruno Copyright (c) 2001-2015, 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 356ab6bfe3SJack F Vogel /* 82562G 10/100 Network Connection 36daf9197cSJack F Vogel * 82562G-2 10/100 Network Connection 37daf9197cSJack F Vogel * 82562GT 10/100 Network Connection 38daf9197cSJack F Vogel * 82562GT-2 10/100 Network Connection 39daf9197cSJack F Vogel * 82562V 10/100 Network Connection 40daf9197cSJack F Vogel * 82562V-2 10/100 Network Connection 41daf9197cSJack F Vogel * 82566DC-2 Gigabit Network Connection 42daf9197cSJack F Vogel * 82566DC Gigabit Network Connection 43daf9197cSJack F Vogel * 82566DM-2 Gigabit Network Connection 44daf9197cSJack F Vogel * 82566DM Gigabit Network Connection 45daf9197cSJack F Vogel * 82566MC Gigabit Network Connection 46daf9197cSJack F Vogel * 82566MM Gigabit Network Connection 47daf9197cSJack F Vogel * 82567LM Gigabit Network Connection 48daf9197cSJack F Vogel * 82567LF Gigabit Network Connection 49daf9197cSJack F Vogel * 82567V Gigabit Network Connection 50daf9197cSJack F Vogel * 82567LM-2 Gigabit Network Connection 51daf9197cSJack F Vogel * 82567LF-2 Gigabit Network Connection 52daf9197cSJack F Vogel * 82567V-2 Gigabit Network Connection 53daf9197cSJack F Vogel * 82567LF-3 Gigabit Network Connection 54daf9197cSJack F Vogel * 82567LM-3 Gigabit Network Connection 55daf9197cSJack F Vogel * 82567LM-4 Gigabit Network Connection 569d81738fSJack F Vogel * 82577LM Gigabit Network Connection 579d81738fSJack F Vogel * 82577LC Gigabit Network Connection 589d81738fSJack F Vogel * 82578DM Gigabit Network Connection 599d81738fSJack F Vogel * 82578DC Gigabit Network Connection 607d9119bdSJack F Vogel * 82579LM Gigabit Network Connection 617d9119bdSJack F Vogel * 82579V Gigabit Network Connection 627609433eSJack F Vogel * Ethernet Connection I217-LM 637609433eSJack F Vogel * Ethernet Connection I217-V 647609433eSJack F Vogel * Ethernet Connection I218-V 657609433eSJack F Vogel * Ethernet Connection I218-LM 668cc64f1eSJack F Vogel * Ethernet Connection (2) I218-LM 678cc64f1eSJack F Vogel * Ethernet Connection (2) I218-V 688cc64f1eSJack F Vogel * Ethernet Connection (3) I218-LM 698cc64f1eSJack F Vogel * Ethernet Connection (3) I218-V 708cfa0ad2SJack F Vogel */ 718cfa0ad2SJack F Vogel 728cfa0ad2SJack F Vogel #include "e1000_api.h" 738cfa0ad2SJack F Vogel 748cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); 758cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); 764edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); 774edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw); 788cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); 797d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw); 808cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); 818cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index); 827609433eSJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw); 83730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw, 84730d3130SJack F Vogel u8 *mc_addr_list, 85730d3130SJack F Vogel u32 mc_addr_count); 868cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); 878cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); 884edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); 898cfa0ad2SJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, 908cfa0ad2SJack F Vogel bool active); 918cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, 928cfa0ad2SJack F Vogel bool active); 938cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 948cfa0ad2SJack F Vogel u16 words, u16 *data); 95*c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words, 96*c80429ceSEric Joyner u16 *data); 978cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 988cfa0ad2SJack F Vogel u16 words, u16 *data); 998cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); 1008cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); 101*c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw); 1028cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, 1038cfa0ad2SJack F Vogel u16 *data); 1049d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); 1058cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); 1068cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); 1078cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); 1088cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); 1098cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); 1106ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw); 1118cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, 1128cfa0ad2SJack F Vogel u16 *speed, u16 *duplex); 1138cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); 1148cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); 1158cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); 1164edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); 1179d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); 1189d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); 1199d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw); 1209d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw); 1218cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); 1228cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); 1238cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); 1248cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); 1258cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, 1268cfa0ad2SJack F Vogel u32 offset, u8 *data); 1278cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1288cfa0ad2SJack F Vogel u8 size, u16 *data); 129*c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 130*c80429ceSEric Joyner u32 *data); 131*c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, 132*c80429ceSEric Joyner u32 offset, u32 *data); 133*c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, 134*c80429ceSEric Joyner u32 offset, u32 data); 135*c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw, 136*c80429ceSEric Joyner u32 offset, u32 dword); 1378cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, 1388cfa0ad2SJack F Vogel u32 offset, u16 *data); 1398cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 1408cfa0ad2SJack F Vogel u32 offset, u8 byte); 1418cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); 1428cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); 1434edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); 144a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); 1457d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); 1467d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); 147e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr); 1488cfa0ad2SJack F Vogel 1498cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ 1508cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */ 1518cfa0ad2SJack F Vogel union ich8_hws_flash_status { 1528cfa0ad2SJack F Vogel struct ich8_hsfsts { 1538cfa0ad2SJack F Vogel u16 flcdone:1; /* bit 0 Flash Cycle Done */ 1548cfa0ad2SJack F Vogel u16 flcerr:1; /* bit 1 Flash Cycle Error */ 1558cfa0ad2SJack F Vogel u16 dael:1; /* bit 2 Direct Access error Log */ 1568cfa0ad2SJack F Vogel u16 berasesz:2; /* bit 4:3 Sector Erase Size */ 1578cfa0ad2SJack F Vogel u16 flcinprog:1; /* bit 5 flash cycle in Progress */ 1588cfa0ad2SJack F Vogel u16 reserved1:2; /* bit 13:6 Reserved */ 1598cfa0ad2SJack F Vogel u16 reserved2:6; /* bit 13:6 Reserved */ 1608cfa0ad2SJack F Vogel u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */ 1618cfa0ad2SJack F Vogel u16 flockdn:1; /* bit 15 Flash Config Lock-Down */ 1628cfa0ad2SJack F Vogel } hsf_status; 1638cfa0ad2SJack F Vogel u16 regval; 1648cfa0ad2SJack F Vogel }; 1658cfa0ad2SJack F Vogel 1668cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ 1678cfa0ad2SJack F Vogel /* Offset 06h FLCTL */ 1688cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl { 1698cfa0ad2SJack F Vogel struct ich8_hsflctl { 1708cfa0ad2SJack F Vogel u16 flcgo:1; /* 0 Flash Cycle Go */ 1718cfa0ad2SJack F Vogel u16 flcycle:2; /* 2:1 Flash Cycle */ 1728cfa0ad2SJack F Vogel u16 reserved:5; /* 7:3 Reserved */ 1738cfa0ad2SJack F Vogel u16 fldbcount:2; /* 9:8 Flash Data Byte Count */ 1748cfa0ad2SJack F Vogel u16 flockdn:6; /* 15:10 Reserved */ 1758cfa0ad2SJack F Vogel } hsf_ctrl; 1768cfa0ad2SJack F Vogel u16 regval; 1778cfa0ad2SJack F Vogel }; 1788cfa0ad2SJack F Vogel 1798cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */ 1808cfa0ad2SJack F Vogel union ich8_hws_flash_regacc { 1818cfa0ad2SJack F Vogel struct ich8_flracc { 1828cfa0ad2SJack F Vogel u32 grra:8; /* 0:7 GbE region Read Access */ 1838cfa0ad2SJack F Vogel u32 grwa:8; /* 8:15 GbE region Write Access */ 1848cfa0ad2SJack F Vogel u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */ 1858cfa0ad2SJack F Vogel u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */ 1868cfa0ad2SJack F Vogel } hsf_flregacc; 1878cfa0ad2SJack F Vogel u16 regval; 1888cfa0ad2SJack F Vogel }; 1898cfa0ad2SJack F Vogel 1906ab6bfe3SJack F Vogel /** 1916ab6bfe3SJack F Vogel * e1000_phy_is_accessible_pchlan - Check if able to access PHY registers 1926ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 1936ab6bfe3SJack F Vogel * 1946ab6bfe3SJack F Vogel * Test access to the PHY registers by reading the PHY ID registers. If 1956ab6bfe3SJack F Vogel * the PHY ID is already known (e.g. resume path) compare it with known ID, 1966ab6bfe3SJack F Vogel * otherwise assume the read PHY ID is correct if it is valid. 1976ab6bfe3SJack F Vogel * 1986ab6bfe3SJack F Vogel * Assumes the sw/fw/hw semaphore is already acquired. 1996ab6bfe3SJack F Vogel **/ 2006ab6bfe3SJack F Vogel static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) 2014dab5c37SJack F Vogel { 2026ab6bfe3SJack F Vogel u16 phy_reg = 0; 2036ab6bfe3SJack F Vogel u32 phy_id = 0; 2047609433eSJack F Vogel s32 ret_val = 0; 2056ab6bfe3SJack F Vogel u16 retry_count; 2067609433eSJack F Vogel u32 mac_reg = 0; 2074dab5c37SJack F Vogel 2086ab6bfe3SJack F Vogel for (retry_count = 0; retry_count < 2; retry_count++) { 2096ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg); 2106ab6bfe3SJack F Vogel if (ret_val || (phy_reg == 0xFFFF)) 2116ab6bfe3SJack F Vogel continue; 2126ab6bfe3SJack F Vogel phy_id = (u32)(phy_reg << 16); 2134dab5c37SJack F Vogel 2146ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg); 2156ab6bfe3SJack F Vogel if (ret_val || (phy_reg == 0xFFFF)) { 2166ab6bfe3SJack F Vogel phy_id = 0; 2176ab6bfe3SJack F Vogel continue; 2186ab6bfe3SJack F Vogel } 2196ab6bfe3SJack F Vogel phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); 2206ab6bfe3SJack F Vogel break; 2216ab6bfe3SJack F Vogel } 2226ab6bfe3SJack F Vogel 2236ab6bfe3SJack F Vogel if (hw->phy.id) { 2246ab6bfe3SJack F Vogel if (hw->phy.id == phy_id) 2257609433eSJack F Vogel goto out; 2266ab6bfe3SJack F Vogel } else if (phy_id) { 2276ab6bfe3SJack F Vogel hw->phy.id = phy_id; 2286ab6bfe3SJack F Vogel hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK); 2297609433eSJack F Vogel goto out; 2306ab6bfe3SJack F Vogel } 2316ab6bfe3SJack F Vogel 2326ab6bfe3SJack F Vogel /* In case the PHY needs to be in mdio slow mode, 2336ab6bfe3SJack F Vogel * set slow mode and try to get the PHY id again. 2346ab6bfe3SJack F Vogel */ 2357609433eSJack F Vogel if (hw->mac.type < e1000_pch_lpt) { 2366ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 2376ab6bfe3SJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 2386ab6bfe3SJack F Vogel if (!ret_val) 2396ab6bfe3SJack F Vogel ret_val = e1000_get_phy_id(hw); 2406ab6bfe3SJack F Vogel hw->phy.ops.acquire(hw); 2417609433eSJack F Vogel } 2426ab6bfe3SJack F Vogel 2437609433eSJack F Vogel if (ret_val) 2447609433eSJack F Vogel return FALSE; 2457609433eSJack F Vogel out: 246*c80429ceSEric Joyner if ((hw->mac.type == e1000_pch_lpt) || 247*c80429ceSEric Joyner (hw->mac.type == e1000_pch_spt)) { 248*c80429ceSEric Joyner /* Only unforce SMBus if ME is not active */ 249*c80429ceSEric Joyner if (!(E1000_READ_REG(hw, E1000_FWSM) & 250*c80429ceSEric Joyner E1000_ICH_FWSM_FW_VALID)) { 2517609433eSJack F Vogel /* Unforce SMBus mode in PHY */ 2527609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg); 2537609433eSJack F Vogel phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; 2547609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg); 2557609433eSJack F Vogel 2567609433eSJack F Vogel /* Unforce SMBus mode in MAC */ 2577609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 2587609433eSJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 2597609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 2607609433eSJack F Vogel } 261*c80429ceSEric Joyner } 2627609433eSJack F Vogel 2637609433eSJack F Vogel return TRUE; 2647609433eSJack F Vogel } 2657609433eSJack F Vogel 2667609433eSJack F Vogel /** 2677609433eSJack F Vogel * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value 2687609433eSJack F Vogel * @hw: pointer to the HW structure 2697609433eSJack F Vogel * 2707609433eSJack F Vogel * Toggling the LANPHYPC pin value fully power-cycles the PHY and is 2717609433eSJack F Vogel * used to reset the PHY to a quiescent state when necessary. 2727609433eSJack F Vogel **/ 2738cc64f1eSJack F Vogel static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) 2747609433eSJack F Vogel { 2757609433eSJack F Vogel u32 mac_reg; 2767609433eSJack F Vogel 2777609433eSJack F Vogel DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt"); 2787609433eSJack F Vogel 2797609433eSJack F Vogel /* Set Phy Config Counter to 50msec */ 2807609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3); 2817609433eSJack F Vogel mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; 2827609433eSJack F Vogel mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; 2837609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg); 2847609433eSJack F Vogel 2857609433eSJack F Vogel /* Toggle LANPHYPC Value bit */ 2867609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL); 2877609433eSJack F Vogel mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; 2887609433eSJack F Vogel mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; 2897609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, mac_reg); 2907609433eSJack F Vogel E1000_WRITE_FLUSH(hw); 2917609433eSJack F Vogel usec_delay(10); 2927609433eSJack F Vogel mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; 2937609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, mac_reg); 2947609433eSJack F Vogel E1000_WRITE_FLUSH(hw); 2957609433eSJack F Vogel 2967609433eSJack F Vogel if (hw->mac.type < e1000_pch_lpt) { 2977609433eSJack F Vogel msec_delay(50); 2987609433eSJack F Vogel } else { 2997609433eSJack F Vogel u16 count = 20; 3007609433eSJack F Vogel 3017609433eSJack F Vogel do { 3027609433eSJack F Vogel msec_delay(5); 3037609433eSJack F Vogel } while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) & 3047609433eSJack F Vogel E1000_CTRL_EXT_LPCD) && count--); 3057609433eSJack F Vogel 3067609433eSJack F Vogel msec_delay(30); 3077609433eSJack F Vogel } 3086ab6bfe3SJack F Vogel } 3096ab6bfe3SJack F Vogel 3106ab6bfe3SJack F Vogel /** 3116ab6bfe3SJack F Vogel * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds 3126ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 3136ab6bfe3SJack F Vogel * 3146ab6bfe3SJack F Vogel * Workarounds/flow necessary for PHY initialization during driver load 3156ab6bfe3SJack F Vogel * and resume paths. 3166ab6bfe3SJack F Vogel **/ 3176ab6bfe3SJack F Vogel static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) 3186ab6bfe3SJack F Vogel { 3196ab6bfe3SJack F Vogel u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM); 3206ab6bfe3SJack F Vogel s32 ret_val; 3216ab6bfe3SJack F Vogel 3226ab6bfe3SJack F Vogel DEBUGFUNC("e1000_init_phy_workarounds_pchlan"); 3236ab6bfe3SJack F Vogel 3246ab6bfe3SJack F Vogel /* Gate automatic PHY configuration by hardware on managed and 3256ab6bfe3SJack F Vogel * non-managed 82579 and newer adapters. 3266ab6bfe3SJack F Vogel */ 3276ab6bfe3SJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 3286ab6bfe3SJack F Vogel 3298cc64f1eSJack F Vogel /* It is not possible to be certain of the current state of ULP 3308cc64f1eSJack F Vogel * so forcibly disable it. 3318cc64f1eSJack F Vogel */ 3328cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown; 3338cc64f1eSJack F Vogel e1000_disable_ulp_lpt_lp(hw, TRUE); 3348cc64f1eSJack F Vogel 3356ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 3366ab6bfe3SJack F Vogel if (ret_val) { 3376ab6bfe3SJack F Vogel DEBUGOUT("Failed to initialize PHY flow\n"); 3386ab6bfe3SJack F Vogel goto out; 3396ab6bfe3SJack F Vogel } 3406ab6bfe3SJack F Vogel 3416ab6bfe3SJack F Vogel /* The MAC-PHY interconnect may be in SMBus mode. If the PHY is 3426ab6bfe3SJack F Vogel * inaccessible and resetting the PHY is not blocked, toggle the 3436ab6bfe3SJack F Vogel * LANPHYPC Value bit to force the interconnect to PCIe mode. 3446ab6bfe3SJack F Vogel */ 3456ab6bfe3SJack F Vogel switch (hw->mac.type) { 3466ab6bfe3SJack F Vogel case e1000_pch_lpt: 347*c80429ceSEric Joyner case e1000_pch_spt: 3486ab6bfe3SJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3496ab6bfe3SJack F Vogel break; 3506ab6bfe3SJack F Vogel 3516ab6bfe3SJack F Vogel /* Before toggling LANPHYPC, see if PHY is accessible by 3526ab6bfe3SJack F Vogel * forcing MAC to SMBus mode first. 3536ab6bfe3SJack F Vogel */ 3546ab6bfe3SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 3556ab6bfe3SJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 3566ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 3576ab6bfe3SJack F Vogel 3587609433eSJack F Vogel /* Wait 50 milliseconds for MAC to finish any retries 3597609433eSJack F Vogel * that it might be trying to perform from previous 3607609433eSJack F Vogel * attempts to acknowledge any phy read requests. 3617609433eSJack F Vogel */ 3627609433eSJack F Vogel msec_delay(50); 3637609433eSJack F Vogel 3646ab6bfe3SJack F Vogel /* fall-through */ 3656ab6bfe3SJack F Vogel case e1000_pch2lan: 3667609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3676ab6bfe3SJack F Vogel break; 3686ab6bfe3SJack F Vogel 3696ab6bfe3SJack F Vogel /* fall-through */ 3706ab6bfe3SJack F Vogel case e1000_pchlan: 3716ab6bfe3SJack F Vogel if ((hw->mac.type == e1000_pchlan) && 3726ab6bfe3SJack F Vogel (fwsm & E1000_ICH_FWSM_FW_VALID)) 3736ab6bfe3SJack F Vogel break; 3746ab6bfe3SJack F Vogel 3756ab6bfe3SJack F Vogel if (hw->phy.ops.check_reset_block(hw)) { 3766ab6bfe3SJack F Vogel DEBUGOUT("Required LANPHYPC toggle blocked by ME\n"); 3777609433eSJack F Vogel ret_val = -E1000_ERR_PHY; 3786ab6bfe3SJack F Vogel break; 3796ab6bfe3SJack F Vogel } 3806ab6bfe3SJack F Vogel 3817609433eSJack F Vogel /* Toggle LANPHYPC Value bit */ 3827609433eSJack F Vogel e1000_toggle_lanphypc_pch_lpt(hw); 3837609433eSJack F Vogel if (hw->mac.type >= e1000_pch_lpt) { 3847609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3857609433eSJack F Vogel break; 3866ab6bfe3SJack F Vogel 3876ab6bfe3SJack F Vogel /* Toggling LANPHYPC brings the PHY out of SMBus mode 3887609433eSJack F Vogel * so ensure that the MAC is also out of SMBus mode 3896ab6bfe3SJack F Vogel */ 3906ab6bfe3SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 3916ab6bfe3SJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 3926ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 3936ab6bfe3SJack F Vogel 3947609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3957609433eSJack F Vogel break; 3967609433eSJack F Vogel 3977609433eSJack F Vogel ret_val = -E1000_ERR_PHY; 3986ab6bfe3SJack F Vogel } 3996ab6bfe3SJack F Vogel break; 4006ab6bfe3SJack F Vogel default: 4016ab6bfe3SJack F Vogel break; 4026ab6bfe3SJack F Vogel } 4036ab6bfe3SJack F Vogel 4046ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 4057609433eSJack F Vogel if (!ret_val) { 4067609433eSJack F Vogel 4077609433eSJack F Vogel /* Check to see if able to reset PHY. Print error if not */ 4087609433eSJack F Vogel if (hw->phy.ops.check_reset_block(hw)) { 4097609433eSJack F Vogel ERROR_REPORT("Reset blocked by ME\n"); 4107609433eSJack F Vogel goto out; 4117609433eSJack F Vogel } 4126ab6bfe3SJack F Vogel 4136ab6bfe3SJack F Vogel /* Reset the PHY before any access to it. Doing so, ensures 4146ab6bfe3SJack F Vogel * that the PHY is in a known good state before we read/write 4156ab6bfe3SJack F Vogel * PHY registers. The generic reset is sufficient here, 4166ab6bfe3SJack F Vogel * because we haven't determined the PHY type yet. 4176ab6bfe3SJack F Vogel */ 4186ab6bfe3SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 4197609433eSJack F Vogel if (ret_val) 4207609433eSJack F Vogel goto out; 4217609433eSJack F Vogel 4227609433eSJack F Vogel /* On a successful reset, possibly need to wait for the PHY 4237609433eSJack F Vogel * to quiesce to an accessible state before returning control 4247609433eSJack F Vogel * to the calling function. If the PHY does not quiesce, then 4257609433eSJack F Vogel * return E1000E_BLK_PHY_RESET, as this is the condition that 4267609433eSJack F Vogel * the PHY is in. 4277609433eSJack F Vogel */ 4287609433eSJack F Vogel ret_val = hw->phy.ops.check_reset_block(hw); 4297609433eSJack F Vogel if (ret_val) 4307609433eSJack F Vogel ERROR_REPORT("ME blocked access to PHY after reset\n"); 4317609433eSJack F Vogel } 4326ab6bfe3SJack F Vogel 4336ab6bfe3SJack F Vogel out: 4346ab6bfe3SJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */ 4356ab6bfe3SJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 4366ab6bfe3SJack F Vogel !(fwsm & E1000_ICH_FWSM_FW_VALID)) { 4376ab6bfe3SJack F Vogel msec_delay(10); 4386ab6bfe3SJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, FALSE); 4396ab6bfe3SJack F Vogel } 4406ab6bfe3SJack F Vogel 4416ab6bfe3SJack F Vogel return ret_val; 4424dab5c37SJack F Vogel } 4434dab5c37SJack F Vogel 4448cfa0ad2SJack F Vogel /** 4459d81738fSJack F Vogel * e1000_init_phy_params_pchlan - Initialize PHY function pointers 4469d81738fSJack F Vogel * @hw: pointer to the HW structure 4479d81738fSJack F Vogel * 4489d81738fSJack F Vogel * Initialize family-specific PHY parameters and function pointers. 4499d81738fSJack F Vogel **/ 4509d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 4519d81738fSJack F Vogel { 4529d81738fSJack F Vogel struct e1000_phy_info *phy = &hw->phy; 4536ab6bfe3SJack F Vogel s32 ret_val; 4549d81738fSJack F Vogel 4559d81738fSJack F Vogel DEBUGFUNC("e1000_init_phy_params_pchlan"); 4569d81738fSJack F Vogel 4579d81738fSJack F Vogel phy->addr = 1; 4589d81738fSJack F Vogel phy->reset_delay_us = 100; 4599d81738fSJack F Vogel 4609d81738fSJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 4619d81738fSJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 4629d81738fSJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 4634dab5c37SJack F Vogel phy->ops.set_page = e1000_set_page_igp; 4649d81738fSJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_hv; 4654edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; 4664dab5c37SJack F Vogel phy->ops.read_reg_page = e1000_read_phy_reg_page_hv; 4679d81738fSJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 4689d81738fSJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 4694edd8523SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; 4704edd8523SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; 4719d81738fSJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_hv; 4724edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; 4734dab5c37SJack F Vogel phy->ops.write_reg_page = e1000_write_phy_reg_page_hv; 4749d81738fSJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 4759d81738fSJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 4769d81738fSJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 4779d81738fSJack F Vogel 4789d81738fSJack F Vogel phy->id = e1000_phy_unknown; 4796ab6bfe3SJack F Vogel 4806ab6bfe3SJack F Vogel ret_val = e1000_init_phy_workarounds_pchlan(hw); 4816ab6bfe3SJack F Vogel if (ret_val) 4826ab6bfe3SJack F Vogel return ret_val; 4836ab6bfe3SJack F Vogel 4846ab6bfe3SJack F Vogel if (phy->id == e1000_phy_unknown) 4857d9119bdSJack F Vogel switch (hw->mac.type) { 4867d9119bdSJack F Vogel default: 487a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw); 488a69ed8dfSJack F Vogel if (ret_val) 4896ab6bfe3SJack F Vogel return ret_val; 4907d9119bdSJack F Vogel if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) 4917d9119bdSJack F Vogel break; 4927d9119bdSJack F Vogel /* fall-through */ 4937d9119bdSJack F Vogel case e1000_pch2lan: 4946ab6bfe3SJack F Vogel case e1000_pch_lpt: 495*c80429ceSEric Joyner case e1000_pch_spt: 4966ab6bfe3SJack F Vogel /* In case the PHY needs to be in mdio slow mode, 497a69ed8dfSJack F Vogel * set slow mode and try to get the PHY id again. 498a69ed8dfSJack F Vogel */ 499a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 500a69ed8dfSJack F Vogel if (ret_val) 5016ab6bfe3SJack F Vogel return ret_val; 502a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw); 503a69ed8dfSJack F Vogel if (ret_val) 5046ab6bfe3SJack F Vogel return ret_val; 5057d9119bdSJack F Vogel break; 506a69ed8dfSJack F Vogel } 5079d81738fSJack F Vogel phy->type = e1000_get_phy_type_from_id(phy->id); 5089d81738fSJack F Vogel 5094edd8523SJack F Vogel switch (phy->type) { 5104edd8523SJack F Vogel case e1000_phy_82577: 5117d9119bdSJack F Vogel case e1000_phy_82579: 5126ab6bfe3SJack F Vogel case e1000_phy_i217: 5139d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_82577; 5149d81738fSJack F Vogel phy->ops.force_speed_duplex = 5159d81738fSJack F Vogel e1000_phy_force_speed_duplex_82577; 5169d81738fSJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_82577; 5179d81738fSJack F Vogel phy->ops.get_info = e1000_get_phy_info_82577; 5189d81738fSJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 5198ec87fc5SJack F Vogel break; 5204edd8523SJack F Vogel case e1000_phy_82578: 5214edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88; 5224edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 5234edd8523SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_m88; 5244edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88; 5254edd8523SJack F Vogel break; 5264edd8523SJack F Vogel default: 5274edd8523SJack F Vogel ret_val = -E1000_ERR_PHY; 5284edd8523SJack F Vogel break; 5299d81738fSJack F Vogel } 5309d81738fSJack F Vogel 5319d81738fSJack F Vogel return ret_val; 5329d81738fSJack F Vogel } 5339d81738fSJack F Vogel 5349d81738fSJack F Vogel /** 5358cfa0ad2SJack F Vogel * e1000_init_phy_params_ich8lan - Initialize PHY function pointers 5368cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5378cfa0ad2SJack F Vogel * 5388cfa0ad2SJack F Vogel * Initialize family-specific PHY parameters and function pointers. 5398cfa0ad2SJack F Vogel **/ 5408cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) 5418cfa0ad2SJack F Vogel { 5428cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 5436ab6bfe3SJack F Vogel s32 ret_val; 5448cfa0ad2SJack F Vogel u16 i = 0; 5458cfa0ad2SJack F Vogel 5468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_phy_params_ich8lan"); 5478cfa0ad2SJack F Vogel 5488cfa0ad2SJack F Vogel phy->addr = 1; 5498cfa0ad2SJack F Vogel phy->reset_delay_us = 100; 5508cfa0ad2SJack F Vogel 5518cfa0ad2SJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 5528cfa0ad2SJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 5538cfa0ad2SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_2; 5548cfa0ad2SJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 5558cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_igp; 5568cfa0ad2SJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 5578cfa0ad2SJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 5588cfa0ad2SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; 5598cfa0ad2SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; 5608cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_igp; 5618cfa0ad2SJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 5628cfa0ad2SJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 5638cfa0ad2SJack F Vogel 5646ab6bfe3SJack F Vogel /* We may need to do this twice - once for IGP and if that fails, 5658cfa0ad2SJack F Vogel * we'll set BM func pointers and try again 5668cfa0ad2SJack F Vogel */ 5678cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 5688cfa0ad2SJack F Vogel if (ret_val) { 5698cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 5708cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 5718cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 5728cfa0ad2SJack F Vogel if (ret_val) { 573d035aa2dSJack F Vogel DEBUGOUT("Cannot determine PHY addr. Erroring out\n"); 5746ab6bfe3SJack F Vogel return ret_val; 5758cfa0ad2SJack F Vogel } 5768cfa0ad2SJack F Vogel } 5778cfa0ad2SJack F Vogel 5788cfa0ad2SJack F Vogel phy->id = 0; 5798cfa0ad2SJack F Vogel while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) && 5808cfa0ad2SJack F Vogel (i++ < 100)) { 5818cfa0ad2SJack F Vogel msec_delay(1); 5828cfa0ad2SJack F Vogel ret_val = e1000_get_phy_id(hw); 5838cfa0ad2SJack F Vogel if (ret_val) 5846ab6bfe3SJack F Vogel return ret_val; 5858cfa0ad2SJack F Vogel } 5868cfa0ad2SJack F Vogel 5878cfa0ad2SJack F Vogel /* Verify phy id */ 5888cfa0ad2SJack F Vogel switch (phy->id) { 5898cfa0ad2SJack F Vogel case IGP03E1000_E_PHY_ID: 5908cfa0ad2SJack F Vogel phy->type = e1000_phy_igp_3; 5918cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 5924edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked; 5934edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked; 5944edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_igp; 5954edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_igp; 5964edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; 5978cfa0ad2SJack F Vogel break; 5988cfa0ad2SJack F Vogel case IFE_E_PHY_ID: 5998cfa0ad2SJack F Vogel case IFE_PLUS_E_PHY_ID: 6008cfa0ad2SJack F Vogel case IFE_C_E_PHY_ID: 6018cfa0ad2SJack F Vogel phy->type = e1000_phy_ife; 6028cfa0ad2SJack F Vogel phy->autoneg_mask = E1000_ALL_NOT_GIG; 6034edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_ife; 6044edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_ife; 6054edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; 6068cfa0ad2SJack F Vogel break; 6078cfa0ad2SJack F Vogel case BME1000_E_PHY_ID: 6088cfa0ad2SJack F Vogel phy->type = e1000_phy_bm; 6098cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 6108cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 6118cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 6128cfa0ad2SJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 6134edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88; 6144edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88; 6154edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 6168cfa0ad2SJack F Vogel break; 6178cfa0ad2SJack F Vogel default: 6186ab6bfe3SJack F Vogel return -E1000_ERR_PHY; 6196ab6bfe3SJack F Vogel break; 6208cfa0ad2SJack F Vogel } 6218cfa0ad2SJack F Vogel 6226ab6bfe3SJack F Vogel return E1000_SUCCESS; 6238cfa0ad2SJack F Vogel } 6248cfa0ad2SJack F Vogel 6258cfa0ad2SJack F Vogel /** 6268cfa0ad2SJack F Vogel * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers 6278cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 6288cfa0ad2SJack F Vogel * 6298cfa0ad2SJack F Vogel * Initialize family-specific NVM parameters and function 6308cfa0ad2SJack F Vogel * pointers. 6318cfa0ad2SJack F Vogel **/ 6328cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) 6338cfa0ad2SJack F Vogel { 6348cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 635daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 6368cfa0ad2SJack F Vogel u32 gfpreg, sector_base_addr, sector_end_addr; 6378cfa0ad2SJack F Vogel u16 i; 638*c80429ceSEric Joyner u32 nvm_size; 6398cfa0ad2SJack F Vogel 6408cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_ich8lan"); 6418cfa0ad2SJack F Vogel 6428cc64f1eSJack F Vogel nvm->type = e1000_nvm_flash_sw; 643*c80429ceSEric Joyner 644*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) { 645*c80429ceSEric Joyner /* in SPT, gfpreg doesn't exist. NVM size is taken from the 646*c80429ceSEric Joyner * STRAP register. This is because in SPT the GbE Flash region 647*c80429ceSEric Joyner * is no longer accessed through the flash registers. Instead, 648*c80429ceSEric Joyner * the mechanism has changed, and the Flash region access 649*c80429ceSEric Joyner * registers are now implemented in GbE memory space. 650*c80429ceSEric Joyner */ 651*c80429ceSEric Joyner nvm->flash_base_addr = 0; 652*c80429ceSEric Joyner nvm_size = 653*c80429ceSEric Joyner (((E1000_READ_REG(hw, E1000_STRAP) >> 1) & 0x1F) + 1) 654*c80429ceSEric Joyner * NVM_SIZE_MULTIPLIER; 655*c80429ceSEric Joyner nvm->flash_bank_size = nvm_size / 2; 656*c80429ceSEric Joyner /* Adjust to word count */ 657*c80429ceSEric Joyner nvm->flash_bank_size /= sizeof(u16); 658*c80429ceSEric Joyner /* Set the base address for flash register access */ 659*c80429ceSEric Joyner hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR; 660*c80429ceSEric Joyner } else { 661*c80429ceSEric Joyner /* Can't read flash registers if register set isn't mapped. */ 6628cfa0ad2SJack F Vogel if (!hw->flash_address) { 6638cfa0ad2SJack F Vogel DEBUGOUT("ERROR: Flash registers not mapped\n"); 6646ab6bfe3SJack F Vogel return -E1000_ERR_CONFIG; 6658cfa0ad2SJack F Vogel } 6668cfa0ad2SJack F Vogel 6678cfa0ad2SJack F Vogel gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); 6688cfa0ad2SJack F Vogel 6696ab6bfe3SJack F Vogel /* sector_X_addr is a "sector"-aligned address (4096 bytes) 6708cfa0ad2SJack F Vogel * Add 1 to sector_end_addr since this sector is included in 6718cfa0ad2SJack F Vogel * the overall size. 6728cfa0ad2SJack F Vogel */ 6738cfa0ad2SJack F Vogel sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 6748cfa0ad2SJack F Vogel sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; 6758cfa0ad2SJack F Vogel 6768cfa0ad2SJack F Vogel /* flash_base_addr is byte-aligned */ 677*c80429ceSEric Joyner nvm->flash_base_addr = sector_base_addr 678*c80429ceSEric Joyner << FLASH_SECTOR_ADDR_SHIFT; 6798cfa0ad2SJack F Vogel 6806ab6bfe3SJack F Vogel /* find total size of the NVM, then cut in half since the total 6818cfa0ad2SJack F Vogel * size represents two separate NVM banks. 6828cfa0ad2SJack F Vogel */ 6837609433eSJack F Vogel nvm->flash_bank_size = ((sector_end_addr - sector_base_addr) 6847609433eSJack F Vogel << FLASH_SECTOR_ADDR_SHIFT); 6858cfa0ad2SJack F Vogel nvm->flash_bank_size /= 2; 6868cfa0ad2SJack F Vogel /* Adjust to word count */ 6878cfa0ad2SJack F Vogel nvm->flash_bank_size /= sizeof(u16); 688*c80429ceSEric Joyner } 6898cfa0ad2SJack F Vogel 6908cfa0ad2SJack F Vogel nvm->word_size = E1000_SHADOW_RAM_WORDS; 6918cfa0ad2SJack F Vogel 6928cfa0ad2SJack F Vogel /* Clear shadow ram */ 6938cfa0ad2SJack F Vogel for (i = 0; i < nvm->word_size; i++) { 6948cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 6958cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 6968cfa0ad2SJack F Vogel } 6978cfa0ad2SJack F Vogel 6984edd8523SJack F Vogel E1000_MUTEX_INIT(&dev_spec->nvm_mutex); 6994edd8523SJack F Vogel E1000_MUTEX_INIT(&dev_spec->swflag_mutex); 7004edd8523SJack F Vogel 7018cfa0ad2SJack F Vogel /* Function Pointers */ 7024edd8523SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_ich8lan; 7034edd8523SJack F Vogel nvm->ops.release = e1000_release_nvm_ich8lan; 704*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) { 705*c80429ceSEric Joyner nvm->ops.read = e1000_read_nvm_spt; 706*c80429ceSEric Joyner nvm->ops.update = e1000_update_nvm_checksum_spt; 707*c80429ceSEric Joyner } else { 7088cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_ich8lan; 7098cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_ich8lan; 710*c80429ceSEric Joyner } 7118cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; 7128cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; 7138cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_ich8lan; 7148cfa0ad2SJack F Vogel 7156ab6bfe3SJack F Vogel return E1000_SUCCESS; 7168cfa0ad2SJack F Vogel } 7178cfa0ad2SJack F Vogel 7188cfa0ad2SJack F Vogel /** 7198cfa0ad2SJack F Vogel * e1000_init_mac_params_ich8lan - Initialize MAC function pointers 7208cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 7218cfa0ad2SJack F Vogel * 7228cfa0ad2SJack F Vogel * Initialize family-specific MAC parameters and function 7238cfa0ad2SJack F Vogel * pointers. 7248cfa0ad2SJack F Vogel **/ 7258cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) 7268cfa0ad2SJack F Vogel { 7278cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 7288cfa0ad2SJack F Vogel 7298cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_mac_params_ich8lan"); 7308cfa0ad2SJack F Vogel 7318cfa0ad2SJack F Vogel /* Set media type function pointer */ 7328cfa0ad2SJack F Vogel hw->phy.media_type = e1000_media_type_copper; 7338cfa0ad2SJack F Vogel 7348cfa0ad2SJack F Vogel /* Set mta register count */ 7358cfa0ad2SJack F Vogel mac->mta_reg_count = 32; 7368cfa0ad2SJack F Vogel /* Set rar entry count */ 7378cfa0ad2SJack F Vogel mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; 7388cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 7398cfa0ad2SJack F Vogel mac->rar_entry_count--; 7408cfa0ad2SJack F Vogel /* Set if part includes ASF firmware */ 7418cfa0ad2SJack F Vogel mac->asf_firmware_present = TRUE; 7428ec87fc5SJack F Vogel /* FWSM register */ 7438ec87fc5SJack F Vogel mac->has_fwsm = TRUE; 7448ec87fc5SJack F Vogel /* ARC subsystem not supported */ 7458ec87fc5SJack F Vogel mac->arc_subsystem_valid = FALSE; 7464edd8523SJack F Vogel /* Adaptive IFS supported */ 7474edd8523SJack F Vogel mac->adaptive_ifs = TRUE; 7488cfa0ad2SJack F Vogel 7498cfa0ad2SJack F Vogel /* Function pointers */ 7508cfa0ad2SJack F Vogel 7518cfa0ad2SJack F Vogel /* bus type/speed/width */ 7528cfa0ad2SJack F Vogel mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; 753daf9197cSJack F Vogel /* function id */ 754daf9197cSJack F Vogel mac->ops.set_lan_id = e1000_set_lan_id_single_port; 7558cfa0ad2SJack F Vogel /* reset */ 7568cfa0ad2SJack F Vogel mac->ops.reset_hw = e1000_reset_hw_ich8lan; 7578cfa0ad2SJack F Vogel /* hw initialization */ 7588cfa0ad2SJack F Vogel mac->ops.init_hw = e1000_init_hw_ich8lan; 7598cfa0ad2SJack F Vogel /* link setup */ 7608cfa0ad2SJack F Vogel mac->ops.setup_link = e1000_setup_link_ich8lan; 7618cfa0ad2SJack F Vogel /* physical interface setup */ 7628cfa0ad2SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; 7638cfa0ad2SJack F Vogel /* check for link */ 7644edd8523SJack F Vogel mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan; 7658cfa0ad2SJack F Vogel /* link info */ 7668cfa0ad2SJack F Vogel mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; 7678cfa0ad2SJack F Vogel /* multicast address update */ 7688cfa0ad2SJack F Vogel mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; 769d035aa2dSJack F Vogel /* clear hardware counters */ 770d035aa2dSJack F Vogel mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; 771d035aa2dSJack F Vogel 7726ab6bfe3SJack F Vogel /* LED and other operations */ 773d035aa2dSJack F Vogel switch (mac->type) { 774d035aa2dSJack F Vogel case e1000_ich8lan: 775d035aa2dSJack F Vogel case e1000_ich9lan: 776d035aa2dSJack F Vogel case e1000_ich10lan: 7777d9119bdSJack F Vogel /* check management mode */ 7787d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; 779d035aa2dSJack F Vogel /* ID LED init */ 780d035aa2dSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_generic; 7818cfa0ad2SJack F Vogel /* blink LED */ 7828cfa0ad2SJack F Vogel mac->ops.blink_led = e1000_blink_led_generic; 7838cfa0ad2SJack F Vogel /* setup LED */ 7848cfa0ad2SJack F Vogel mac->ops.setup_led = e1000_setup_led_generic; 7858cfa0ad2SJack F Vogel /* cleanup LED */ 7868cfa0ad2SJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; 7878cfa0ad2SJack F Vogel /* turn on/off LED */ 7888cfa0ad2SJack F Vogel mac->ops.led_on = e1000_led_on_ich8lan; 7898cfa0ad2SJack F Vogel mac->ops.led_off = e1000_led_off_ich8lan; 790d035aa2dSJack F Vogel break; 7917d9119bdSJack F Vogel case e1000_pch2lan: 7927d9119bdSJack F Vogel mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES; 7937d9119bdSJack F Vogel mac->ops.rar_set = e1000_rar_set_pch2lan; 7946ab6bfe3SJack F Vogel /* fall-through */ 7956ab6bfe3SJack F Vogel case e1000_pch_lpt: 796*c80429ceSEric Joyner case e1000_pch_spt: 797730d3130SJack F Vogel /* multicast address update for pch2 */ 798730d3130SJack F Vogel mac->ops.update_mc_addr_list = 799730d3130SJack F Vogel e1000_update_mc_addr_list_pch2lan; 800*c80429ceSEric Joyner /* fall-through */ 8019d81738fSJack F Vogel case e1000_pchlan: 8027d9119bdSJack F Vogel /* check management mode */ 8037d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; 8049d81738fSJack F Vogel /* ID LED init */ 8059d81738fSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_pchlan; 8069d81738fSJack F Vogel /* setup LED */ 8079d81738fSJack F Vogel mac->ops.setup_led = e1000_setup_led_pchlan; 8089d81738fSJack F Vogel /* cleanup LED */ 8099d81738fSJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_pchlan; 8109d81738fSJack F Vogel /* turn on/off LED */ 8119d81738fSJack F Vogel mac->ops.led_on = e1000_led_on_pchlan; 8129d81738fSJack F Vogel mac->ops.led_off = e1000_led_off_pchlan; 8139d81738fSJack F Vogel break; 814d035aa2dSJack F Vogel default: 815d035aa2dSJack F Vogel break; 816d035aa2dSJack F Vogel } 8178cfa0ad2SJack F Vogel 818*c80429ceSEric Joyner if ((mac->type == e1000_pch_lpt) || 819*c80429ceSEric Joyner (mac->type == e1000_pch_spt)) { 8206ab6bfe3SJack F Vogel mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES; 8216ab6bfe3SJack F Vogel mac->ops.rar_set = e1000_rar_set_pch_lpt; 8226ab6bfe3SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt; 823e373323fSSean Bruno mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt; 8244dab5c37SJack F Vogel } 8254dab5c37SJack F Vogel 8268cfa0ad2SJack F Vogel /* Enable PCS Lock-loss workaround for ICH8 */ 8278cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 8288cfa0ad2SJack F Vogel e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE); 8298cfa0ad2SJack F Vogel 830daf9197cSJack F Vogel return E1000_SUCCESS; 8318cfa0ad2SJack F Vogel } 8328cfa0ad2SJack F Vogel 8338cfa0ad2SJack F Vogel /** 8346ab6bfe3SJack F Vogel * __e1000_access_emi_reg_locked - Read/write EMI register 8356ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 8366ab6bfe3SJack F Vogel * @addr: EMI address to program 8376ab6bfe3SJack F Vogel * @data: pointer to value to read/write from/to the EMI address 8386ab6bfe3SJack F Vogel * @read: boolean flag to indicate read or write 8396ab6bfe3SJack F Vogel * 8406ab6bfe3SJack F Vogel * This helper function assumes the SW/FW/HW Semaphore is already acquired. 8416ab6bfe3SJack F Vogel **/ 8426ab6bfe3SJack F Vogel static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address, 8436ab6bfe3SJack F Vogel u16 *data, bool read) 8446ab6bfe3SJack F Vogel { 8456ab6bfe3SJack F Vogel s32 ret_val; 8466ab6bfe3SJack F Vogel 8476ab6bfe3SJack F Vogel DEBUGFUNC("__e1000_access_emi_reg_locked"); 8486ab6bfe3SJack F Vogel 8496ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, address); 8506ab6bfe3SJack F Vogel if (ret_val) 8516ab6bfe3SJack F Vogel return ret_val; 8526ab6bfe3SJack F Vogel 8536ab6bfe3SJack F Vogel if (read) 8546ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I82579_EMI_DATA, 8556ab6bfe3SJack F Vogel data); 8566ab6bfe3SJack F Vogel else 8576ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 8586ab6bfe3SJack F Vogel *data); 8596ab6bfe3SJack F Vogel 8606ab6bfe3SJack F Vogel return ret_val; 8616ab6bfe3SJack F Vogel } 8626ab6bfe3SJack F Vogel 8636ab6bfe3SJack F Vogel /** 8646ab6bfe3SJack F Vogel * e1000_read_emi_reg_locked - Read Extended Management Interface register 8656ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 8666ab6bfe3SJack F Vogel * @addr: EMI address to program 8676ab6bfe3SJack F Vogel * @data: value to be read from the EMI address 8686ab6bfe3SJack F Vogel * 8696ab6bfe3SJack F Vogel * Assumes the SW/FW/HW Semaphore is already acquired. 8706ab6bfe3SJack F Vogel **/ 8716ab6bfe3SJack F Vogel s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data) 8726ab6bfe3SJack F Vogel { 8736ab6bfe3SJack F Vogel DEBUGFUNC("e1000_read_emi_reg_locked"); 8746ab6bfe3SJack F Vogel 8756ab6bfe3SJack F Vogel return __e1000_access_emi_reg_locked(hw, addr, data, TRUE); 8766ab6bfe3SJack F Vogel } 8776ab6bfe3SJack F Vogel 8786ab6bfe3SJack F Vogel /** 8796ab6bfe3SJack F Vogel * e1000_write_emi_reg_locked - Write Extended Management Interface register 8806ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 8816ab6bfe3SJack F Vogel * @addr: EMI address to program 8826ab6bfe3SJack F Vogel * @data: value to be written to the EMI address 8836ab6bfe3SJack F Vogel * 8846ab6bfe3SJack F Vogel * Assumes the SW/FW/HW Semaphore is already acquired. 8856ab6bfe3SJack F Vogel **/ 8867609433eSJack F Vogel s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data) 8876ab6bfe3SJack F Vogel { 8886ab6bfe3SJack F Vogel DEBUGFUNC("e1000_read_emi_reg_locked"); 8896ab6bfe3SJack F Vogel 8906ab6bfe3SJack F Vogel return __e1000_access_emi_reg_locked(hw, addr, &data, FALSE); 8916ab6bfe3SJack F Vogel } 8926ab6bfe3SJack F Vogel 8936ab6bfe3SJack F Vogel /** 8947d9119bdSJack F Vogel * e1000_set_eee_pchlan - Enable/disable EEE support 8957d9119bdSJack F Vogel * @hw: pointer to the HW structure 8967d9119bdSJack F Vogel * 8976ab6bfe3SJack F Vogel * Enable/disable EEE based on setting in dev_spec structure, the duplex of 8986ab6bfe3SJack F Vogel * the link and the EEE capabilities of the link partner. The LPI Control 8996ab6bfe3SJack F Vogel * register bits will remain set only if/when link is up. 9007609433eSJack F Vogel * 9017609433eSJack F Vogel * EEE LPI must not be asserted earlier than one second after link is up. 9027609433eSJack F Vogel * On 82579, EEE LPI should not be enabled until such time otherwise there 9037609433eSJack F Vogel * can be link issues with some switches. Other devices can have EEE LPI 9047609433eSJack F Vogel * enabled immediately upon link up since they have a timer in hardware which 9057609433eSJack F Vogel * prevents LPI from being asserted too early. 9067d9119bdSJack F Vogel **/ 9077609433eSJack F Vogel s32 e1000_set_eee_pchlan(struct e1000_hw *hw) 9087d9119bdSJack F Vogel { 9094dab5c37SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 9106ab6bfe3SJack F Vogel s32 ret_val; 9117609433eSJack F Vogel u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data; 9127d9119bdSJack F Vogel 9137d9119bdSJack F Vogel DEBUGFUNC("e1000_set_eee_pchlan"); 9147d9119bdSJack F Vogel 9157609433eSJack F Vogel switch (hw->phy.type) { 9167609433eSJack F Vogel case e1000_phy_82579: 9177609433eSJack F Vogel lpa = I82579_EEE_LP_ABILITY; 9187609433eSJack F Vogel pcs_status = I82579_EEE_PCS_STATUS; 9197609433eSJack F Vogel adv_addr = I82579_EEE_ADVERTISEMENT; 9207609433eSJack F Vogel break; 9217609433eSJack F Vogel case e1000_phy_i217: 9227609433eSJack F Vogel lpa = I217_EEE_LP_ABILITY; 9237609433eSJack F Vogel pcs_status = I217_EEE_PCS_STATUS; 9247609433eSJack F Vogel adv_addr = I217_EEE_ADVERTISEMENT; 9257609433eSJack F Vogel break; 9267609433eSJack F Vogel default: 9276ab6bfe3SJack F Vogel return E1000_SUCCESS; 9287609433eSJack F Vogel } 9297d9119bdSJack F Vogel 9306ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 9317d9119bdSJack F Vogel if (ret_val) 9327d9119bdSJack F Vogel return ret_val; 9336ab6bfe3SJack F Vogel 9346ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl); 9356ab6bfe3SJack F Vogel if (ret_val) 9366ab6bfe3SJack F Vogel goto release; 9376ab6bfe3SJack F Vogel 9386ab6bfe3SJack F Vogel /* Clear bits that enable EEE in various speeds */ 9396ab6bfe3SJack F Vogel lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK; 9406ab6bfe3SJack F Vogel 9416ab6bfe3SJack F Vogel /* Enable EEE if not disabled by user */ 9426ab6bfe3SJack F Vogel if (!dev_spec->eee_disable) { 9436ab6bfe3SJack F Vogel /* Save off link partner's EEE ability */ 9446ab6bfe3SJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, lpa, 9456ab6bfe3SJack F Vogel &dev_spec->eee_lp_ability); 9466ab6bfe3SJack F Vogel if (ret_val) 9476ab6bfe3SJack F Vogel goto release; 9486ab6bfe3SJack F Vogel 9497609433eSJack F Vogel /* Read EEE advertisement */ 9507609433eSJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv); 9517609433eSJack F Vogel if (ret_val) 9527609433eSJack F Vogel goto release; 9537609433eSJack F Vogel 9546ab6bfe3SJack F Vogel /* Enable EEE only for speeds in which the link partner is 9557609433eSJack F Vogel * EEE capable and for which we advertise EEE. 9566ab6bfe3SJack F Vogel */ 9577609433eSJack F Vogel if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED) 9586ab6bfe3SJack F Vogel lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE; 9596ab6bfe3SJack F Vogel 9607609433eSJack F Vogel if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) { 9616ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data); 9626ab6bfe3SJack F Vogel if (data & NWAY_LPAR_100TX_FD_CAPS) 9636ab6bfe3SJack F Vogel lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE; 9646ab6bfe3SJack F Vogel else 9656ab6bfe3SJack F Vogel /* EEE is not supported in 100Half, so ignore 9666ab6bfe3SJack F Vogel * partner's EEE in 100 ability if full-duplex 9676ab6bfe3SJack F Vogel * is not advertised. 9686ab6bfe3SJack F Vogel */ 9696ab6bfe3SJack F Vogel dev_spec->eee_lp_ability &= 9706ab6bfe3SJack F Vogel ~I82579_EEE_100_SUPPORTED; 9716ab6bfe3SJack F Vogel } 9727609433eSJack F Vogel } 9736ab6bfe3SJack F Vogel 9748cc64f1eSJack F Vogel if (hw->phy.type == e1000_phy_82579) { 9758cc64f1eSJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, 9768cc64f1eSJack F Vogel &data); 9778cc64f1eSJack F Vogel if (ret_val) 9788cc64f1eSJack F Vogel goto release; 9798cc64f1eSJack F Vogel 9808cc64f1eSJack F Vogel data &= ~I82579_LPI_100_PLL_SHUT; 9818cc64f1eSJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, 9828cc64f1eSJack F Vogel data); 9838cc64f1eSJack F Vogel } 9848cc64f1eSJack F Vogel 9856ab6bfe3SJack F Vogel /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */ 9866ab6bfe3SJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data); 9876ab6bfe3SJack F Vogel if (ret_val) 9886ab6bfe3SJack F Vogel goto release; 9896ab6bfe3SJack F Vogel 9906ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl); 9916ab6bfe3SJack F Vogel release: 9926ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 9936ab6bfe3SJack F Vogel 9946ab6bfe3SJack F Vogel return ret_val; 9956ab6bfe3SJack F Vogel } 9966ab6bfe3SJack F Vogel 9976ab6bfe3SJack F Vogel /** 9986ab6bfe3SJack F Vogel * e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP 9996ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 10006ab6bfe3SJack F Vogel * @link: link up bool flag 10016ab6bfe3SJack F Vogel * 10026ab6bfe3SJack F Vogel * When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications 10036ab6bfe3SJack F Vogel * preventing further DMA write requests. Workaround the issue by disabling 10046ab6bfe3SJack F Vogel * the de-assertion of the clock request when in 1Gpbs mode. 10057609433eSJack F Vogel * Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link 10067609433eSJack F Vogel * speeds in order to avoid Tx hangs. 10076ab6bfe3SJack F Vogel **/ 10086ab6bfe3SJack F Vogel static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link) 10096ab6bfe3SJack F Vogel { 10106ab6bfe3SJack F Vogel u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); 10117609433eSJack F Vogel u32 status = E1000_READ_REG(hw, E1000_STATUS); 10126ab6bfe3SJack F Vogel s32 ret_val = E1000_SUCCESS; 10137609433eSJack F Vogel u16 reg; 10146ab6bfe3SJack F Vogel 10157609433eSJack F Vogel if (link && (status & E1000_STATUS_SPEED_1000)) { 10166ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 10176ab6bfe3SJack F Vogel if (ret_val) 10186ab6bfe3SJack F Vogel return ret_val; 10196ab6bfe3SJack F Vogel 10206ab6bfe3SJack F Vogel ret_val = 10216ab6bfe3SJack F Vogel e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 10227609433eSJack F Vogel ®); 10236ab6bfe3SJack F Vogel if (ret_val) 10246ab6bfe3SJack F Vogel goto release; 10256ab6bfe3SJack F Vogel 10266ab6bfe3SJack F Vogel ret_val = 10276ab6bfe3SJack F Vogel e1000_write_kmrn_reg_locked(hw, 10286ab6bfe3SJack F Vogel E1000_KMRNCTRLSTA_K1_CONFIG, 10297609433eSJack F Vogel reg & 10306ab6bfe3SJack F Vogel ~E1000_KMRNCTRLSTA_K1_ENABLE); 10316ab6bfe3SJack F Vogel if (ret_val) 10326ab6bfe3SJack F Vogel goto release; 10336ab6bfe3SJack F Vogel 10346ab6bfe3SJack F Vogel usec_delay(10); 10356ab6bfe3SJack F Vogel 10366ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, 10376ab6bfe3SJack F Vogel fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK); 10386ab6bfe3SJack F Vogel 10396ab6bfe3SJack F Vogel ret_val = 10406ab6bfe3SJack F Vogel e1000_write_kmrn_reg_locked(hw, 10416ab6bfe3SJack F Vogel E1000_KMRNCTRLSTA_K1_CONFIG, 10427609433eSJack F Vogel reg); 10436ab6bfe3SJack F Vogel release: 10446ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 10456ab6bfe3SJack F Vogel } else { 10466ab6bfe3SJack F Vogel /* clear FEXTNVM6 bit 8 on link down or 10/100 */ 10477609433eSJack F Vogel fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK; 10487609433eSJack F Vogel 1049*c80429ceSEric Joyner if ((hw->phy.revision > 5) || !link || 1050*c80429ceSEric Joyner ((status & E1000_STATUS_SPEED_100) && 10517609433eSJack F Vogel (status & E1000_STATUS_FD))) 10527609433eSJack F Vogel goto update_fextnvm6; 10537609433eSJack F Vogel 10547609433eSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, ®); 10557609433eSJack F Vogel if (ret_val) 10567609433eSJack F Vogel return ret_val; 10577609433eSJack F Vogel 10587609433eSJack F Vogel /* Clear link status transmit timeout */ 10597609433eSJack F Vogel reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK; 10607609433eSJack F Vogel 10617609433eSJack F Vogel if (status & E1000_STATUS_SPEED_100) { 10627609433eSJack F Vogel /* Set inband Tx timeout to 5x10us for 100Half */ 10637609433eSJack F Vogel reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT; 10647609433eSJack F Vogel 10657609433eSJack F Vogel /* Do not extend the K1 entry latency for 100Half */ 10667609433eSJack F Vogel fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION; 10677609433eSJack F Vogel } else { 10687609433eSJack F Vogel /* Set inband Tx timeout to 50x10us for 10Full/Half */ 10697609433eSJack F Vogel reg |= 50 << 10707609433eSJack F Vogel I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT; 10717609433eSJack F Vogel 10727609433eSJack F Vogel /* Extend the K1 entry latency for 10 Mbps */ 10737609433eSJack F Vogel fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION; 10747609433eSJack F Vogel } 10757609433eSJack F Vogel 10767609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg); 10777609433eSJack F Vogel if (ret_val) 10787609433eSJack F Vogel return ret_val; 10797609433eSJack F Vogel 10807609433eSJack F Vogel update_fextnvm6: 10817609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6); 10826ab6bfe3SJack F Vogel } 10836ab6bfe3SJack F Vogel 10846ab6bfe3SJack F Vogel return ret_val; 10856ab6bfe3SJack F Vogel } 10866ab6bfe3SJack F Vogel 1087e373323fSSean Bruno static u64 e1000_ltr2ns(u16 ltr) 1088e373323fSSean Bruno { 1089e373323fSSean Bruno u32 value, scale; 1090e373323fSSean Bruno 1091e373323fSSean Bruno /* Determine the latency in nsec based on the LTR value & scale */ 1092e373323fSSean Bruno value = ltr & E1000_LTRV_VALUE_MASK; 1093e373323fSSean Bruno scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT; 1094e373323fSSean Bruno 1095e373323fSSean Bruno return value * (1 << (scale * E1000_LTRV_SCALE_FACTOR)); 1096e373323fSSean Bruno } 1097e373323fSSean Bruno 1098e373323fSSean Bruno /** 1099e373323fSSean Bruno * e1000_platform_pm_pch_lpt - Set platform power management values 1100e373323fSSean Bruno * @hw: pointer to the HW structure 1101e373323fSSean Bruno * @link: bool indicating link status 1102e373323fSSean Bruno * 1103e373323fSSean Bruno * Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like" 1104e373323fSSean Bruno * GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed 1105e373323fSSean Bruno * when link is up (which must not exceed the maximum latency supported 1106e373323fSSean Bruno * by the platform), otherwise specify there is no LTR requirement. 1107e373323fSSean Bruno * Unlike TRUE-PCIe devices which set the LTR maximum snoop/no-snoop 1108e373323fSSean Bruno * latencies in the LTR Extended Capability Structure in the PCIe Extended 1109e373323fSSean Bruno * Capability register set, on this device LTR is set by writing the 1110e373323fSSean Bruno * equivalent snoop/no-snoop latencies in the LTRV register in the MAC and 1111e373323fSSean Bruno * set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB) 1112e373323fSSean Bruno * message to the PMC. 1113e373323fSSean Bruno * 1114e373323fSSean Bruno * Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF) 1115e373323fSSean Bruno * high-water mark. 1116e373323fSSean Bruno **/ 1117e373323fSSean Bruno static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) 1118e373323fSSean Bruno { 1119e373323fSSean Bruno u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) | 1120e373323fSSean Bruno link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND; 1121e373323fSSean Bruno u16 lat_enc = 0; /* latency encoded */ 1122e373323fSSean Bruno s32 obff_hwm = 0; 1123e373323fSSean Bruno 1124e373323fSSean Bruno DEBUGFUNC("e1000_platform_pm_pch_lpt"); 1125e373323fSSean Bruno 1126e373323fSSean Bruno if (link) { 1127e373323fSSean Bruno u16 speed, duplex, scale = 0; 1128e373323fSSean Bruno u16 max_snoop, max_nosnoop; 1129e373323fSSean Bruno u16 max_ltr_enc; /* max LTR latency encoded */ 1130e373323fSSean Bruno s64 lat_ns; 1131e373323fSSean Bruno s64 value; 1132e373323fSSean Bruno u32 rxa; 1133e373323fSSean Bruno 1134e373323fSSean Bruno if (!hw->mac.max_frame_size) { 1135e373323fSSean Bruno DEBUGOUT("max_frame_size not set.\n"); 1136e373323fSSean Bruno return -E1000_ERR_CONFIG; 1137e373323fSSean Bruno } 1138e373323fSSean Bruno 1139e373323fSSean Bruno hw->mac.ops.get_link_up_info(hw, &speed, &duplex); 1140e373323fSSean Bruno if (!speed) { 1141e373323fSSean Bruno DEBUGOUT("Speed not set.\n"); 1142e373323fSSean Bruno return -E1000_ERR_CONFIG; 1143e373323fSSean Bruno } 1144e373323fSSean Bruno 1145e373323fSSean Bruno /* Rx Packet Buffer Allocation size (KB) */ 1146e373323fSSean Bruno rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK; 1147e373323fSSean Bruno 1148e373323fSSean Bruno /* Determine the maximum latency tolerated by the device. 1149e373323fSSean Bruno * 1150e373323fSSean Bruno * Per the PCIe spec, the tolerated latencies are encoded as 1151e373323fSSean Bruno * a 3-bit encoded scale (only 0-5 are valid) multiplied by 1152e373323fSSean Bruno * a 10-bit value (0-1023) to provide a range from 1 ns to 1153e373323fSSean Bruno * 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns, 1154e373323fSSean Bruno * 1=2^5ns, 2=2^10ns,...5=2^25ns. 1155e373323fSSean Bruno */ 1156e373323fSSean Bruno lat_ns = ((s64)rxa * 1024 - 1157e373323fSSean Bruno (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000; 1158e373323fSSean Bruno if (lat_ns < 0) 1159e373323fSSean Bruno lat_ns = 0; 1160e373323fSSean Bruno else 1161e373323fSSean Bruno lat_ns /= speed; 1162e373323fSSean Bruno value = lat_ns; 1163e373323fSSean Bruno 1164e373323fSSean Bruno while (value > E1000_LTRV_VALUE_MASK) { 1165e373323fSSean Bruno scale++; 1166e373323fSSean Bruno value = E1000_DIVIDE_ROUND_UP(value, (1 << 5)); 1167e373323fSSean Bruno } 1168e373323fSSean Bruno if (scale > E1000_LTRV_SCALE_MAX) { 1169e373323fSSean Bruno DEBUGOUT1("Invalid LTR latency scale %d\n", scale); 1170e373323fSSean Bruno return -E1000_ERR_CONFIG; 1171e373323fSSean Bruno } 1172e373323fSSean Bruno lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value); 1173e373323fSSean Bruno 1174e373323fSSean Bruno /* Determine the maximum latency tolerated by the platform */ 1175e373323fSSean Bruno e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop); 1176e373323fSSean Bruno e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop); 1177e373323fSSean Bruno max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop); 1178e373323fSSean Bruno 1179e373323fSSean Bruno if (lat_enc > max_ltr_enc) { 1180e373323fSSean Bruno lat_enc = max_ltr_enc; 1181e373323fSSean Bruno lat_ns = e1000_ltr2ns(max_ltr_enc); 1182e373323fSSean Bruno } 1183e373323fSSean Bruno 1184e373323fSSean Bruno if (lat_ns) { 1185e373323fSSean Bruno lat_ns *= speed * 1000; 1186e373323fSSean Bruno lat_ns /= 8; 1187e373323fSSean Bruno lat_ns /= 1000000000; 1188e373323fSSean Bruno obff_hwm = (s32)(rxa - lat_ns); 1189e373323fSSean Bruno } 1190e373323fSSean Bruno if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) { 1191e373323fSSean Bruno DEBUGOUT1("Invalid high water mark %d\n", obff_hwm); 1192e373323fSSean Bruno return -E1000_ERR_CONFIG; 1193e373323fSSean Bruno } 1194e373323fSSean Bruno } 1195e373323fSSean Bruno 1196e373323fSSean Bruno /* Set Snoop and No-Snoop latencies the same */ 1197e373323fSSean Bruno reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT); 1198e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_LTRV, reg); 1199e373323fSSean Bruno 1200e373323fSSean Bruno /* Set OBFF high water mark */ 1201e373323fSSean Bruno reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK; 1202e373323fSSean Bruno reg |= obff_hwm; 1203e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVT, reg); 1204e373323fSSean Bruno 1205e373323fSSean Bruno /* Enable OBFF */ 1206e373323fSSean Bruno reg = E1000_READ_REG(hw, E1000_SVCR); 1207e373323fSSean Bruno reg |= E1000_SVCR_OFF_EN; 1208e373323fSSean Bruno /* Always unblock interrupts to the CPU even when the system is 1209e373323fSSean Bruno * in OBFF mode. This ensures that small round-robin traffic 1210e373323fSSean Bruno * (like ping) does not get dropped or experience long latency. 1211e373323fSSean Bruno */ 1212e373323fSSean Bruno reg |= E1000_SVCR_OFF_MASKINT; 1213e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVCR, reg); 1214e373323fSSean Bruno 1215e373323fSSean Bruno return E1000_SUCCESS; 1216e373323fSSean Bruno } 1217e373323fSSean Bruno 1218e373323fSSean Bruno /** 1219e373323fSSean Bruno * e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer 1220e373323fSSean Bruno * @hw: pointer to the HW structure 1221e373323fSSean Bruno * @itr: interrupt throttling rate 1222e373323fSSean Bruno * 1223e373323fSSean Bruno * Configure OBFF with the updated interrupt rate. 1224e373323fSSean Bruno **/ 1225e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr) 1226e373323fSSean Bruno { 1227e373323fSSean Bruno u32 svcr; 1228e373323fSSean Bruno s32 timer; 1229e373323fSSean Bruno 1230e373323fSSean Bruno DEBUGFUNC("e1000_set_obff_timer_pch_lpt"); 1231e373323fSSean Bruno 1232e373323fSSean Bruno /* Convert ITR value into microseconds for OBFF timer */ 1233e373323fSSean Bruno timer = itr & E1000_ITR_MASK; 1234e373323fSSean Bruno timer = (timer * E1000_ITR_MULT) / 1000; 1235e373323fSSean Bruno 1236e373323fSSean Bruno if ((timer < 0) || (timer > E1000_ITR_MASK)) { 1237e373323fSSean Bruno DEBUGOUT1("Invalid OBFF timer %d\n", timer); 1238e373323fSSean Bruno return -E1000_ERR_CONFIG; 1239e373323fSSean Bruno } 1240e373323fSSean Bruno 1241e373323fSSean Bruno svcr = E1000_READ_REG(hw, E1000_SVCR); 1242e373323fSSean Bruno svcr &= ~E1000_SVCR_OFF_TIMER_MASK; 1243e373323fSSean Bruno svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT; 1244e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVCR, svcr); 1245e373323fSSean Bruno 1246e373323fSSean Bruno return E1000_SUCCESS; 1247e373323fSSean Bruno } 1248e373323fSSean Bruno 12497d9119bdSJack F Vogel /** 12508cc64f1eSJack F Vogel * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP 12518cc64f1eSJack F Vogel * @hw: pointer to the HW structure 12528cc64f1eSJack F Vogel * @to_sx: boolean indicating a system power state transition to Sx 12538cc64f1eSJack F Vogel * 12548cc64f1eSJack F Vogel * When link is down, configure ULP mode to significantly reduce the power 12558cc64f1eSJack F Vogel * to the PHY. If on a Manageability Engine (ME) enabled system, tell the 12568cc64f1eSJack F Vogel * ME firmware to start the ULP configuration. If not on an ME enabled 12578cc64f1eSJack F Vogel * system, configure the ULP mode by software. 12588cc64f1eSJack F Vogel */ 12598cc64f1eSJack F Vogel s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx) 12608cc64f1eSJack F Vogel { 12618cc64f1eSJack F Vogel u32 mac_reg; 12628cc64f1eSJack F Vogel s32 ret_val = E1000_SUCCESS; 12638cc64f1eSJack F Vogel u16 phy_reg; 1264*c80429ceSEric Joyner u16 oem_reg = 0; 12658cc64f1eSJack F Vogel 12668cc64f1eSJack F Vogel if ((hw->mac.type < e1000_pch_lpt) || 12678cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) || 12688cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) || 12698cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) || 12708cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V2) || 12718cc64f1eSJack F Vogel (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on)) 12728cc64f1eSJack F Vogel return 0; 12738cc64f1eSJack F Vogel 12748cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) { 12758cc64f1eSJack F Vogel /* Request ME configure ULP mode in the PHY */ 12768cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 12778cc64f1eSJack F Vogel mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; 12788cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 12798cc64f1eSJack F Vogel 12808cc64f1eSJack F Vogel goto out; 12818cc64f1eSJack F Vogel } 12828cc64f1eSJack F Vogel 12838cc64f1eSJack F Vogel if (!to_sx) { 12848cc64f1eSJack F Vogel int i = 0; 12858cc64f1eSJack F Vogel 12868cc64f1eSJack F Vogel /* Poll up to 5 seconds for Cable Disconnected indication */ 12878cc64f1eSJack F Vogel while (!(E1000_READ_REG(hw, E1000_FEXT) & 12888cc64f1eSJack F Vogel E1000_FEXT_PHY_CABLE_DISCONNECTED)) { 12898cc64f1eSJack F Vogel /* Bail if link is re-acquired */ 12908cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) 12918cc64f1eSJack F Vogel return -E1000_ERR_PHY; 12928cc64f1eSJack F Vogel 12938cc64f1eSJack F Vogel if (i++ == 100) 12948cc64f1eSJack F Vogel break; 12958cc64f1eSJack F Vogel 12968cc64f1eSJack F Vogel msec_delay(50); 12978cc64f1eSJack F Vogel } 12988cc64f1eSJack F Vogel DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n", 12998cc64f1eSJack F Vogel (E1000_READ_REG(hw, E1000_FEXT) & 13008cc64f1eSJack F Vogel E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", 13018cc64f1eSJack F Vogel i * 50); 13028cc64f1eSJack F Vogel } 13038cc64f1eSJack F Vogel 13048cc64f1eSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 13058cc64f1eSJack F Vogel if (ret_val) 13068cc64f1eSJack F Vogel goto out; 13078cc64f1eSJack F Vogel 13088cc64f1eSJack F Vogel /* Force SMBus mode in PHY */ 13098cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); 13108cc64f1eSJack F Vogel if (ret_val) 13118cc64f1eSJack F Vogel goto release; 13128cc64f1eSJack F Vogel phy_reg |= CV_SMB_CTRL_FORCE_SMBUS; 13138cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); 13148cc64f1eSJack F Vogel 13158cc64f1eSJack F Vogel /* Force SMBus mode in MAC */ 13168cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 13178cc64f1eSJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 13188cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 13198cc64f1eSJack F Vogel 1320*c80429ceSEric Joyner /* Si workaround for ULP entry flow on i127/rev6 h/w. Enable 1321*c80429ceSEric Joyner * LPLU and disable Gig speed when entering ULP 1322*c80429ceSEric Joyner */ 1323*c80429ceSEric Joyner if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) { 1324*c80429ceSEric Joyner ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS, 1325*c80429ceSEric Joyner &oem_reg); 1326*c80429ceSEric Joyner if (ret_val) 1327*c80429ceSEric Joyner goto release; 1328*c80429ceSEric Joyner 1329*c80429ceSEric Joyner phy_reg = oem_reg; 1330*c80429ceSEric Joyner phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS; 1331*c80429ceSEric Joyner 1332*c80429ceSEric Joyner ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, 1333*c80429ceSEric Joyner phy_reg); 1334*c80429ceSEric Joyner 1335*c80429ceSEric Joyner if (ret_val) 1336*c80429ceSEric Joyner goto release; 1337*c80429ceSEric Joyner } 1338*c80429ceSEric Joyner 13398cc64f1eSJack F Vogel /* Set Inband ULP Exit, Reset to SMBus mode and 13408cc64f1eSJack F Vogel * Disable SMBus Release on PERST# in PHY 13418cc64f1eSJack F Vogel */ 13428cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); 13438cc64f1eSJack F Vogel if (ret_val) 13448cc64f1eSJack F Vogel goto release; 13458cc64f1eSJack F Vogel phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS | 13468cc64f1eSJack F Vogel I218_ULP_CONFIG1_DISABLE_SMB_PERST); 13478cc64f1eSJack F Vogel if (to_sx) { 13488cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC) 13498cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_WOL_HOST; 1350*c80429ceSEric Joyner else 1351*c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST; 13528cc64f1eSJack F Vogel 13538cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_STICKY_ULP; 1354*c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT; 13558cc64f1eSJack F Vogel } else { 13568cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT; 1357*c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP; 1358*c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST; 13598cc64f1eSJack F Vogel } 13608cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 13618cc64f1eSJack F Vogel 13628cc64f1eSJack F Vogel /* Set Disable SMBus Release on PERST# in MAC */ 13638cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7); 13648cc64f1eSJack F Vogel mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST; 13658cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg); 13668cc64f1eSJack F Vogel 13678cc64f1eSJack F Vogel /* Commit ULP changes in PHY by starting auto ULP configuration */ 13688cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_START; 13698cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 1370*c80429ceSEric Joyner 1371*c80429ceSEric Joyner if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) && 1372*c80429ceSEric Joyner to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 1373*c80429ceSEric Joyner ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, 1374*c80429ceSEric Joyner oem_reg); 1375*c80429ceSEric Joyner if (ret_val) 1376*c80429ceSEric Joyner goto release; 1377*c80429ceSEric Joyner } 1378*c80429ceSEric Joyner 13798cc64f1eSJack F Vogel release: 13808cc64f1eSJack F Vogel hw->phy.ops.release(hw); 13818cc64f1eSJack F Vogel out: 13828cc64f1eSJack F Vogel if (ret_val) 13838cc64f1eSJack F Vogel DEBUGOUT1("Error in ULP enable flow: %d\n", ret_val); 13848cc64f1eSJack F Vogel else 13858cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on; 13868cc64f1eSJack F Vogel 13878cc64f1eSJack F Vogel return ret_val; 13888cc64f1eSJack F Vogel } 13898cc64f1eSJack F Vogel 13908cc64f1eSJack F Vogel /** 13918cc64f1eSJack F Vogel * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP 13928cc64f1eSJack F Vogel * @hw: pointer to the HW structure 13938cc64f1eSJack F Vogel * @force: boolean indicating whether or not to force disabling ULP 13948cc64f1eSJack F Vogel * 13958cc64f1eSJack F Vogel * Un-configure ULP mode when link is up, the system is transitioned from 13968cc64f1eSJack F Vogel * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled 13978cc64f1eSJack F Vogel * system, poll for an indication from ME that ULP has been un-configured. 13988cc64f1eSJack F Vogel * If not on an ME enabled system, un-configure the ULP mode by software. 13998cc64f1eSJack F Vogel * 14008cc64f1eSJack F Vogel * During nominal operation, this function is called when link is acquired 14018cc64f1eSJack F Vogel * to disable ULP mode (force=FALSE); otherwise, for example when unloading 14028cc64f1eSJack F Vogel * the driver or during Sx->S0 transitions, this is called with force=TRUE 14038cc64f1eSJack F Vogel * to forcibly disable ULP. 14048cc64f1eSJack F Vogel */ 14058cc64f1eSJack F Vogel s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) 14068cc64f1eSJack F Vogel { 14078cc64f1eSJack F Vogel s32 ret_val = E1000_SUCCESS; 14088cc64f1eSJack F Vogel u32 mac_reg; 14098cc64f1eSJack F Vogel u16 phy_reg; 14108cc64f1eSJack F Vogel int i = 0; 14118cc64f1eSJack F Vogel 14128cc64f1eSJack F Vogel if ((hw->mac.type < e1000_pch_lpt) || 14138cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) || 14148cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) || 14158cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) || 14168cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V2) || 14178cc64f1eSJack F Vogel (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off)) 14188cc64f1eSJack F Vogel return 0; 14198cc64f1eSJack F Vogel 14208cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) { 14218cc64f1eSJack F Vogel if (force) { 14228cc64f1eSJack F Vogel /* Request ME un-configure ULP mode in the PHY */ 14238cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 14248cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ULP; 14258cc64f1eSJack F Vogel mac_reg |= E1000_H2ME_ENFORCE_SETTINGS; 14268cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 14278cc64f1eSJack F Vogel } 14288cc64f1eSJack F Vogel 1429*c80429ceSEric Joyner /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */ 14308cc64f1eSJack F Vogel while (E1000_READ_REG(hw, E1000_FWSM) & 14318cc64f1eSJack F Vogel E1000_FWSM_ULP_CFG_DONE) { 1432*c80429ceSEric Joyner if (i++ == 30) { 14338cc64f1eSJack F Vogel ret_val = -E1000_ERR_PHY; 14348cc64f1eSJack F Vogel goto out; 14358cc64f1eSJack F Vogel } 14368cc64f1eSJack F Vogel 14378cc64f1eSJack F Vogel msec_delay(10); 14388cc64f1eSJack F Vogel } 14398cc64f1eSJack F Vogel DEBUGOUT1("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); 14408cc64f1eSJack F Vogel 14418cc64f1eSJack F Vogel if (force) { 14428cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 14438cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS; 14448cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 14458cc64f1eSJack F Vogel } else { 14468cc64f1eSJack F Vogel /* Clear H2ME.ULP after ME ULP configuration */ 14478cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 14488cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ULP; 14498cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 14508cc64f1eSJack F Vogel } 14518cc64f1eSJack F Vogel 14528cc64f1eSJack F Vogel goto out; 14538cc64f1eSJack F Vogel } 14548cc64f1eSJack F Vogel 14558cc64f1eSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 14568cc64f1eSJack F Vogel if (ret_val) 14578cc64f1eSJack F Vogel goto out; 14588cc64f1eSJack F Vogel 14598cc64f1eSJack F Vogel if (force) 14608cc64f1eSJack F Vogel /* Toggle LANPHYPC Value bit */ 14618cc64f1eSJack F Vogel e1000_toggle_lanphypc_pch_lpt(hw); 14628cc64f1eSJack F Vogel 14638cc64f1eSJack F Vogel /* Unforce SMBus mode in PHY */ 14648cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); 14658cc64f1eSJack F Vogel if (ret_val) { 14668cc64f1eSJack F Vogel /* The MAC might be in PCIe mode, so temporarily force to 14678cc64f1eSJack F Vogel * SMBus mode in order to access the PHY. 14688cc64f1eSJack F Vogel */ 14698cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 14708cc64f1eSJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 14718cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 14728cc64f1eSJack F Vogel 14738cc64f1eSJack F Vogel msec_delay(50); 14748cc64f1eSJack F Vogel 14758cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, 14768cc64f1eSJack F Vogel &phy_reg); 14778cc64f1eSJack F Vogel if (ret_val) 14788cc64f1eSJack F Vogel goto release; 14798cc64f1eSJack F Vogel } 14808cc64f1eSJack F Vogel phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; 14818cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); 14828cc64f1eSJack F Vogel 14838cc64f1eSJack F Vogel /* Unforce SMBus mode in MAC */ 14848cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 14858cc64f1eSJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 14868cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 14878cc64f1eSJack F Vogel 14888cc64f1eSJack F Vogel /* When ULP mode was previously entered, K1 was disabled by the 14898cc64f1eSJack F Vogel * hardware. Re-Enable K1 in the PHY when exiting ULP. 14908cc64f1eSJack F Vogel */ 14918cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg); 14928cc64f1eSJack F Vogel if (ret_val) 14938cc64f1eSJack F Vogel goto release; 14948cc64f1eSJack F Vogel phy_reg |= HV_PM_CTRL_K1_ENABLE; 14958cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg); 14968cc64f1eSJack F Vogel 14978cc64f1eSJack F Vogel /* Clear ULP enabled configuration */ 14988cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); 14998cc64f1eSJack F Vogel if (ret_val) 15008cc64f1eSJack F Vogel goto release; 15018cc64f1eSJack F Vogel phy_reg &= ~(I218_ULP_CONFIG1_IND | 15028cc64f1eSJack F Vogel I218_ULP_CONFIG1_STICKY_ULP | 15038cc64f1eSJack F Vogel I218_ULP_CONFIG1_RESET_TO_SMBUS | 15048cc64f1eSJack F Vogel I218_ULP_CONFIG1_WOL_HOST | 15058cc64f1eSJack F Vogel I218_ULP_CONFIG1_INBAND_EXIT | 1506*c80429ceSEric Joyner I218_ULP_CONFIG1_EN_ULP_LANPHYPC | 1507*c80429ceSEric Joyner I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST | 15088cc64f1eSJack F Vogel I218_ULP_CONFIG1_DISABLE_SMB_PERST); 15098cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 15108cc64f1eSJack F Vogel 15118cc64f1eSJack F Vogel /* Commit ULP changes by starting auto ULP configuration */ 15128cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_START; 15138cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 15148cc64f1eSJack F Vogel 15158cc64f1eSJack F Vogel /* Clear Disable SMBus Release on PERST# in MAC */ 15168cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7); 15178cc64f1eSJack F Vogel mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; 15188cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg); 15198cc64f1eSJack F Vogel 15208cc64f1eSJack F Vogel release: 15218cc64f1eSJack F Vogel hw->phy.ops.release(hw); 15228cc64f1eSJack F Vogel if (force) { 15238cc64f1eSJack F Vogel hw->phy.ops.reset(hw); 15248cc64f1eSJack F Vogel msec_delay(50); 15258cc64f1eSJack F Vogel } 15268cc64f1eSJack F Vogel out: 15278cc64f1eSJack F Vogel if (ret_val) 15288cc64f1eSJack F Vogel DEBUGOUT1("Error in ULP disable flow: %d\n", ret_val); 15298cc64f1eSJack F Vogel else 15308cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off; 15318cc64f1eSJack F Vogel 15328cc64f1eSJack F Vogel return ret_val; 15338cc64f1eSJack F Vogel } 15348cc64f1eSJack F Vogel 15358cc64f1eSJack F Vogel /** 15364edd8523SJack F Vogel * e1000_check_for_copper_link_ich8lan - Check for link (Copper) 15374edd8523SJack F Vogel * @hw: pointer to the HW structure 15384edd8523SJack F Vogel * 15394edd8523SJack F Vogel * Checks to see of the link status of the hardware has changed. If a 15404edd8523SJack F Vogel * change in link status has been detected, then we read the PHY registers 15414edd8523SJack F Vogel * to get the current speed/duplex if link exists. 15424edd8523SJack F Vogel **/ 15434edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) 15444edd8523SJack F Vogel { 15454edd8523SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 1546*c80429ceSEric Joyner s32 ret_val, tipg_reg = 0; 1547*c80429ceSEric Joyner u16 emi_addr, emi_val = 0; 15484edd8523SJack F Vogel bool link; 15494dab5c37SJack F Vogel u16 phy_reg; 15504edd8523SJack F Vogel 15514edd8523SJack F Vogel DEBUGFUNC("e1000_check_for_copper_link_ich8lan"); 15524edd8523SJack F Vogel 15536ab6bfe3SJack F Vogel /* We only want to go out to the PHY registers to see if Auto-Neg 15544edd8523SJack F Vogel * has completed and/or if our link status has changed. The 15554edd8523SJack F Vogel * get_link_status flag is set upon receiving a Link Status 15564edd8523SJack F Vogel * Change or Rx Sequence Error interrupt. 15574edd8523SJack F Vogel */ 15586ab6bfe3SJack F Vogel if (!mac->get_link_status) 15596ab6bfe3SJack F Vogel return E1000_SUCCESS; 15604edd8523SJack F Vogel 15616ab6bfe3SJack F Vogel /* First we want to see if the MII Status Register reports 15624edd8523SJack F Vogel * link. If so, then we want to get the current speed/duplex 15634edd8523SJack F Vogel * of the PHY. 15644edd8523SJack F Vogel */ 15654edd8523SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 15664edd8523SJack F Vogel if (ret_val) 15676ab6bfe3SJack F Vogel return ret_val; 15684edd8523SJack F Vogel 15694edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) { 15704edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, link); 15714edd8523SJack F Vogel if (ret_val) 15726ab6bfe3SJack F Vogel return ret_val; 15734edd8523SJack F Vogel } 15744edd8523SJack F Vogel 15758cc64f1eSJack F Vogel /* When connected at 10Mbps half-duplex, some parts are excessively 15766ab6bfe3SJack F Vogel * aggressive resulting in many collisions. To avoid this, increase 15776ab6bfe3SJack F Vogel * the IPG and reduce Rx latency in the PHY. 15786ab6bfe3SJack F Vogel */ 15798cc64f1eSJack F Vogel if (((hw->mac.type == e1000_pch2lan) || 1580*c80429ceSEric Joyner (hw->mac.type == e1000_pch_lpt) || 1581*c80429ceSEric Joyner (hw->mac.type == e1000_pch_spt)) && link) { 1582*c80429ceSEric Joyner u16 speed, duplex; 15838cc64f1eSJack F Vogel 1584*c80429ceSEric Joyner e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex); 1585*c80429ceSEric Joyner tipg_reg = E1000_READ_REG(hw, E1000_TIPG); 1586*c80429ceSEric Joyner tipg_reg &= ~E1000_TIPG_IPGT_MASK; 15876ab6bfe3SJack F Vogel 1588*c80429ceSEric Joyner if (duplex == HALF_DUPLEX && speed == SPEED_10) { 1589*c80429ceSEric Joyner tipg_reg |= 0xFF; 15906ab6bfe3SJack F Vogel /* Reduce Rx latency in analog PHY */ 1591*c80429ceSEric Joyner emi_val = 0; 1592*c80429ceSEric Joyner } else if (hw->mac.type == e1000_pch_spt && 1593*c80429ceSEric Joyner duplex == FULL_DUPLEX && speed != SPEED_1000) { 1594*c80429ceSEric Joyner tipg_reg |= 0xC; 1595*c80429ceSEric Joyner emi_val = 1; 1596*c80429ceSEric Joyner } else { 1597*c80429ceSEric Joyner /* Roll back the default values */ 1598*c80429ceSEric Joyner tipg_reg |= 0x08; 1599*c80429ceSEric Joyner emi_val = 1; 1600*c80429ceSEric Joyner } 1601*c80429ceSEric Joyner 1602*c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_TIPG, tipg_reg); 1603*c80429ceSEric Joyner 16046ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 16056ab6bfe3SJack F Vogel if (ret_val) 16066ab6bfe3SJack F Vogel return ret_val; 16076ab6bfe3SJack F Vogel 16088cc64f1eSJack F Vogel if (hw->mac.type == e1000_pch2lan) 16098cc64f1eSJack F Vogel emi_addr = I82579_RX_CONFIG; 16108cc64f1eSJack F Vogel else 16118cc64f1eSJack F Vogel emi_addr = I217_RX_CONFIG; 1612*c80429ceSEric Joyner ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val); 16136ab6bfe3SJack F Vogel 1614*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_lpt || 1615*c80429ceSEric Joyner hw->mac.type == e1000_pch_spt) { 1616*c80429ceSEric Joyner u16 phy_reg; 1617*c80429ceSEric Joyner 1618*c80429ceSEric Joyner hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG, 1619*c80429ceSEric Joyner &phy_reg); 1620*c80429ceSEric Joyner phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; 1621*c80429ceSEric Joyner if (speed == SPEED_100 || speed == SPEED_10) 1622*c80429ceSEric Joyner phy_reg |= 0x3E8; 1623*c80429ceSEric Joyner else 1624*c80429ceSEric Joyner phy_reg |= 0xFA; 1625*c80429ceSEric Joyner hw->phy.ops.write_reg_locked(hw, 1626*c80429ceSEric Joyner I217_PLL_CLOCK_GATE_REG, 1627*c80429ceSEric Joyner phy_reg); 1628*c80429ceSEric Joyner } 16296ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 16306ab6bfe3SJack F Vogel 16316ab6bfe3SJack F Vogel if (ret_val) 16326ab6bfe3SJack F Vogel return ret_val; 1633*c80429ceSEric Joyner 1634*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) { 1635*c80429ceSEric Joyner u16 data; 1636*c80429ceSEric Joyner u16 ptr_gap; 1637*c80429ceSEric Joyner 1638*c80429ceSEric Joyner if (speed == SPEED_1000) { 1639*c80429ceSEric Joyner ret_val = hw->phy.ops.acquire(hw); 1640*c80429ceSEric Joyner if (ret_val) 1641*c80429ceSEric Joyner return ret_val; 1642*c80429ceSEric Joyner 1643*c80429ceSEric Joyner ret_val = hw->phy.ops.read_reg_locked(hw, 1644*c80429ceSEric Joyner PHY_REG(776, 20), 1645*c80429ceSEric Joyner &data); 1646*c80429ceSEric Joyner if (ret_val) { 1647*c80429ceSEric Joyner hw->phy.ops.release(hw); 1648*c80429ceSEric Joyner return ret_val; 16496ab6bfe3SJack F Vogel } 1650*c80429ceSEric Joyner 1651*c80429ceSEric Joyner ptr_gap = (data & (0x3FF << 2)) >> 2; 1652*c80429ceSEric Joyner if (ptr_gap < 0x18) { 1653*c80429ceSEric Joyner data &= ~(0x3FF << 2); 1654*c80429ceSEric Joyner data |= (0x18 << 2); 1655*c80429ceSEric Joyner ret_val = 1656*c80429ceSEric Joyner hw->phy.ops.write_reg_locked(hw, 1657*c80429ceSEric Joyner PHY_REG(776, 20), data); 1658*c80429ceSEric Joyner } 1659*c80429ceSEric Joyner hw->phy.ops.release(hw); 1660*c80429ceSEric Joyner if (ret_val) 1661*c80429ceSEric Joyner return ret_val; 1662*c80429ceSEric Joyner } else { 1663*c80429ceSEric Joyner ret_val = hw->phy.ops.acquire(hw); 1664*c80429ceSEric Joyner if (ret_val) 1665*c80429ceSEric Joyner return ret_val; 1666*c80429ceSEric Joyner 1667*c80429ceSEric Joyner ret_val = hw->phy.ops.write_reg_locked(hw, 1668*c80429ceSEric Joyner PHY_REG(776, 20), 1669*c80429ceSEric Joyner 0xC023); 1670*c80429ceSEric Joyner hw->phy.ops.release(hw); 1671*c80429ceSEric Joyner if (ret_val) 1672*c80429ceSEric Joyner return ret_val; 1673*c80429ceSEric Joyner 1674*c80429ceSEric Joyner } 1675*c80429ceSEric Joyner } 1676*c80429ceSEric Joyner } 1677*c80429ceSEric Joyner 1678*c80429ceSEric Joyner /* I217 Packet Loss issue: 1679*c80429ceSEric Joyner * ensure that FEXTNVM4 Beacon Duration is set correctly 1680*c80429ceSEric Joyner * on power up. 1681*c80429ceSEric Joyner * Set the Beacon Duration for I217 to 8 usec 1682*c80429ceSEric Joyner */ 1683*c80429ceSEric Joyner if ((hw->mac.type == e1000_pch_lpt) || 1684*c80429ceSEric Joyner (hw->mac.type == e1000_pch_spt)) { 1685*c80429ceSEric Joyner u32 mac_reg; 1686*c80429ceSEric Joyner 1687*c80429ceSEric Joyner mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); 1688*c80429ceSEric Joyner mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 1689*c80429ceSEric Joyner mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC; 1690*c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg); 16916ab6bfe3SJack F Vogel } 16926ab6bfe3SJack F Vogel 16936ab6bfe3SJack F Vogel /* Work-around I218 hang issue */ 16946ab6bfe3SJack F Vogel if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || 16958cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || 16968cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) || 16978cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) { 16986ab6bfe3SJack F Vogel ret_val = e1000_k1_workaround_lpt_lp(hw, link); 16996ab6bfe3SJack F Vogel if (ret_val) 17006ab6bfe3SJack F Vogel return ret_val; 17016ab6bfe3SJack F Vogel } 1702*c80429ceSEric Joyner if ((hw->mac.type == e1000_pch_lpt) || 1703*c80429ceSEric Joyner (hw->mac.type == e1000_pch_spt)) { 1704e373323fSSean Bruno /* Set platform power management values for 1705e373323fSSean Bruno * Latency Tolerance Reporting (LTR) 1706e373323fSSean Bruno * Optimized Buffer Flush/Fill (OBFF) 1707e373323fSSean Bruno */ 1708e373323fSSean Bruno ret_val = e1000_platform_pm_pch_lpt(hw, link); 1709e373323fSSean Bruno if (ret_val) 1710e373323fSSean Bruno return ret_val; 1711e373323fSSean Bruno } 1712e373323fSSean Bruno 17136ab6bfe3SJack F Vogel /* Clear link partner's EEE ability */ 17146ab6bfe3SJack F Vogel hw->dev_spec.ich8lan.eee_lp_ability = 0; 17156ab6bfe3SJack F Vogel 1716*c80429ceSEric Joyner /* FEXTNVM6 K1-off workaround */ 1717*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) { 1718*c80429ceSEric Joyner u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG); 1719*c80429ceSEric Joyner u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); 1720*c80429ceSEric Joyner 1721*c80429ceSEric Joyner if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE) 1722*c80429ceSEric Joyner fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE; 1723*c80429ceSEric Joyner else 1724*c80429ceSEric Joyner fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE; 1725*c80429ceSEric Joyner 1726*c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6); 1727*c80429ceSEric Joyner } 1728*c80429ceSEric Joyner 17294edd8523SJack F Vogel if (!link) 17306ab6bfe3SJack F Vogel return E1000_SUCCESS; /* No link detected */ 17314edd8523SJack F Vogel 17324edd8523SJack F Vogel mac->get_link_status = FALSE; 17334edd8523SJack F Vogel 17344dab5c37SJack F Vogel switch (hw->mac.type) { 17354dab5c37SJack F Vogel case e1000_pch2lan: 17364dab5c37SJack F Vogel ret_val = e1000_k1_workaround_lv(hw); 17374dab5c37SJack F Vogel if (ret_val) 17386ab6bfe3SJack F Vogel return ret_val; 17394dab5c37SJack F Vogel /* fall-thru */ 17404dab5c37SJack F Vogel case e1000_pchlan: 17414edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) { 17424edd8523SJack F Vogel ret_val = e1000_link_stall_workaround_hv(hw); 17434edd8523SJack F Vogel if (ret_val) 17446ab6bfe3SJack F Vogel return ret_val; 17454edd8523SJack F Vogel } 17464edd8523SJack F Vogel 17476ab6bfe3SJack F Vogel /* Workaround for PCHx parts in half-duplex: 17484dab5c37SJack F Vogel * Set the number of preambles removed from the packet 17494dab5c37SJack F Vogel * when it is passed from the PHY to the MAC to prevent 17504dab5c37SJack F Vogel * the MAC from misinterpreting the packet type. 17514dab5c37SJack F Vogel */ 17524dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg); 17534dab5c37SJack F Vogel phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK; 17544dab5c37SJack F Vogel 17554dab5c37SJack F Vogel if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) != 17564dab5c37SJack F Vogel E1000_STATUS_FD) 17574dab5c37SJack F Vogel phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT); 17584dab5c37SJack F Vogel 17594dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg); 17604dab5c37SJack F Vogel break; 17614dab5c37SJack F Vogel default: 17624dab5c37SJack F Vogel break; 17637d9119bdSJack F Vogel } 17647d9119bdSJack F Vogel 17656ab6bfe3SJack F Vogel /* Check if there was DownShift, must be checked 17664edd8523SJack F Vogel * immediately after link-up 17674edd8523SJack F Vogel */ 17684edd8523SJack F Vogel e1000_check_downshift_generic(hw); 17694edd8523SJack F Vogel 17707d9119bdSJack F Vogel /* Enable/Disable EEE after link up */ 17717609433eSJack F Vogel if (hw->phy.type > e1000_phy_82579) { 17727d9119bdSJack F Vogel ret_val = e1000_set_eee_pchlan(hw); 17737d9119bdSJack F Vogel if (ret_val) 17746ab6bfe3SJack F Vogel return ret_val; 17757609433eSJack F Vogel } 17767d9119bdSJack F Vogel 17776ab6bfe3SJack F Vogel /* If we are forcing speed/duplex, then we simply return since 17784edd8523SJack F Vogel * we have already determined whether we have link or not. 17794edd8523SJack F Vogel */ 17806ab6bfe3SJack F Vogel if (!mac->autoneg) 17816ab6bfe3SJack F Vogel return -E1000_ERR_CONFIG; 17824edd8523SJack F Vogel 17836ab6bfe3SJack F Vogel /* Auto-Neg is enabled. Auto Speed Detection takes care 17844edd8523SJack F Vogel * of MAC speed/duplex configuration. So we only need to 17854edd8523SJack F Vogel * configure Collision Distance in the MAC. 17864edd8523SJack F Vogel */ 17876ab6bfe3SJack F Vogel mac->ops.config_collision_dist(hw); 17884edd8523SJack F Vogel 17896ab6bfe3SJack F Vogel /* Configure Flow Control now that Auto-Neg has completed. 17904edd8523SJack F Vogel * First, we need to restore the desired flow control 17914edd8523SJack F Vogel * settings because we may have had to re-autoneg with a 17924edd8523SJack F Vogel * different link partner. 17934edd8523SJack F Vogel */ 17944edd8523SJack F Vogel ret_val = e1000_config_fc_after_link_up_generic(hw); 17954edd8523SJack F Vogel if (ret_val) 17964edd8523SJack F Vogel DEBUGOUT("Error configuring flow control\n"); 17974edd8523SJack F Vogel 17984edd8523SJack F Vogel return ret_val; 17994edd8523SJack F Vogel } 18004edd8523SJack F Vogel 18014edd8523SJack F Vogel /** 18028cfa0ad2SJack F Vogel * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers 18038cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 18048cfa0ad2SJack F Vogel * 18058cfa0ad2SJack F Vogel * Initialize family-specific function pointers for PHY, MAC, and NVM. 18068cfa0ad2SJack F Vogel **/ 18078cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) 18088cfa0ad2SJack F Vogel { 18098cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_function_pointers_ich8lan"); 18108cfa0ad2SJack F Vogel 18118cfa0ad2SJack F Vogel hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; 18128cfa0ad2SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; 18139d81738fSJack F Vogel switch (hw->mac.type) { 18149d81738fSJack F Vogel case e1000_ich8lan: 18159d81738fSJack F Vogel case e1000_ich9lan: 18169d81738fSJack F Vogel case e1000_ich10lan: 18178cfa0ad2SJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; 18189d81738fSJack F Vogel break; 18199d81738fSJack F Vogel case e1000_pchlan: 18207d9119bdSJack F Vogel case e1000_pch2lan: 18216ab6bfe3SJack F Vogel case e1000_pch_lpt: 1822*c80429ceSEric Joyner case e1000_pch_spt: 18239d81738fSJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_pchlan; 18249d81738fSJack F Vogel break; 18259d81738fSJack F Vogel default: 18269d81738fSJack F Vogel break; 18279d81738fSJack F Vogel } 18288cfa0ad2SJack F Vogel } 18298cfa0ad2SJack F Vogel 18308cfa0ad2SJack F Vogel /** 18314edd8523SJack F Vogel * e1000_acquire_nvm_ich8lan - Acquire NVM mutex 18324edd8523SJack F Vogel * @hw: pointer to the HW structure 18334edd8523SJack F Vogel * 18344edd8523SJack F Vogel * Acquires the mutex for performing NVM operations. 18354edd8523SJack F Vogel **/ 18364edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw) 18374edd8523SJack F Vogel { 18384edd8523SJack F Vogel DEBUGFUNC("e1000_acquire_nvm_ich8lan"); 18394edd8523SJack F Vogel 18404edd8523SJack F Vogel E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex); 18414edd8523SJack F Vogel 18424edd8523SJack F Vogel return E1000_SUCCESS; 18434edd8523SJack F Vogel } 18444edd8523SJack F Vogel 18454edd8523SJack F Vogel /** 18464edd8523SJack F Vogel * e1000_release_nvm_ich8lan - Release NVM mutex 18474edd8523SJack F Vogel * @hw: pointer to the HW structure 18484edd8523SJack F Vogel * 18494edd8523SJack F Vogel * Releases the mutex used while performing NVM operations. 18504edd8523SJack F Vogel **/ 18514edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw) 18524edd8523SJack F Vogel { 18534edd8523SJack F Vogel DEBUGFUNC("e1000_release_nvm_ich8lan"); 18544edd8523SJack F Vogel 18554edd8523SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex); 18564edd8523SJack F Vogel 18574edd8523SJack F Vogel return; 18584edd8523SJack F Vogel } 18594edd8523SJack F Vogel 18604edd8523SJack F Vogel /** 18618cfa0ad2SJack F Vogel * e1000_acquire_swflag_ich8lan - Acquire software control flag 18628cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 18638cfa0ad2SJack F Vogel * 18644edd8523SJack F Vogel * Acquires the software control flag for performing PHY and select 18654edd8523SJack F Vogel * MAC CSR accesses. 18668cfa0ad2SJack F Vogel **/ 18678cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) 18688cfa0ad2SJack F Vogel { 18698cfa0ad2SJack F Vogel u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; 18708cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 18718cfa0ad2SJack F Vogel 18728cfa0ad2SJack F Vogel DEBUGFUNC("e1000_acquire_swflag_ich8lan"); 18738cfa0ad2SJack F Vogel 18744edd8523SJack F Vogel E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex); 18754edd8523SJack F Vogel 18768cfa0ad2SJack F Vogel while (timeout) { 18778cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 18784edd8523SJack F Vogel if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) 18798cfa0ad2SJack F Vogel break; 18804edd8523SJack F Vogel 18818cfa0ad2SJack F Vogel msec_delay_irq(1); 18828cfa0ad2SJack F Vogel timeout--; 18838cfa0ad2SJack F Vogel } 18848cfa0ad2SJack F Vogel 18858cfa0ad2SJack F Vogel if (!timeout) { 18864dab5c37SJack F Vogel DEBUGOUT("SW has already locked the resource.\n"); 18874edd8523SJack F Vogel ret_val = -E1000_ERR_CONFIG; 18884edd8523SJack F Vogel goto out; 18894edd8523SJack F Vogel } 18904edd8523SJack F Vogel 18914edd8523SJack F Vogel timeout = SW_FLAG_TIMEOUT; 18924edd8523SJack F Vogel 18934edd8523SJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; 18944edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 18954edd8523SJack F Vogel 18964edd8523SJack F Vogel while (timeout) { 18974edd8523SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 18984edd8523SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) 18994edd8523SJack F Vogel break; 19004edd8523SJack F Vogel 19014edd8523SJack F Vogel msec_delay_irq(1); 19024edd8523SJack F Vogel timeout--; 19034edd8523SJack F Vogel } 19044edd8523SJack F Vogel 19054edd8523SJack F Vogel if (!timeout) { 19064dab5c37SJack F Vogel DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n", 19074dab5c37SJack F Vogel E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl); 19088cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 19098cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 19108cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 19118cfa0ad2SJack F Vogel goto out; 19128cfa0ad2SJack F Vogel } 19138cfa0ad2SJack F Vogel 19148cfa0ad2SJack F Vogel out: 19154edd8523SJack F Vogel if (ret_val) 19164edd8523SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); 19174edd8523SJack F Vogel 19188cfa0ad2SJack F Vogel return ret_val; 19198cfa0ad2SJack F Vogel } 19208cfa0ad2SJack F Vogel 19218cfa0ad2SJack F Vogel /** 19228cfa0ad2SJack F Vogel * e1000_release_swflag_ich8lan - Release software control flag 19238cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 19248cfa0ad2SJack F Vogel * 19254edd8523SJack F Vogel * Releases the software control flag for performing PHY and select 19264edd8523SJack F Vogel * MAC CSR accesses. 19278cfa0ad2SJack F Vogel **/ 19288cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) 19298cfa0ad2SJack F Vogel { 19308cfa0ad2SJack F Vogel u32 extcnf_ctrl; 19318cfa0ad2SJack F Vogel 19328cfa0ad2SJack F Vogel DEBUGFUNC("e1000_release_swflag_ich8lan"); 19338cfa0ad2SJack F Vogel 19348cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 1935730d3130SJack F Vogel 1936730d3130SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) { 19378cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 19388cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 1939730d3130SJack F Vogel } else { 1940730d3130SJack F Vogel DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n"); 1941730d3130SJack F Vogel } 19428cfa0ad2SJack F Vogel 19434edd8523SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); 19444edd8523SJack F Vogel 19458cfa0ad2SJack F Vogel return; 19468cfa0ad2SJack F Vogel } 19478cfa0ad2SJack F Vogel 19488cfa0ad2SJack F Vogel /** 19498cfa0ad2SJack F Vogel * e1000_check_mng_mode_ich8lan - Checks management mode 19508cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 19518cfa0ad2SJack F Vogel * 19527d9119bdSJack F Vogel * This checks if the adapter has any manageability enabled. 19538cfa0ad2SJack F Vogel * This is a function pointer entry point only called by read/write 19548cfa0ad2SJack F Vogel * routines for the PHY and NVM parts. 19558cfa0ad2SJack F Vogel **/ 19568cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) 19578cfa0ad2SJack F Vogel { 19588cfa0ad2SJack F Vogel u32 fwsm; 19598cfa0ad2SJack F Vogel 19608cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_mng_mode_ich8lan"); 19618cfa0ad2SJack F Vogel 19628cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 19638cfa0ad2SJack F Vogel 19648cc64f1eSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) && 19657d9119bdSJack F Vogel ((fwsm & E1000_FWSM_MODE_MASK) == 19668cc64f1eSJack F Vogel (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 19677d9119bdSJack F Vogel } 19687d9119bdSJack F Vogel 19697d9119bdSJack F Vogel /** 19707d9119bdSJack F Vogel * e1000_check_mng_mode_pchlan - Checks management mode 19717d9119bdSJack F Vogel * @hw: pointer to the HW structure 19727d9119bdSJack F Vogel * 19737d9119bdSJack F Vogel * This checks if the adapter has iAMT enabled. 19747d9119bdSJack F Vogel * This is a function pointer entry point only called by read/write 19757d9119bdSJack F Vogel * routines for the PHY and NVM parts. 19767d9119bdSJack F Vogel **/ 19777d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw) 19787d9119bdSJack F Vogel { 19797d9119bdSJack F Vogel u32 fwsm; 19807d9119bdSJack F Vogel 19817d9119bdSJack F Vogel DEBUGFUNC("e1000_check_mng_mode_pchlan"); 19827d9119bdSJack F Vogel 19837d9119bdSJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 19847d9119bdSJack F Vogel 19857d9119bdSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) && 19867d9119bdSJack F Vogel (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 19877d9119bdSJack F Vogel } 19887d9119bdSJack F Vogel 19897d9119bdSJack F Vogel /** 19907d9119bdSJack F Vogel * e1000_rar_set_pch2lan - Set receive address register 19917d9119bdSJack F Vogel * @hw: pointer to the HW structure 19927d9119bdSJack F Vogel * @addr: pointer to the receive address 19937d9119bdSJack F Vogel * @index: receive address array register 19947d9119bdSJack F Vogel * 19957d9119bdSJack F Vogel * Sets the receive address array register at index to the address passed 19967d9119bdSJack F Vogel * in by addr. For 82579, RAR[0] is the base address register that is to 19977d9119bdSJack F Vogel * contain the MAC address but RAR[1-6] are reserved for manageability (ME). 19987d9119bdSJack F Vogel * Use SHRA[0-3] in place of those reserved for ME. 19997d9119bdSJack F Vogel **/ 20008cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) 20017d9119bdSJack F Vogel { 20027d9119bdSJack F Vogel u32 rar_low, rar_high; 20037d9119bdSJack F Vogel 20047d9119bdSJack F Vogel DEBUGFUNC("e1000_rar_set_pch2lan"); 20057d9119bdSJack F Vogel 20066ab6bfe3SJack F Vogel /* HW expects these in little endian so we reverse the byte order 20077d9119bdSJack F Vogel * from network order (big endian) to little endian 20087d9119bdSJack F Vogel */ 20097d9119bdSJack F Vogel rar_low = ((u32) addr[0] | 20107d9119bdSJack F Vogel ((u32) addr[1] << 8) | 20117d9119bdSJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); 20127d9119bdSJack F Vogel 20137d9119bdSJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); 20147d9119bdSJack F Vogel 20157d9119bdSJack F Vogel /* If MAC address zero, no need to set the AV bit */ 20167d9119bdSJack F Vogel if (rar_low || rar_high) 20177d9119bdSJack F Vogel rar_high |= E1000_RAH_AV; 20187d9119bdSJack F Vogel 20197d9119bdSJack F Vogel if (index == 0) { 20207d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); 20217d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 20227d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); 20237d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 20248cc64f1eSJack F Vogel return E1000_SUCCESS; 20257d9119bdSJack F Vogel } 20267d9119bdSJack F Vogel 20277609433eSJack F Vogel /* RAR[1-6] are owned by manageability. Skip those and program the 20287609433eSJack F Vogel * next address into the SHRA register array. 20297609433eSJack F Vogel */ 20308cc64f1eSJack F Vogel if (index < (u32) (hw->mac.rar_entry_count)) { 20316ab6bfe3SJack F Vogel s32 ret_val; 20326ab6bfe3SJack F Vogel 20336ab6bfe3SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 20346ab6bfe3SJack F Vogel if (ret_val) 20356ab6bfe3SJack F Vogel goto out; 20366ab6bfe3SJack F Vogel 20377d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low); 20387d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 20397d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high); 20407d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 20417d9119bdSJack F Vogel 20426ab6bfe3SJack F Vogel e1000_release_swflag_ich8lan(hw); 20436ab6bfe3SJack F Vogel 20447d9119bdSJack F Vogel /* verify the register updates */ 20457d9119bdSJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) && 20467d9119bdSJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high)) 20478cc64f1eSJack F Vogel return E1000_SUCCESS; 20487d9119bdSJack F Vogel 20497d9119bdSJack F Vogel DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n", 20507d9119bdSJack F Vogel (index - 1), E1000_READ_REG(hw, E1000_FWSM)); 20517d9119bdSJack F Vogel } 20527d9119bdSJack F Vogel 20536ab6bfe3SJack F Vogel out: 20546ab6bfe3SJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index); 20558cc64f1eSJack F Vogel return -E1000_ERR_CONFIG; 20566ab6bfe3SJack F Vogel } 20576ab6bfe3SJack F Vogel 20586ab6bfe3SJack F Vogel /** 20596ab6bfe3SJack F Vogel * e1000_rar_set_pch_lpt - Set receive address registers 20606ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 20616ab6bfe3SJack F Vogel * @addr: pointer to the receive address 20626ab6bfe3SJack F Vogel * @index: receive address array register 20636ab6bfe3SJack F Vogel * 20646ab6bfe3SJack F Vogel * Sets the receive address register array at index to the address passed 20656ab6bfe3SJack F Vogel * in by addr. For LPT, RAR[0] is the base address register that is to 20666ab6bfe3SJack F Vogel * contain the MAC address. SHRA[0-10] are the shared receive address 20676ab6bfe3SJack F Vogel * registers that are shared between the Host and manageability engine (ME). 20686ab6bfe3SJack F Vogel **/ 20698cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index) 20706ab6bfe3SJack F Vogel { 20716ab6bfe3SJack F Vogel u32 rar_low, rar_high; 20726ab6bfe3SJack F Vogel u32 wlock_mac; 20736ab6bfe3SJack F Vogel 20746ab6bfe3SJack F Vogel DEBUGFUNC("e1000_rar_set_pch_lpt"); 20756ab6bfe3SJack F Vogel 20766ab6bfe3SJack F Vogel /* HW expects these in little endian so we reverse the byte order 20776ab6bfe3SJack F Vogel * from network order (big endian) to little endian 20786ab6bfe3SJack F Vogel */ 20796ab6bfe3SJack F Vogel rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) | 20806ab6bfe3SJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); 20816ab6bfe3SJack F Vogel 20826ab6bfe3SJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); 20836ab6bfe3SJack F Vogel 20846ab6bfe3SJack F Vogel /* If MAC address zero, no need to set the AV bit */ 20856ab6bfe3SJack F Vogel if (rar_low || rar_high) 20866ab6bfe3SJack F Vogel rar_high |= E1000_RAH_AV; 20876ab6bfe3SJack F Vogel 20886ab6bfe3SJack F Vogel if (index == 0) { 20896ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); 20906ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 20916ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); 20926ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 20938cc64f1eSJack F Vogel return E1000_SUCCESS; 20946ab6bfe3SJack F Vogel } 20956ab6bfe3SJack F Vogel 20966ab6bfe3SJack F Vogel /* The manageability engine (ME) can lock certain SHRAR registers that 20976ab6bfe3SJack F Vogel * it is using - those registers are unavailable for use. 20986ab6bfe3SJack F Vogel */ 20996ab6bfe3SJack F Vogel if (index < hw->mac.rar_entry_count) { 21006ab6bfe3SJack F Vogel wlock_mac = E1000_READ_REG(hw, E1000_FWSM) & 21016ab6bfe3SJack F Vogel E1000_FWSM_WLOCK_MAC_MASK; 21026ab6bfe3SJack F Vogel wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT; 21036ab6bfe3SJack F Vogel 21046ab6bfe3SJack F Vogel /* Check if all SHRAR registers are locked */ 21056ab6bfe3SJack F Vogel if (wlock_mac == 1) 21066ab6bfe3SJack F Vogel goto out; 21076ab6bfe3SJack F Vogel 21086ab6bfe3SJack F Vogel if ((wlock_mac == 0) || (index <= wlock_mac)) { 21096ab6bfe3SJack F Vogel s32 ret_val; 21106ab6bfe3SJack F Vogel 21116ab6bfe3SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 21126ab6bfe3SJack F Vogel 21136ab6bfe3SJack F Vogel if (ret_val) 21146ab6bfe3SJack F Vogel goto out; 21156ab6bfe3SJack F Vogel 21166ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL_PCH_LPT(index - 1), 21176ab6bfe3SJack F Vogel rar_low); 21186ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 21196ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH_PCH_LPT(index - 1), 21206ab6bfe3SJack F Vogel rar_high); 21216ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 21226ab6bfe3SJack F Vogel 21236ab6bfe3SJack F Vogel e1000_release_swflag_ich8lan(hw); 21246ab6bfe3SJack F Vogel 21256ab6bfe3SJack F Vogel /* verify the register updates */ 21266ab6bfe3SJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL_PCH_LPT(index - 1)) == rar_low) && 21276ab6bfe3SJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH_PCH_LPT(index - 1)) == rar_high)) 21288cc64f1eSJack F Vogel return E1000_SUCCESS; 21296ab6bfe3SJack F Vogel } 21306ab6bfe3SJack F Vogel } 21316ab6bfe3SJack F Vogel 21326ab6bfe3SJack F Vogel out: 21337d9119bdSJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index); 21348cc64f1eSJack F Vogel return -E1000_ERR_CONFIG; 21358cfa0ad2SJack F Vogel } 21368cfa0ad2SJack F Vogel 21378cfa0ad2SJack F Vogel /** 2138730d3130SJack F Vogel * e1000_update_mc_addr_list_pch2lan - Update Multicast addresses 2139730d3130SJack F Vogel * @hw: pointer to the HW structure 2140730d3130SJack F Vogel * @mc_addr_list: array of multicast addresses to program 2141730d3130SJack F Vogel * @mc_addr_count: number of multicast addresses to program 2142730d3130SJack F Vogel * 2143730d3130SJack F Vogel * Updates entire Multicast Table Array of the PCH2 MAC and PHY. 2144730d3130SJack F Vogel * The caller must have a packed mc_addr_list of multicast addresses. 2145730d3130SJack F Vogel **/ 2146730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw, 2147730d3130SJack F Vogel u8 *mc_addr_list, 2148730d3130SJack F Vogel u32 mc_addr_count) 2149730d3130SJack F Vogel { 21504dab5c37SJack F Vogel u16 phy_reg = 0; 2151730d3130SJack F Vogel int i; 21524dab5c37SJack F Vogel s32 ret_val; 2153730d3130SJack F Vogel 2154730d3130SJack F Vogel DEBUGFUNC("e1000_update_mc_addr_list_pch2lan"); 2155730d3130SJack F Vogel 2156730d3130SJack F Vogel e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count); 2157730d3130SJack F Vogel 21584dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 21594dab5c37SJack F Vogel if (ret_val) 21604dab5c37SJack F Vogel return; 21614dab5c37SJack F Vogel 21624dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 21634dab5c37SJack F Vogel if (ret_val) 21644dab5c37SJack F Vogel goto release; 21654dab5c37SJack F Vogel 2166730d3130SJack F Vogel for (i = 0; i < hw->mac.mta_reg_count; i++) { 21674dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_MTA(i), 21684dab5c37SJack F Vogel (u16)(hw->mac.mta_shadow[i] & 21694dab5c37SJack F Vogel 0xFFFF)); 21704dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1), 2171730d3130SJack F Vogel (u16)((hw->mac.mta_shadow[i] >> 16) & 2172730d3130SJack F Vogel 0xFFFF)); 2173730d3130SJack F Vogel } 21744dab5c37SJack F Vogel 21754dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 21764dab5c37SJack F Vogel 21774dab5c37SJack F Vogel release: 21784dab5c37SJack F Vogel hw->phy.ops.release(hw); 2179730d3130SJack F Vogel } 2180730d3130SJack F Vogel 2181730d3130SJack F Vogel /** 21828cfa0ad2SJack F Vogel * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked 21838cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 21848cfa0ad2SJack F Vogel * 21858cfa0ad2SJack F Vogel * Checks if firmware is blocking the reset of the PHY. 21868cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 21878cfa0ad2SJack F Vogel * reset routines. 21888cfa0ad2SJack F Vogel **/ 21898cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) 21908cfa0ad2SJack F Vogel { 21918cfa0ad2SJack F Vogel u32 fwsm; 21927609433eSJack F Vogel bool blocked = FALSE; 21937609433eSJack F Vogel int i = 0; 21948cfa0ad2SJack F Vogel 21958cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_reset_block_ich8lan"); 21968cfa0ad2SJack F Vogel 21977609433eSJack F Vogel do { 21988cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 21997609433eSJack F Vogel if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) { 22007609433eSJack F Vogel blocked = TRUE; 22017609433eSJack F Vogel msec_delay(10); 22027609433eSJack F Vogel continue; 22037609433eSJack F Vogel } 22047609433eSJack F Vogel blocked = FALSE; 2205*c80429ceSEric Joyner } while (blocked && (i++ < 30)); 22067609433eSJack F Vogel return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS; 22078cfa0ad2SJack F Vogel } 22088cfa0ad2SJack F Vogel 22098cfa0ad2SJack F Vogel /** 22107d9119bdSJack F Vogel * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states 22117d9119bdSJack F Vogel * @hw: pointer to the HW structure 22127d9119bdSJack F Vogel * 22137d9119bdSJack F Vogel * Assumes semaphore already acquired. 22147d9119bdSJack F Vogel * 22157d9119bdSJack F Vogel **/ 22167d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw) 22177d9119bdSJack F Vogel { 22187d9119bdSJack F Vogel u16 phy_data; 22197d9119bdSJack F Vogel u32 strap = E1000_READ_REG(hw, E1000_STRAP); 22206ab6bfe3SJack F Vogel u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >> 22216ab6bfe3SJack F Vogel E1000_STRAP_SMT_FREQ_SHIFT; 22226ab6bfe3SJack F Vogel s32 ret_val; 22237d9119bdSJack F Vogel 22247d9119bdSJack F Vogel strap &= E1000_STRAP_SMBUS_ADDRESS_MASK; 22257d9119bdSJack F Vogel 22267d9119bdSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data); 22277d9119bdSJack F Vogel if (ret_val) 22286ab6bfe3SJack F Vogel return ret_val; 22297d9119bdSJack F Vogel 22307d9119bdSJack F Vogel phy_data &= ~HV_SMB_ADDR_MASK; 22317d9119bdSJack F Vogel phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT); 22327d9119bdSJack F Vogel phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; 22337d9119bdSJack F Vogel 22346ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) { 22356ab6bfe3SJack F Vogel /* Restore SMBus frequency */ 22366ab6bfe3SJack F Vogel if (freq--) { 22376ab6bfe3SJack F Vogel phy_data &= ~HV_SMB_ADDR_FREQ_MASK; 22386ab6bfe3SJack F Vogel phy_data |= (freq & (1 << 0)) << 22396ab6bfe3SJack F Vogel HV_SMB_ADDR_FREQ_LOW_SHIFT; 22406ab6bfe3SJack F Vogel phy_data |= (freq & (1 << 1)) << 22416ab6bfe3SJack F Vogel (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1); 22426ab6bfe3SJack F Vogel } else { 22436ab6bfe3SJack F Vogel DEBUGOUT("Unsupported SMB frequency in PHY\n"); 22446ab6bfe3SJack F Vogel } 22456ab6bfe3SJack F Vogel } 22466ab6bfe3SJack F Vogel 22476ab6bfe3SJack F Vogel return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data); 22487d9119bdSJack F Vogel } 22497d9119bdSJack F Vogel 22507d9119bdSJack F Vogel /** 22514edd8523SJack F Vogel * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration 22524edd8523SJack F Vogel * @hw: pointer to the HW structure 22534edd8523SJack F Vogel * 22544edd8523SJack F Vogel * SW should configure the LCD from the NVM extended configuration region 22554edd8523SJack F Vogel * as a workaround for certain parts. 22564edd8523SJack F Vogel **/ 22574edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) 22584edd8523SJack F Vogel { 22594edd8523SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 22604edd8523SJack F Vogel u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; 2261a69ed8dfSJack F Vogel s32 ret_val = E1000_SUCCESS; 22624edd8523SJack F Vogel u16 word_addr, reg_data, reg_addr, phy_page = 0; 22634edd8523SJack F Vogel 22647d9119bdSJack F Vogel DEBUGFUNC("e1000_sw_lcd_config_ich8lan"); 22654edd8523SJack F Vogel 22666ab6bfe3SJack F Vogel /* Initialize the PHY from the NVM on ICH platforms. This 22674edd8523SJack F Vogel * is needed due to an issue where the NVM configuration is 22684edd8523SJack F Vogel * not properly autoloaded after power transitions. 22694edd8523SJack F Vogel * Therefore, after each PHY reset, we will load the 22704edd8523SJack F Vogel * configuration data out of the NVM manually. 22714edd8523SJack F Vogel */ 22727d9119bdSJack F Vogel switch (hw->mac.type) { 22737d9119bdSJack F Vogel case e1000_ich8lan: 22747d9119bdSJack F Vogel if (phy->type != e1000_phy_igp_3) 22757d9119bdSJack F Vogel return ret_val; 22767d9119bdSJack F Vogel 22777d9119bdSJack F Vogel if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) || 22787d9119bdSJack F Vogel (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) { 22794edd8523SJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; 22807d9119bdSJack F Vogel break; 22817d9119bdSJack F Vogel } 22827d9119bdSJack F Vogel /* Fall-thru */ 22837d9119bdSJack F Vogel case e1000_pchlan: 22847d9119bdSJack F Vogel case e1000_pch2lan: 22856ab6bfe3SJack F Vogel case e1000_pch_lpt: 2286*c80429ceSEric Joyner case e1000_pch_spt: 22877d9119bdSJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; 22887d9119bdSJack F Vogel break; 22897d9119bdSJack F Vogel default: 22907d9119bdSJack F Vogel return ret_val; 22917d9119bdSJack F Vogel } 22927d9119bdSJack F Vogel 22937d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 22947d9119bdSJack F Vogel if (ret_val) 22957d9119bdSJack F Vogel return ret_val; 22964edd8523SJack F Vogel 22974edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_FEXTNVM); 22984edd8523SJack F Vogel if (!(data & sw_cfg_mask)) 22996ab6bfe3SJack F Vogel goto release; 23004edd8523SJack F Vogel 23016ab6bfe3SJack F Vogel /* Make sure HW does not configure LCD from PHY 23024edd8523SJack F Vogel * extended configuration before SW configuration 23034edd8523SJack F Vogel */ 23044edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 23056ab6bfe3SJack F Vogel if ((hw->mac.type < e1000_pch2lan) && 23066ab6bfe3SJack F Vogel (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)) 23076ab6bfe3SJack F Vogel goto release; 23084edd8523SJack F Vogel 23094edd8523SJack F Vogel cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); 23104edd8523SJack F Vogel cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; 23114edd8523SJack F Vogel cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; 23124edd8523SJack F Vogel if (!cnf_size) 23136ab6bfe3SJack F Vogel goto release; 23144edd8523SJack F Vogel 23154edd8523SJack F Vogel cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; 23164edd8523SJack F Vogel cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; 23174edd8523SJack F Vogel 23186ab6bfe3SJack F Vogel if (((hw->mac.type == e1000_pchlan) && 23196ab6bfe3SJack F Vogel !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) || 23206ab6bfe3SJack F Vogel (hw->mac.type > e1000_pchlan)) { 23216ab6bfe3SJack F Vogel /* HW configures the SMBus address and LEDs when the 23224edd8523SJack F Vogel * OEM and LCD Write Enable bits are set in the NVM. 23234edd8523SJack F Vogel * When both NVM bits are cleared, SW will configure 23244edd8523SJack F Vogel * them instead. 23254edd8523SJack F Vogel */ 23267d9119bdSJack F Vogel ret_val = e1000_write_smbus_addr(hw); 23274edd8523SJack F Vogel if (ret_val) 23286ab6bfe3SJack F Vogel goto release; 23294edd8523SJack F Vogel 23304edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_LEDCTL); 2331a69ed8dfSJack F Vogel ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG, 23324edd8523SJack F Vogel (u16)data); 23334edd8523SJack F Vogel if (ret_val) 23346ab6bfe3SJack F Vogel goto release; 23354edd8523SJack F Vogel } 23364edd8523SJack F Vogel 23374edd8523SJack F Vogel /* Configure LCD from extended configuration region. */ 23384edd8523SJack F Vogel 23394edd8523SJack F Vogel /* cnf_base_addr is in DWORD */ 23404edd8523SJack F Vogel word_addr = (u16)(cnf_base_addr << 1); 23414edd8523SJack F Vogel 23424edd8523SJack F Vogel for (i = 0; i < cnf_size; i++) { 23434edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, 23444edd8523SJack F Vogel ®_data); 23454edd8523SJack F Vogel if (ret_val) 23466ab6bfe3SJack F Vogel goto release; 23474edd8523SJack F Vogel 23484edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), 23494edd8523SJack F Vogel 1, ®_addr); 23504edd8523SJack F Vogel if (ret_val) 23516ab6bfe3SJack F Vogel goto release; 23524edd8523SJack F Vogel 23534edd8523SJack F Vogel /* Save off the PHY page for future writes. */ 23544edd8523SJack F Vogel if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { 23554edd8523SJack F Vogel phy_page = reg_data; 23564edd8523SJack F Vogel continue; 23574edd8523SJack F Vogel } 23584edd8523SJack F Vogel 23594edd8523SJack F Vogel reg_addr &= PHY_REG_MASK; 23604edd8523SJack F Vogel reg_addr |= phy_page; 23614edd8523SJack F Vogel 23624edd8523SJack F Vogel ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, 23634edd8523SJack F Vogel reg_data); 23644edd8523SJack F Vogel if (ret_val) 23656ab6bfe3SJack F Vogel goto release; 23664edd8523SJack F Vogel } 23674edd8523SJack F Vogel 23686ab6bfe3SJack F Vogel release: 23694edd8523SJack F Vogel hw->phy.ops.release(hw); 23704edd8523SJack F Vogel return ret_val; 23714edd8523SJack F Vogel } 23724edd8523SJack F Vogel 23734edd8523SJack F Vogel /** 23744edd8523SJack F Vogel * e1000_k1_gig_workaround_hv - K1 Si workaround 23754edd8523SJack F Vogel * @hw: pointer to the HW structure 23764edd8523SJack F Vogel * @link: link up bool flag 23774edd8523SJack F Vogel * 23784edd8523SJack F Vogel * If K1 is enabled for 1Gbps, the MAC might stall when transitioning 23794edd8523SJack F Vogel * from a lower speed. This workaround disables K1 whenever link is at 1Gig 23804edd8523SJack F Vogel * If link is down, the function will restore the default K1 setting located 23814edd8523SJack F Vogel * in the NVM. 23824edd8523SJack F Vogel **/ 23834edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) 23844edd8523SJack F Vogel { 23854edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 23864edd8523SJack F Vogel u16 status_reg = 0; 23874edd8523SJack F Vogel bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; 23884edd8523SJack F Vogel 23894edd8523SJack F Vogel DEBUGFUNC("e1000_k1_gig_workaround_hv"); 23904edd8523SJack F Vogel 23914edd8523SJack F Vogel if (hw->mac.type != e1000_pchlan) 23926ab6bfe3SJack F Vogel return E1000_SUCCESS; 23934edd8523SJack F Vogel 23944edd8523SJack F Vogel /* Wrap the whole flow with the sw flag */ 23954edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 23964edd8523SJack F Vogel if (ret_val) 23976ab6bfe3SJack F Vogel return ret_val; 23984edd8523SJack F Vogel 23994edd8523SJack F Vogel /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ 24004edd8523SJack F Vogel if (link) { 24014edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) { 24024edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, 24034edd8523SJack F Vogel &status_reg); 24044edd8523SJack F Vogel if (ret_val) 24054edd8523SJack F Vogel goto release; 24064edd8523SJack F Vogel 24077609433eSJack F Vogel status_reg &= (BM_CS_STATUS_LINK_UP | 24084edd8523SJack F Vogel BM_CS_STATUS_RESOLVED | 24097609433eSJack F Vogel BM_CS_STATUS_SPEED_MASK); 24104edd8523SJack F Vogel 24114edd8523SJack F Vogel if (status_reg == (BM_CS_STATUS_LINK_UP | 24124edd8523SJack F Vogel BM_CS_STATUS_RESOLVED | 24134edd8523SJack F Vogel BM_CS_STATUS_SPEED_1000)) 24144edd8523SJack F Vogel k1_enable = FALSE; 24154edd8523SJack F Vogel } 24164edd8523SJack F Vogel 24174edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82577) { 24184edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, 24194edd8523SJack F Vogel &status_reg); 24204edd8523SJack F Vogel if (ret_val) 24214edd8523SJack F Vogel goto release; 24224edd8523SJack F Vogel 24237609433eSJack F Vogel status_reg &= (HV_M_STATUS_LINK_UP | 24244edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE | 24257609433eSJack F Vogel HV_M_STATUS_SPEED_MASK); 24264edd8523SJack F Vogel 24274edd8523SJack F Vogel if (status_reg == (HV_M_STATUS_LINK_UP | 24284edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE | 24294edd8523SJack F Vogel HV_M_STATUS_SPEED_1000)) 24304edd8523SJack F Vogel k1_enable = FALSE; 24314edd8523SJack F Vogel } 24324edd8523SJack F Vogel 24334edd8523SJack F Vogel /* Link stall fix for link up */ 24344edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), 24354edd8523SJack F Vogel 0x0100); 24364edd8523SJack F Vogel if (ret_val) 24374edd8523SJack F Vogel goto release; 24384edd8523SJack F Vogel 24394edd8523SJack F Vogel } else { 24404edd8523SJack F Vogel /* Link stall fix for link down */ 24414edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), 24424edd8523SJack F Vogel 0x4100); 24434edd8523SJack F Vogel if (ret_val) 24444edd8523SJack F Vogel goto release; 24454edd8523SJack F Vogel } 24464edd8523SJack F Vogel 24474edd8523SJack F Vogel ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); 24484edd8523SJack F Vogel 24494edd8523SJack F Vogel release: 24504edd8523SJack F Vogel hw->phy.ops.release(hw); 24516ab6bfe3SJack F Vogel 24524edd8523SJack F Vogel return ret_val; 24534edd8523SJack F Vogel } 24544edd8523SJack F Vogel 24554edd8523SJack F Vogel /** 24564edd8523SJack F Vogel * e1000_configure_k1_ich8lan - Configure K1 power state 24574edd8523SJack F Vogel * @hw: pointer to the HW structure 24584edd8523SJack F Vogel * @enable: K1 state to configure 24594edd8523SJack F Vogel * 24604edd8523SJack F Vogel * Configure the K1 power state based on the provided parameter. 24614edd8523SJack F Vogel * Assumes semaphore already acquired. 24624edd8523SJack F Vogel * 24634edd8523SJack F Vogel * Success returns 0, Failure returns -E1000_ERR_PHY (-2) 24644edd8523SJack F Vogel **/ 24654edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) 24664edd8523SJack F Vogel { 24676ab6bfe3SJack F Vogel s32 ret_val; 24684edd8523SJack F Vogel u32 ctrl_reg = 0; 24694edd8523SJack F Vogel u32 ctrl_ext = 0; 24704edd8523SJack F Vogel u32 reg = 0; 24714edd8523SJack F Vogel u16 kmrn_reg = 0; 24724edd8523SJack F Vogel 24737d9119bdSJack F Vogel DEBUGFUNC("e1000_configure_k1_ich8lan"); 24747d9119bdSJack F Vogel 24754dab5c37SJack F Vogel ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 24764edd8523SJack F Vogel &kmrn_reg); 24774edd8523SJack F Vogel if (ret_val) 24786ab6bfe3SJack F Vogel return ret_val; 24794edd8523SJack F Vogel 24804edd8523SJack F Vogel if (k1_enable) 24814edd8523SJack F Vogel kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; 24824edd8523SJack F Vogel else 24834edd8523SJack F Vogel kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; 24844edd8523SJack F Vogel 24854dab5c37SJack F Vogel ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 24864edd8523SJack F Vogel kmrn_reg); 24874edd8523SJack F Vogel if (ret_val) 24886ab6bfe3SJack F Vogel return ret_val; 24894edd8523SJack F Vogel 24904edd8523SJack F Vogel usec_delay(20); 24914edd8523SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 24924edd8523SJack F Vogel ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); 24934edd8523SJack F Vogel 24944edd8523SJack F Vogel reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); 24954edd8523SJack F Vogel reg |= E1000_CTRL_FRCSPD; 24964edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg); 24974edd8523SJack F Vogel 24984edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); 24994dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 25004edd8523SJack F Vogel usec_delay(20); 25014edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); 25024edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 25034dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 25044edd8523SJack F Vogel usec_delay(20); 25054edd8523SJack F Vogel 25066ab6bfe3SJack F Vogel return E1000_SUCCESS; 25074edd8523SJack F Vogel } 25084edd8523SJack F Vogel 25094edd8523SJack F Vogel /** 25104edd8523SJack F Vogel * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration 25114edd8523SJack F Vogel * @hw: pointer to the HW structure 25124edd8523SJack F Vogel * @d0_state: boolean if entering d0 or d3 device state 25134edd8523SJack F Vogel * 25144edd8523SJack F Vogel * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are 25154edd8523SJack F Vogel * collectively called OEM bits. The OEM Write Enable bit and SW Config bit 25164edd8523SJack F Vogel * in NVM determines whether HW should configure LPLU and Gbe Disable. 25174edd8523SJack F Vogel **/ 25184dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) 25194edd8523SJack F Vogel { 25204edd8523SJack F Vogel s32 ret_val = 0; 25214edd8523SJack F Vogel u32 mac_reg; 25224edd8523SJack F Vogel u16 oem_reg; 25234edd8523SJack F Vogel 25247d9119bdSJack F Vogel DEBUGFUNC("e1000_oem_bits_config_ich8lan"); 25257d9119bdSJack F Vogel 25266ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pchlan) 25274edd8523SJack F Vogel return ret_val; 25284edd8523SJack F Vogel 25294edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 25304edd8523SJack F Vogel if (ret_val) 25314edd8523SJack F Vogel return ret_val; 25324edd8523SJack F Vogel 25336ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pchlan) { 25344edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 25354edd8523SJack F Vogel if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) 25366ab6bfe3SJack F Vogel goto release; 25377d9119bdSJack F Vogel } 25384edd8523SJack F Vogel 25394edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM); 25404edd8523SJack F Vogel if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) 25416ab6bfe3SJack F Vogel goto release; 25424edd8523SJack F Vogel 25434edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 25444edd8523SJack F Vogel 25454edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); 25464edd8523SJack F Vogel if (ret_val) 25476ab6bfe3SJack F Vogel goto release; 25484edd8523SJack F Vogel 25494edd8523SJack F Vogel oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); 25504edd8523SJack F Vogel 25514edd8523SJack F Vogel if (d0_state) { 25524edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) 25534edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS; 25544edd8523SJack F Vogel 25554edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) 25564edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 25574dab5c37SJack F Vogel } else { 25584dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE | 25594dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE)) 25604dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS; 25614dab5c37SJack F Vogel 25624dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU | 25634dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU)) 25644dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 25654dab5c37SJack F Vogel } 25664dab5c37SJack F Vogel 25676ab6bfe3SJack F Vogel /* Set Restart auto-neg to activate the bits */ 25686ab6bfe3SJack F Vogel if ((d0_state || (hw->mac.type != e1000_pchlan)) && 25696ab6bfe3SJack F Vogel !hw->phy.ops.check_reset_block(hw)) 25706ab6bfe3SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN; 25716ab6bfe3SJack F Vogel 25724edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); 25734edd8523SJack F Vogel 25746ab6bfe3SJack F Vogel release: 25754edd8523SJack F Vogel hw->phy.ops.release(hw); 25764edd8523SJack F Vogel 25774edd8523SJack F Vogel return ret_val; 25784edd8523SJack F Vogel } 25794edd8523SJack F Vogel 25804edd8523SJack F Vogel 25814edd8523SJack F Vogel /** 2582a69ed8dfSJack F Vogel * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode 2583a69ed8dfSJack F Vogel * @hw: pointer to the HW structure 2584a69ed8dfSJack F Vogel **/ 2585a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw) 2586a69ed8dfSJack F Vogel { 2587a69ed8dfSJack F Vogel s32 ret_val; 2588a69ed8dfSJack F Vogel u16 data; 2589a69ed8dfSJack F Vogel 25907d9119bdSJack F Vogel DEBUGFUNC("e1000_set_mdio_slow_mode_hv"); 25917d9119bdSJack F Vogel 2592a69ed8dfSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data); 2593a69ed8dfSJack F Vogel if (ret_val) 2594a69ed8dfSJack F Vogel return ret_val; 2595a69ed8dfSJack F Vogel 2596a69ed8dfSJack F Vogel data |= HV_KMRN_MDIO_SLOW; 2597a69ed8dfSJack F Vogel 2598a69ed8dfSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data); 2599a69ed8dfSJack F Vogel 2600a69ed8dfSJack F Vogel return ret_val; 2601a69ed8dfSJack F Vogel } 2602a69ed8dfSJack F Vogel 2603a69ed8dfSJack F Vogel /** 26049d81738fSJack F Vogel * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be 26059d81738fSJack F Vogel * done after every PHY reset. 26069d81738fSJack F Vogel **/ 26079d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) 26089d81738fSJack F Vogel { 26099d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS; 2610a69ed8dfSJack F Vogel u16 phy_data; 26119d81738fSJack F Vogel 26127d9119bdSJack F Vogel DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan"); 26137d9119bdSJack F Vogel 26149d81738fSJack F Vogel if (hw->mac.type != e1000_pchlan) 26156ab6bfe3SJack F Vogel return E1000_SUCCESS; 26169d81738fSJack F Vogel 2617a69ed8dfSJack F Vogel /* Set MDIO slow mode before any other MDIO access */ 2618a69ed8dfSJack F Vogel if (hw->phy.type == e1000_phy_82577) { 2619a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 2620a69ed8dfSJack F Vogel if (ret_val) 26216ab6bfe3SJack F Vogel return ret_val; 2622a69ed8dfSJack F Vogel } 2623a69ed8dfSJack F Vogel 26249d81738fSJack F Vogel if (((hw->phy.type == e1000_phy_82577) && 26259d81738fSJack F Vogel ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || 26269d81738fSJack F Vogel ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { 26279d81738fSJack F Vogel /* Disable generation of early preamble */ 26289d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); 26299d81738fSJack F Vogel if (ret_val) 26306ab6bfe3SJack F Vogel return ret_val; 26319d81738fSJack F Vogel 26329d81738fSJack F Vogel /* Preamble tuning for SSC */ 26334dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, 26344dab5c37SJack F Vogel 0xA204); 26359d81738fSJack F Vogel if (ret_val) 26366ab6bfe3SJack F Vogel return ret_val; 26379d81738fSJack F Vogel } 26389d81738fSJack F Vogel 26399d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 26406ab6bfe3SJack F Vogel /* Return registers to default by doing a soft reset then 26419d81738fSJack F Vogel * writing 0x3140 to the control register. 26429d81738fSJack F Vogel */ 26439d81738fSJack F Vogel if (hw->phy.revision < 2) { 26449d81738fSJack F Vogel e1000_phy_sw_reset_generic(hw); 26459d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, 26469d81738fSJack F Vogel 0x3140); 26479d81738fSJack F Vogel } 26489d81738fSJack F Vogel } 26499d81738fSJack F Vogel 26509d81738fSJack F Vogel /* Select page 0 */ 26519d81738fSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 26529d81738fSJack F Vogel if (ret_val) 26536ab6bfe3SJack F Vogel return ret_val; 26544edd8523SJack F Vogel 26559d81738fSJack F Vogel hw->phy.addr = 1; 26564edd8523SJack F Vogel ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); 2657a69ed8dfSJack F Vogel hw->phy.ops.release(hw); 26584edd8523SJack F Vogel if (ret_val) 26596ab6bfe3SJack F Vogel return ret_val; 26609d81738fSJack F Vogel 26616ab6bfe3SJack F Vogel /* Configure the K1 Si workaround during phy reset assuming there is 26624edd8523SJack F Vogel * link so that it disables K1 if link is in 1Gbps. 26634edd8523SJack F Vogel */ 26644edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, TRUE); 2665a69ed8dfSJack F Vogel if (ret_val) 26666ab6bfe3SJack F Vogel return ret_val; 26674edd8523SJack F Vogel 2668a69ed8dfSJack F Vogel /* Workaround for link disconnects on a busy hub in half duplex */ 2669a69ed8dfSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 2670a69ed8dfSJack F Vogel if (ret_val) 26716ab6bfe3SJack F Vogel return ret_val; 26724dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data); 2673a69ed8dfSJack F Vogel if (ret_val) 2674a69ed8dfSJack F Vogel goto release; 26754dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG, 2676a69ed8dfSJack F Vogel phy_data & 0x00FF); 26776ab6bfe3SJack F Vogel if (ret_val) 26786ab6bfe3SJack F Vogel goto release; 26796ab6bfe3SJack F Vogel 26806ab6bfe3SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */ 26816ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034); 2682a69ed8dfSJack F Vogel release: 2683a69ed8dfSJack F Vogel hw->phy.ops.release(hw); 26846ab6bfe3SJack F Vogel 26859d81738fSJack F Vogel return ret_val; 26869d81738fSJack F Vogel } 26879d81738fSJack F Vogel 26889d81738fSJack F Vogel /** 26897d9119bdSJack F Vogel * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY 26907d9119bdSJack F Vogel * @hw: pointer to the HW structure 26917d9119bdSJack F Vogel **/ 26927d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw) 26937d9119bdSJack F Vogel { 26947d9119bdSJack F Vogel u32 mac_reg; 26954dab5c37SJack F Vogel u16 i, phy_reg = 0; 26964dab5c37SJack F Vogel s32 ret_val; 26977d9119bdSJack F Vogel 26987d9119bdSJack F Vogel DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan"); 26997d9119bdSJack F Vogel 27004dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 27014dab5c37SJack F Vogel if (ret_val) 27024dab5c37SJack F Vogel return; 27034dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 27044dab5c37SJack F Vogel if (ret_val) 27054dab5c37SJack F Vogel goto release; 27064dab5c37SJack F Vogel 27077609433eSJack F Vogel /* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */ 27087609433eSJack F Vogel for (i = 0; i < (hw->mac.rar_entry_count); i++) { 27097d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAL(i)); 27104dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_L(i), 27114dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF)); 27124dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_M(i), 27134dab5c37SJack F Vogel (u16)((mac_reg >> 16) & 0xFFFF)); 27144dab5c37SJack F Vogel 27157d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAH(i)); 27164dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_H(i), 27174dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF)); 27184dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i), 27194dab5c37SJack F Vogel (u16)((mac_reg & E1000_RAH_AV) 27204dab5c37SJack F Vogel >> 16)); 27217d9119bdSJack F Vogel } 27224dab5c37SJack F Vogel 27234dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 27244dab5c37SJack F Vogel 27254dab5c37SJack F Vogel release: 27264dab5c37SJack F Vogel hw->phy.ops.release(hw); 27277d9119bdSJack F Vogel } 27287d9119bdSJack F Vogel 27297d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[]) 27307d9119bdSJack F Vogel { 27317d9119bdSJack F Vogel u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */ 27327d9119bdSJack F Vogel u32 i, j, mask, crc; 27337d9119bdSJack F Vogel 27347d9119bdSJack F Vogel DEBUGFUNC("e1000_calc_rx_da_crc"); 27357d9119bdSJack F Vogel 27367d9119bdSJack F Vogel crc = 0xffffffff; 27377d9119bdSJack F Vogel for (i = 0; i < 6; i++) { 27387d9119bdSJack F Vogel crc = crc ^ mac[i]; 27397d9119bdSJack F Vogel for (j = 8; j > 0; j--) { 27407d9119bdSJack F Vogel mask = (crc & 1) * (-1); 27417d9119bdSJack F Vogel crc = (crc >> 1) ^ (poly & mask); 27427d9119bdSJack F Vogel } 27437d9119bdSJack F Vogel } 27447d9119bdSJack F Vogel return ~crc; 27457d9119bdSJack F Vogel } 27467d9119bdSJack F Vogel 27477d9119bdSJack F Vogel /** 27487d9119bdSJack F Vogel * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation 27497d9119bdSJack F Vogel * with 82579 PHY 27507d9119bdSJack F Vogel * @hw: pointer to the HW structure 27517d9119bdSJack F Vogel * @enable: flag to enable/disable workaround when enabling/disabling jumbos 27527d9119bdSJack F Vogel **/ 27537d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) 27547d9119bdSJack F Vogel { 27557d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 27567d9119bdSJack F Vogel u16 phy_reg, data; 27577d9119bdSJack F Vogel u32 mac_reg; 27587d9119bdSJack F Vogel u16 i; 27597d9119bdSJack F Vogel 27607d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan"); 27617d9119bdSJack F Vogel 27626ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan) 27636ab6bfe3SJack F Vogel return E1000_SUCCESS; 27647d9119bdSJack F Vogel 27657d9119bdSJack F Vogel /* disable Rx path while enabling/disabling workaround */ 27667d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); 27674dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), 27684dab5c37SJack F Vogel phy_reg | (1 << 14)); 27697d9119bdSJack F Vogel if (ret_val) 27706ab6bfe3SJack F Vogel return ret_val; 27717d9119bdSJack F Vogel 27727d9119bdSJack F Vogel if (enable) { 27737609433eSJack F Vogel /* Write Rx addresses (rar_entry_count for RAL/H, and 27747d9119bdSJack F Vogel * SHRAL/H) and initial CRC values to the MAC 27757d9119bdSJack F Vogel */ 27767609433eSJack F Vogel for (i = 0; i < hw->mac.rar_entry_count; i++) { 27777d9119bdSJack F Vogel u8 mac_addr[ETH_ADDR_LEN] = {0}; 27787d9119bdSJack F Vogel u32 addr_high, addr_low; 27797d9119bdSJack F Vogel 27807d9119bdSJack F Vogel addr_high = E1000_READ_REG(hw, E1000_RAH(i)); 27817d9119bdSJack F Vogel if (!(addr_high & E1000_RAH_AV)) 27827d9119bdSJack F Vogel continue; 27837d9119bdSJack F Vogel addr_low = E1000_READ_REG(hw, E1000_RAL(i)); 27847d9119bdSJack F Vogel mac_addr[0] = (addr_low & 0xFF); 27857d9119bdSJack F Vogel mac_addr[1] = ((addr_low >> 8) & 0xFF); 27867d9119bdSJack F Vogel mac_addr[2] = ((addr_low >> 16) & 0xFF); 27877d9119bdSJack F Vogel mac_addr[3] = ((addr_low >> 24) & 0xFF); 27887d9119bdSJack F Vogel mac_addr[4] = (addr_high & 0xFF); 27897d9119bdSJack F Vogel mac_addr[5] = ((addr_high >> 8) & 0xFF); 27907d9119bdSJack F Vogel 27917d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_PCH_RAICC(i), 27927d9119bdSJack F Vogel e1000_calc_rx_da_crc(mac_addr)); 27937d9119bdSJack F Vogel } 27947d9119bdSJack F Vogel 27957d9119bdSJack F Vogel /* Write Rx addresses to the PHY */ 27967d9119bdSJack F Vogel e1000_copy_rx_addrs_to_phy_ich8lan(hw); 27977d9119bdSJack F Vogel 27987d9119bdSJack F Vogel /* Enable jumbo frame workaround in the MAC */ 27997d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); 28007d9119bdSJack F Vogel mac_reg &= ~(1 << 14); 28017d9119bdSJack F Vogel mac_reg |= (7 << 15); 28027d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); 28037d9119bdSJack F Vogel 28047d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL); 28057d9119bdSJack F Vogel mac_reg |= E1000_RCTL_SECRC; 28067d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); 28077d9119bdSJack F Vogel 28087d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 28097d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 28107d9119bdSJack F Vogel &data); 28117d9119bdSJack F Vogel if (ret_val) 28126ab6bfe3SJack F Vogel return ret_val; 28137d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 28147d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 28157d9119bdSJack F Vogel data | (1 << 0)); 28167d9119bdSJack F Vogel if (ret_val) 28176ab6bfe3SJack F Vogel return ret_val; 28187d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 28197d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 28207d9119bdSJack F Vogel &data); 28217d9119bdSJack F Vogel if (ret_val) 28226ab6bfe3SJack F Vogel return ret_val; 28237d9119bdSJack F Vogel data &= ~(0xF << 8); 28247d9119bdSJack F Vogel data |= (0xB << 8); 28257d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 28267d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 28277d9119bdSJack F Vogel data); 28287d9119bdSJack F Vogel if (ret_val) 28296ab6bfe3SJack F Vogel return ret_val; 28307d9119bdSJack F Vogel 28317d9119bdSJack F Vogel /* Enable jumbo frame workaround in the PHY */ 28327d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); 28337d9119bdSJack F Vogel data &= ~(0x7F << 5); 28347d9119bdSJack F Vogel data |= (0x37 << 5); 28357d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); 28367d9119bdSJack F Vogel if (ret_val) 28376ab6bfe3SJack F Vogel return ret_val; 28387d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); 28397d9119bdSJack F Vogel data &= ~(1 << 13); 28407d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); 28417d9119bdSJack F Vogel if (ret_val) 28426ab6bfe3SJack F Vogel return ret_val; 28437d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); 28447d9119bdSJack F Vogel data &= ~(0x3FF << 2); 28458cc64f1eSJack F Vogel data |= (E1000_TX_PTR_GAP << 2); 28467d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); 28477d9119bdSJack F Vogel if (ret_val) 28486ab6bfe3SJack F Vogel return ret_val; 28494dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100); 28507d9119bdSJack F Vogel if (ret_val) 28516ab6bfe3SJack F Vogel return ret_val; 28527d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); 28534dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | 28544dab5c37SJack F Vogel (1 << 10)); 28557d9119bdSJack F Vogel if (ret_val) 28566ab6bfe3SJack F Vogel return ret_val; 28577d9119bdSJack F Vogel } else { 28587d9119bdSJack F Vogel /* Write MAC register values back to h/w defaults */ 28597d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); 28607d9119bdSJack F Vogel mac_reg &= ~(0xF << 14); 28617d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); 28627d9119bdSJack F Vogel 28637d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL); 28647d9119bdSJack F Vogel mac_reg &= ~E1000_RCTL_SECRC; 28657d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); 28667d9119bdSJack F Vogel 28677d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 28687d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 28697d9119bdSJack F Vogel &data); 28707d9119bdSJack F Vogel if (ret_val) 28716ab6bfe3SJack F Vogel return ret_val; 28727d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 28737d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 28747d9119bdSJack F Vogel data & ~(1 << 0)); 28757d9119bdSJack F Vogel if (ret_val) 28766ab6bfe3SJack F Vogel return ret_val; 28777d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 28787d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 28797d9119bdSJack F Vogel &data); 28807d9119bdSJack F Vogel if (ret_val) 28816ab6bfe3SJack F Vogel return ret_val; 28827d9119bdSJack F Vogel data &= ~(0xF << 8); 28837d9119bdSJack F Vogel data |= (0xB << 8); 28847d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 28857d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 28867d9119bdSJack F Vogel data); 28877d9119bdSJack F Vogel if (ret_val) 28886ab6bfe3SJack F Vogel return ret_val; 28897d9119bdSJack F Vogel 28907d9119bdSJack F Vogel /* Write PHY register values back to h/w defaults */ 28917d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); 28927d9119bdSJack F Vogel data &= ~(0x7F << 5); 28937d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); 28947d9119bdSJack F Vogel if (ret_val) 28956ab6bfe3SJack F Vogel return ret_val; 28967d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); 28977d9119bdSJack F Vogel data |= (1 << 13); 28987d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); 28997d9119bdSJack F Vogel if (ret_val) 29006ab6bfe3SJack F Vogel return ret_val; 29017d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); 29027d9119bdSJack F Vogel data &= ~(0x3FF << 2); 29037d9119bdSJack F Vogel data |= (0x8 << 2); 29047d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); 29057d9119bdSJack F Vogel if (ret_val) 29066ab6bfe3SJack F Vogel return ret_val; 29077d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00); 29087d9119bdSJack F Vogel if (ret_val) 29096ab6bfe3SJack F Vogel return ret_val; 29107d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); 29114dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & 29124dab5c37SJack F Vogel ~(1 << 10)); 29137d9119bdSJack F Vogel if (ret_val) 29146ab6bfe3SJack F Vogel return ret_val; 29157d9119bdSJack F Vogel } 29167d9119bdSJack F Vogel 29177d9119bdSJack F Vogel /* re-enable Rx path after enabling/disabling workaround */ 29186ab6bfe3SJack F Vogel return hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & 29194dab5c37SJack F Vogel ~(1 << 14)); 29207d9119bdSJack F Vogel } 29217d9119bdSJack F Vogel 29227d9119bdSJack F Vogel /** 29237d9119bdSJack F Vogel * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be 29247d9119bdSJack F Vogel * done after every PHY reset. 29257d9119bdSJack F Vogel **/ 29267d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) 29277d9119bdSJack F Vogel { 29287d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 29297d9119bdSJack F Vogel 29307d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan"); 29317d9119bdSJack F Vogel 29327d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 29336ab6bfe3SJack F Vogel return E1000_SUCCESS; 29347d9119bdSJack F Vogel 29357d9119bdSJack F Vogel /* Set MDIO slow mode before any other MDIO access */ 29367d9119bdSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 29376ab6bfe3SJack F Vogel if (ret_val) 29386ab6bfe3SJack F Vogel return ret_val; 29397d9119bdSJack F Vogel 29404dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 29414dab5c37SJack F Vogel if (ret_val) 29426ab6bfe3SJack F Vogel return ret_val; 29434dab5c37SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */ 29446ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034); 29454dab5c37SJack F Vogel if (ret_val) 29464dab5c37SJack F Vogel goto release; 29474dab5c37SJack F Vogel /* drop link after 5 times MSE threshold was reached */ 29486ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005); 29494dab5c37SJack F Vogel release: 29504dab5c37SJack F Vogel hw->phy.ops.release(hw); 29514dab5c37SJack F Vogel 29527d9119bdSJack F Vogel return ret_val; 29537d9119bdSJack F Vogel } 29547d9119bdSJack F Vogel 29557d9119bdSJack F Vogel /** 29567d9119bdSJack F Vogel * e1000_k1_gig_workaround_lv - K1 Si workaround 29577d9119bdSJack F Vogel * @hw: pointer to the HW structure 29587d9119bdSJack F Vogel * 29598cc64f1eSJack F Vogel * Workaround to set the K1 beacon duration for 82579 parts in 10Mbps 29608cc64f1eSJack F Vogel * Disable K1 for 1000 and 100 speeds 29617d9119bdSJack F Vogel **/ 29627d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw) 29637d9119bdSJack F Vogel { 29647d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 29657d9119bdSJack F Vogel u16 status_reg = 0; 29667d9119bdSJack F Vogel 29677d9119bdSJack F Vogel DEBUGFUNC("e1000_k1_workaround_lv"); 29687d9119bdSJack F Vogel 29697d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 29706ab6bfe3SJack F Vogel return E1000_SUCCESS; 29717d9119bdSJack F Vogel 29728cc64f1eSJack F Vogel /* Set K1 beacon duration based on 10Mbs speed */ 29737d9119bdSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg); 29747d9119bdSJack F Vogel if (ret_val) 29756ab6bfe3SJack F Vogel return ret_val; 29767d9119bdSJack F Vogel 29777d9119bdSJack F Vogel if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) 29787d9119bdSJack F Vogel == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) { 29798cc64f1eSJack F Vogel if (status_reg & 29808cc64f1eSJack F Vogel (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) { 29816ab6bfe3SJack F Vogel u16 pm_phy_reg; 29826ab6bfe3SJack F Vogel 29838cc64f1eSJack F Vogel /* LV 1G/100 Packet drop issue wa */ 29846ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_PM_CTRL, 29856ab6bfe3SJack F Vogel &pm_phy_reg); 29866ab6bfe3SJack F Vogel if (ret_val) 29876ab6bfe3SJack F Vogel return ret_val; 29888cc64f1eSJack F Vogel pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE; 29896ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, 29906ab6bfe3SJack F Vogel pm_phy_reg); 29916ab6bfe3SJack F Vogel if (ret_val) 29926ab6bfe3SJack F Vogel return ret_val; 29934dab5c37SJack F Vogel } else { 29948cc64f1eSJack F Vogel u32 mac_reg; 29958cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); 29968cc64f1eSJack F Vogel mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 29974dab5c37SJack F Vogel mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC; 29987d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg); 29998cc64f1eSJack F Vogel } 30007d9119bdSJack F Vogel } 30017d9119bdSJack F Vogel 30027d9119bdSJack F Vogel return ret_val; 30037d9119bdSJack F Vogel } 30047d9119bdSJack F Vogel 30057d9119bdSJack F Vogel /** 30067d9119bdSJack F Vogel * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware 30077d9119bdSJack F Vogel * @hw: pointer to the HW structure 3008730d3130SJack F Vogel * @gate: boolean set to TRUE to gate, FALSE to ungate 30097d9119bdSJack F Vogel * 30107d9119bdSJack F Vogel * Gate/ungate the automatic PHY configuration via hardware; perform 30117d9119bdSJack F Vogel * the configuration via software instead. 30127d9119bdSJack F Vogel **/ 30137d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate) 30147d9119bdSJack F Vogel { 30157d9119bdSJack F Vogel u32 extcnf_ctrl; 30167d9119bdSJack F Vogel 30177d9119bdSJack F Vogel DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan"); 30187d9119bdSJack F Vogel 30196ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan) 30207d9119bdSJack F Vogel return; 30217d9119bdSJack F Vogel 30227d9119bdSJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 30237d9119bdSJack F Vogel 30247d9119bdSJack F Vogel if (gate) 30257d9119bdSJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; 30267d9119bdSJack F Vogel else 30277d9119bdSJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG; 30287d9119bdSJack F Vogel 30297d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 30307d9119bdSJack F Vogel } 30317d9119bdSJack F Vogel 30327d9119bdSJack F Vogel /** 30339d81738fSJack F Vogel * e1000_lan_init_done_ich8lan - Check for PHY config completion 30348cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 30358cfa0ad2SJack F Vogel * 30369d81738fSJack F Vogel * Check the appropriate indication the MAC has finished configuring the 30379d81738fSJack F Vogel * PHY after a software reset. 30388cfa0ad2SJack F Vogel **/ 30399d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) 30408cfa0ad2SJack F Vogel { 30419d81738fSJack F Vogel u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; 30428cfa0ad2SJack F Vogel 30439d81738fSJack F Vogel DEBUGFUNC("e1000_lan_init_done_ich8lan"); 30448cfa0ad2SJack F Vogel 30459d81738fSJack F Vogel /* Wait for basic configuration completes before proceeding */ 30469d81738fSJack F Vogel do { 30479d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 30489d81738fSJack F Vogel data &= E1000_STATUS_LAN_INIT_DONE; 30499d81738fSJack F Vogel usec_delay(100); 30509d81738fSJack F Vogel } while ((!data) && --loop); 30518cfa0ad2SJack F Vogel 30526ab6bfe3SJack F Vogel /* If basic configuration is incomplete before the above loop 30539d81738fSJack F Vogel * count reaches 0, loading the configuration from NVM will 30549d81738fSJack F Vogel * leave the PHY in a bad state possibly resulting in no link. 30559d81738fSJack F Vogel */ 30569d81738fSJack F Vogel if (loop == 0) 30579d81738fSJack F Vogel DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); 30588cfa0ad2SJack F Vogel 30599d81738fSJack F Vogel /* Clear the Init Done bit for the next init event */ 30609d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 30619d81738fSJack F Vogel data &= ~E1000_STATUS_LAN_INIT_DONE; 30629d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, data); 30638cfa0ad2SJack F Vogel } 30648cfa0ad2SJack F Vogel 30658cfa0ad2SJack F Vogel /** 30667d9119bdSJack F Vogel * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset 30677d9119bdSJack F Vogel * @hw: pointer to the HW structure 30687d9119bdSJack F Vogel **/ 30697d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) 30707d9119bdSJack F Vogel { 30717d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 30727d9119bdSJack F Vogel u16 reg; 30737d9119bdSJack F Vogel 30747d9119bdSJack F Vogel DEBUGFUNC("e1000_post_phy_reset_ich8lan"); 30757d9119bdSJack F Vogel 30767d9119bdSJack F Vogel if (hw->phy.ops.check_reset_block(hw)) 30776ab6bfe3SJack F Vogel return E1000_SUCCESS; 30787d9119bdSJack F Vogel 30797d9119bdSJack F Vogel /* Allow time for h/w to get to quiescent state after reset */ 30807d9119bdSJack F Vogel msec_delay(10); 30817d9119bdSJack F Vogel 30827d9119bdSJack F Vogel /* Perform any necessary post-reset workarounds */ 30837d9119bdSJack F Vogel switch (hw->mac.type) { 30847d9119bdSJack F Vogel case e1000_pchlan: 30857d9119bdSJack F Vogel ret_val = e1000_hv_phy_workarounds_ich8lan(hw); 30867d9119bdSJack F Vogel if (ret_val) 30876ab6bfe3SJack F Vogel return ret_val; 30887d9119bdSJack F Vogel break; 30897d9119bdSJack F Vogel case e1000_pch2lan: 30907d9119bdSJack F Vogel ret_val = e1000_lv_phy_workarounds_ich8lan(hw); 30917d9119bdSJack F Vogel if (ret_val) 30926ab6bfe3SJack F Vogel return ret_val; 30937d9119bdSJack F Vogel break; 30947d9119bdSJack F Vogel default: 30957d9119bdSJack F Vogel break; 30967d9119bdSJack F Vogel } 30977d9119bdSJack F Vogel 30984dab5c37SJack F Vogel /* Clear the host wakeup bit after lcd reset */ 30994dab5c37SJack F Vogel if (hw->mac.type >= e1000_pchlan) { 31004dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, ®); 31014dab5c37SJack F Vogel reg &= ~BM_WUC_HOST_WU_BIT; 31024dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg); 31037d9119bdSJack F Vogel } 31047d9119bdSJack F Vogel 31057d9119bdSJack F Vogel /* Configure the LCD with the extended configuration region in NVM */ 31067d9119bdSJack F Vogel ret_val = e1000_sw_lcd_config_ich8lan(hw); 31077d9119bdSJack F Vogel if (ret_val) 31086ab6bfe3SJack F Vogel return ret_val; 31097d9119bdSJack F Vogel 31107d9119bdSJack F Vogel /* Configure the LCD with the OEM bits in NVM */ 31117d9119bdSJack F Vogel ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); 31127d9119bdSJack F Vogel 3113730d3130SJack F Vogel if (hw->mac.type == e1000_pch2lan) { 31147d9119bdSJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */ 3115730d3130SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 3116730d3130SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 31177d9119bdSJack F Vogel msec_delay(10); 31187d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, FALSE); 31197d9119bdSJack F Vogel } 31207d9119bdSJack F Vogel 3121730d3130SJack F Vogel /* Set EEE LPI Update Timer to 200usec */ 3122730d3130SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 3123730d3130SJack F Vogel if (ret_val) 31246ab6bfe3SJack F Vogel return ret_val; 31256ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, 31266ab6bfe3SJack F Vogel I82579_LPI_UPDATE_TIMER, 3127730d3130SJack F Vogel 0x1387); 3128730d3130SJack F Vogel hw->phy.ops.release(hw); 3129730d3130SJack F Vogel } 3130730d3130SJack F Vogel 31317d9119bdSJack F Vogel return ret_val; 31327d9119bdSJack F Vogel } 31337d9119bdSJack F Vogel 31347d9119bdSJack F Vogel /** 31358cfa0ad2SJack F Vogel * e1000_phy_hw_reset_ich8lan - Performs a PHY reset 31368cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 31378cfa0ad2SJack F Vogel * 31388cfa0ad2SJack F Vogel * Resets the PHY 31398cfa0ad2SJack F Vogel * This is a function pointer entry point called by drivers 31408cfa0ad2SJack F Vogel * or other shared routines. 31418cfa0ad2SJack F Vogel **/ 31428cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) 31438cfa0ad2SJack F Vogel { 31444edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 31458cfa0ad2SJack F Vogel 31468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); 31478cfa0ad2SJack F Vogel 31487d9119bdSJack F Vogel /* Gate automatic PHY configuration by hardware on non-managed 82579 */ 31497d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 31507d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 31517d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 31527d9119bdSJack F Vogel 31538cfa0ad2SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 31548cfa0ad2SJack F Vogel if (ret_val) 31558cfa0ad2SJack F Vogel return ret_val; 31566ab6bfe3SJack F Vogel 31576ab6bfe3SJack F Vogel return e1000_post_phy_reset_ich8lan(hw); 31588cfa0ad2SJack F Vogel } 31598cfa0ad2SJack F Vogel 31608cfa0ad2SJack F Vogel /** 31614edd8523SJack F Vogel * e1000_set_lplu_state_pchlan - Set Low Power Link Up state 31628cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 31634edd8523SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 31648cfa0ad2SJack F Vogel * 31654edd8523SJack F Vogel * Sets the LPLU state according to the active flag. For PCH, if OEM write 31664edd8523SJack F Vogel * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set 31674edd8523SJack F Vogel * the phy speed. This function will manually set the LPLU bit and restart 31684edd8523SJack F Vogel * auto-neg as hw would do. D3 and D0 LPLU will call the same function 31694edd8523SJack F Vogel * since it configures the same bit. 31708cfa0ad2SJack F Vogel **/ 31714edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) 31728cfa0ad2SJack F Vogel { 31736ab6bfe3SJack F Vogel s32 ret_val; 31744edd8523SJack F Vogel u16 oem_reg; 31758cfa0ad2SJack F Vogel 31764edd8523SJack F Vogel DEBUGFUNC("e1000_set_lplu_state_pchlan"); 31774edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg); 31788cfa0ad2SJack F Vogel if (ret_val) 31796ab6bfe3SJack F Vogel return ret_val; 31808cfa0ad2SJack F Vogel 31814edd8523SJack F Vogel if (active) 31824edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 31834edd8523SJack F Vogel else 31844edd8523SJack F Vogel oem_reg &= ~HV_OEM_BITS_LPLU; 31858cfa0ad2SJack F Vogel 31864dab5c37SJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) 31874edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN; 31884dab5c37SJack F Vogel 31896ab6bfe3SJack F Vogel return hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg); 31908cfa0ad2SJack F Vogel } 31918cfa0ad2SJack F Vogel 31928cfa0ad2SJack F Vogel /** 31938cfa0ad2SJack F Vogel * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state 31948cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 31958cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 31968cfa0ad2SJack F Vogel * 31978cfa0ad2SJack F Vogel * Sets the LPLU D0 state according to the active flag. When 31988cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 31998cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 32008cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 32018cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 32028cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 32038cfa0ad2SJack F Vogel * PHY setup routines. 32048cfa0ad2SJack F Vogel **/ 3205daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 32068cfa0ad2SJack F Vogel { 32078cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 32088cfa0ad2SJack F Vogel u32 phy_ctrl; 32098cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 32108cfa0ad2SJack F Vogel u16 data; 32118cfa0ad2SJack F Vogel 32128cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); 32138cfa0ad2SJack F Vogel 32148cfa0ad2SJack F Vogel if (phy->type == e1000_phy_ife) 32156ab6bfe3SJack F Vogel return E1000_SUCCESS; 32168cfa0ad2SJack F Vogel 32178cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 32188cfa0ad2SJack F Vogel 32198cfa0ad2SJack F Vogel if (active) { 32208cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; 32218cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 32228cfa0ad2SJack F Vogel 32239d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 32246ab6bfe3SJack F Vogel return E1000_SUCCESS; 32259d81738fSJack F Vogel 32266ab6bfe3SJack F Vogel /* Call gig speed drop workaround on LPLU before accessing 32278cfa0ad2SJack F Vogel * any PHY registers 32288cfa0ad2SJack F Vogel */ 32299d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 32308cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 32318cfa0ad2SJack F Vogel 32328cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 32338cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 32348cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 32358cfa0ad2SJack F Vogel &data); 32366ab6bfe3SJack F Vogel if (ret_val) 32376ab6bfe3SJack F Vogel return ret_val; 32388cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 32398cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 32408cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 32418cfa0ad2SJack F Vogel data); 32428cfa0ad2SJack F Vogel if (ret_val) 32436ab6bfe3SJack F Vogel return ret_val; 32448cfa0ad2SJack F Vogel } else { 32458cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; 32468cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 32478cfa0ad2SJack F Vogel 32489d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 32496ab6bfe3SJack F Vogel return E1000_SUCCESS; 32509d81738fSJack F Vogel 32516ab6bfe3SJack F Vogel /* LPLU and SmartSpeed are mutually exclusive. LPLU is used 32528cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 32538cfa0ad2SJack F Vogel * important. During driver activity we should enable 32548cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 32558cfa0ad2SJack F Vogel */ 32568cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 32578cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 32588cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 32598cfa0ad2SJack F Vogel &data); 32608cfa0ad2SJack F Vogel if (ret_val) 32616ab6bfe3SJack F Vogel return ret_val; 32628cfa0ad2SJack F Vogel 32638cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 32648cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 32658cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 32668cfa0ad2SJack F Vogel data); 32678cfa0ad2SJack F Vogel if (ret_val) 32686ab6bfe3SJack F Vogel return ret_val; 32698cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 32708cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 32718cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 32728cfa0ad2SJack F Vogel &data); 32738cfa0ad2SJack F Vogel if (ret_val) 32746ab6bfe3SJack F Vogel return ret_val; 32758cfa0ad2SJack F Vogel 32768cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 32778cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 32788cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 32798cfa0ad2SJack F Vogel data); 32808cfa0ad2SJack F Vogel if (ret_val) 32816ab6bfe3SJack F Vogel return ret_val; 32828cfa0ad2SJack F Vogel } 32838cfa0ad2SJack F Vogel } 32848cfa0ad2SJack F Vogel 32856ab6bfe3SJack F Vogel return E1000_SUCCESS; 32868cfa0ad2SJack F Vogel } 32878cfa0ad2SJack F Vogel 32888cfa0ad2SJack F Vogel /** 32898cfa0ad2SJack F Vogel * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state 32908cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 32918cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 32928cfa0ad2SJack F Vogel * 32938cfa0ad2SJack F Vogel * Sets the LPLU D3 state according to the active flag. When 32948cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 32958cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 32968cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 32978cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 32988cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 32998cfa0ad2SJack F Vogel * PHY setup routines. 33008cfa0ad2SJack F Vogel **/ 3301daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 33028cfa0ad2SJack F Vogel { 33038cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 33048cfa0ad2SJack F Vogel u32 phy_ctrl; 33058cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 33068cfa0ad2SJack F Vogel u16 data; 33078cfa0ad2SJack F Vogel 33088cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan"); 33098cfa0ad2SJack F Vogel 33108cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 33118cfa0ad2SJack F Vogel 33128cfa0ad2SJack F Vogel if (!active) { 33138cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; 33148cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 33159d81738fSJack F Vogel 33169d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 33176ab6bfe3SJack F Vogel return E1000_SUCCESS; 33189d81738fSJack F Vogel 33196ab6bfe3SJack F Vogel /* LPLU and SmartSpeed are mutually exclusive. LPLU is used 33208cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 33218cfa0ad2SJack F Vogel * important. During driver activity we should enable 33228cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 33238cfa0ad2SJack F Vogel */ 33248cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 33258cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 33268cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33278cfa0ad2SJack F Vogel &data); 33288cfa0ad2SJack F Vogel if (ret_val) 33296ab6bfe3SJack F Vogel return ret_val; 33308cfa0ad2SJack F Vogel 33318cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 33328cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 33338cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33348cfa0ad2SJack F Vogel data); 33358cfa0ad2SJack F Vogel if (ret_val) 33366ab6bfe3SJack F Vogel return ret_val; 33378cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 33388cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 33398cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33408cfa0ad2SJack F Vogel &data); 33418cfa0ad2SJack F Vogel if (ret_val) 33426ab6bfe3SJack F Vogel return ret_val; 33438cfa0ad2SJack F Vogel 33448cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 33458cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 33468cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33478cfa0ad2SJack F Vogel data); 33488cfa0ad2SJack F Vogel if (ret_val) 33496ab6bfe3SJack F Vogel return ret_val; 33508cfa0ad2SJack F Vogel } 33518cfa0ad2SJack F Vogel } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 33528cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 33538cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 33548cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; 33558cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 33568cfa0ad2SJack F Vogel 33579d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 33586ab6bfe3SJack F Vogel return E1000_SUCCESS; 33599d81738fSJack F Vogel 33606ab6bfe3SJack F Vogel /* Call gig speed drop workaround on LPLU before accessing 33618cfa0ad2SJack F Vogel * any PHY registers 33628cfa0ad2SJack F Vogel */ 33639d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 33648cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 33658cfa0ad2SJack F Vogel 33668cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 33678cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 33688cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33698cfa0ad2SJack F Vogel &data); 33708cfa0ad2SJack F Vogel if (ret_val) 33716ab6bfe3SJack F Vogel return ret_val; 33728cfa0ad2SJack F Vogel 33738cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 33748cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 33758cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33768cfa0ad2SJack F Vogel data); 33778cfa0ad2SJack F Vogel } 33788cfa0ad2SJack F Vogel 33798cfa0ad2SJack F Vogel return ret_val; 33808cfa0ad2SJack F Vogel } 33818cfa0ad2SJack F Vogel 33828cfa0ad2SJack F Vogel /** 33838cfa0ad2SJack F Vogel * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 33848cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 33858cfa0ad2SJack F Vogel * @bank: pointer to the variable that returns the active bank 33868cfa0ad2SJack F Vogel * 33878cfa0ad2SJack F Vogel * Reads signature byte from the NVM using the flash access registers. 3388d035aa2dSJack F Vogel * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. 33898cfa0ad2SJack F Vogel **/ 33908cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) 33918cfa0ad2SJack F Vogel { 3392d035aa2dSJack F Vogel u32 eecd; 33938cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 33948cfa0ad2SJack F Vogel u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); 33958cfa0ad2SJack F Vogel u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; 3396*c80429ceSEric Joyner u32 nvm_dword = 0; 3397d035aa2dSJack F Vogel u8 sig_byte = 0; 33986ab6bfe3SJack F Vogel s32 ret_val; 33998cfa0ad2SJack F Vogel 34007d9119bdSJack F Vogel DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan"); 34017d9119bdSJack F Vogel 3402d035aa2dSJack F Vogel switch (hw->mac.type) { 3403*c80429ceSEric Joyner case e1000_pch_spt: 3404*c80429ceSEric Joyner bank1_offset = nvm->flash_bank_size; 3405*c80429ceSEric Joyner act_offset = E1000_ICH_NVM_SIG_WORD; 3406*c80429ceSEric Joyner 3407*c80429ceSEric Joyner /* set bank to 0 in case flash read fails */ 3408*c80429ceSEric Joyner *bank = 0; 3409*c80429ceSEric Joyner 3410*c80429ceSEric Joyner /* Check bank 0 */ 3411*c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, 3412*c80429ceSEric Joyner &nvm_dword); 3413*c80429ceSEric Joyner if (ret_val) 3414*c80429ceSEric Joyner return ret_val; 3415*c80429ceSEric Joyner sig_byte = (u8)((nvm_dword & 0xFF00) >> 8); 3416*c80429ceSEric Joyner if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3417*c80429ceSEric Joyner E1000_ICH_NVM_SIG_VALUE) { 3418*c80429ceSEric Joyner *bank = 0; 3419*c80429ceSEric Joyner return E1000_SUCCESS; 3420*c80429ceSEric Joyner } 3421*c80429ceSEric Joyner 3422*c80429ceSEric Joyner /* Check bank 1 */ 3423*c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset + 3424*c80429ceSEric Joyner bank1_offset, 3425*c80429ceSEric Joyner &nvm_dword); 3426*c80429ceSEric Joyner if (ret_val) 3427*c80429ceSEric Joyner return ret_val; 3428*c80429ceSEric Joyner sig_byte = (u8)((nvm_dword & 0xFF00) >> 8); 3429*c80429ceSEric Joyner if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3430*c80429ceSEric Joyner E1000_ICH_NVM_SIG_VALUE) { 3431*c80429ceSEric Joyner *bank = 1; 3432*c80429ceSEric Joyner return E1000_SUCCESS; 3433*c80429ceSEric Joyner } 3434*c80429ceSEric Joyner 3435*c80429ceSEric Joyner DEBUGOUT("ERROR: No valid NVM bank present\n"); 3436*c80429ceSEric Joyner return -E1000_ERR_NVM; 3437d035aa2dSJack F Vogel case e1000_ich8lan: 3438d035aa2dSJack F Vogel case e1000_ich9lan: 3439d035aa2dSJack F Vogel eecd = E1000_READ_REG(hw, E1000_EECD); 3440d035aa2dSJack F Vogel if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == 3441d035aa2dSJack F Vogel E1000_EECD_SEC1VAL_VALID_MASK) { 3442d035aa2dSJack F Vogel if (eecd & E1000_EECD_SEC1VAL) 34438cfa0ad2SJack F Vogel *bank = 1; 34448cfa0ad2SJack F Vogel else 34458cfa0ad2SJack F Vogel *bank = 0; 3446d035aa2dSJack F Vogel 34476ab6bfe3SJack F Vogel return E1000_SUCCESS; 3448d035aa2dSJack F Vogel } 34494dab5c37SJack F Vogel DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n"); 3450d035aa2dSJack F Vogel /* fall-thru */ 3451d035aa2dSJack F Vogel default: 3452d035aa2dSJack F Vogel /* set bank to 0 in case flash read fails */ 34538cfa0ad2SJack F Vogel *bank = 0; 34548cfa0ad2SJack F Vogel 3455d035aa2dSJack F Vogel /* Check bank 0 */ 3456d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, 3457d035aa2dSJack F Vogel &sig_byte); 3458d035aa2dSJack F Vogel if (ret_val) 34596ab6bfe3SJack F Vogel return ret_val; 3460d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3461d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 3462d035aa2dSJack F Vogel *bank = 0; 34636ab6bfe3SJack F Vogel return E1000_SUCCESS; 3464d035aa2dSJack F Vogel } 3465d035aa2dSJack F Vogel 3466d035aa2dSJack F Vogel /* Check bank 1 */ 3467d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + 3468d035aa2dSJack F Vogel bank1_offset, 3469d035aa2dSJack F Vogel &sig_byte); 3470d035aa2dSJack F Vogel if (ret_val) 34716ab6bfe3SJack F Vogel return ret_val; 3472d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3473d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 34748cfa0ad2SJack F Vogel *bank = 1; 34756ab6bfe3SJack F Vogel return E1000_SUCCESS; 34768cfa0ad2SJack F Vogel } 34778cfa0ad2SJack F Vogel 3478d035aa2dSJack F Vogel DEBUGOUT("ERROR: No valid NVM bank present\n"); 34796ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 3480d035aa2dSJack F Vogel } 34818cfa0ad2SJack F Vogel } 34828cfa0ad2SJack F Vogel 34838cfa0ad2SJack F Vogel /** 3484*c80429ceSEric Joyner * e1000_read_nvm_spt - NVM access for SPT 3485*c80429ceSEric Joyner * @hw: pointer to the HW structure 3486*c80429ceSEric Joyner * @offset: The offset (in bytes) of the word(s) to read. 3487*c80429ceSEric Joyner * @words: Size of data to read in words. 3488*c80429ceSEric Joyner * @data: pointer to the word(s) to read at offset. 3489*c80429ceSEric Joyner * 3490*c80429ceSEric Joyner * Reads a word(s) from the NVM 3491*c80429ceSEric Joyner **/ 3492*c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words, 3493*c80429ceSEric Joyner u16 *data) 3494*c80429ceSEric Joyner { 3495*c80429ceSEric Joyner struct e1000_nvm_info *nvm = &hw->nvm; 3496*c80429ceSEric Joyner struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 3497*c80429ceSEric Joyner u32 act_offset; 3498*c80429ceSEric Joyner s32 ret_val = E1000_SUCCESS; 3499*c80429ceSEric Joyner u32 bank = 0; 3500*c80429ceSEric Joyner u32 dword = 0; 3501*c80429ceSEric Joyner u16 offset_to_read; 3502*c80429ceSEric Joyner u16 i; 3503*c80429ceSEric Joyner 3504*c80429ceSEric Joyner DEBUGFUNC("e1000_read_nvm_spt"); 3505*c80429ceSEric Joyner 3506*c80429ceSEric Joyner if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 3507*c80429ceSEric Joyner (words == 0)) { 3508*c80429ceSEric Joyner DEBUGOUT("nvm parameter(s) out of bounds\n"); 3509*c80429ceSEric Joyner ret_val = -E1000_ERR_NVM; 3510*c80429ceSEric Joyner goto out; 3511*c80429ceSEric Joyner } 3512*c80429ceSEric Joyner 3513*c80429ceSEric Joyner nvm->ops.acquire(hw); 3514*c80429ceSEric Joyner 3515*c80429ceSEric Joyner ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 3516*c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) { 3517*c80429ceSEric Joyner DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 3518*c80429ceSEric Joyner bank = 0; 3519*c80429ceSEric Joyner } 3520*c80429ceSEric Joyner 3521*c80429ceSEric Joyner act_offset = (bank) ? nvm->flash_bank_size : 0; 3522*c80429ceSEric Joyner act_offset += offset; 3523*c80429ceSEric Joyner 3524*c80429ceSEric Joyner ret_val = E1000_SUCCESS; 3525*c80429ceSEric Joyner 3526*c80429ceSEric Joyner for (i = 0; i < words; i += 2) { 3527*c80429ceSEric Joyner if (words - i == 1) { 3528*c80429ceSEric Joyner if (dev_spec->shadow_ram[offset+i].modified) { 3529*c80429ceSEric Joyner data[i] = dev_spec->shadow_ram[offset+i].value; 3530*c80429ceSEric Joyner } else { 3531*c80429ceSEric Joyner offset_to_read = act_offset + i - 3532*c80429ceSEric Joyner ((act_offset + i) % 2); 3533*c80429ceSEric Joyner ret_val = 3534*c80429ceSEric Joyner e1000_read_flash_dword_ich8lan(hw, 3535*c80429ceSEric Joyner offset_to_read, 3536*c80429ceSEric Joyner &dword); 3537*c80429ceSEric Joyner if (ret_val) 3538*c80429ceSEric Joyner break; 3539*c80429ceSEric Joyner if ((act_offset + i) % 2 == 0) 3540*c80429ceSEric Joyner data[i] = (u16)(dword & 0xFFFF); 3541*c80429ceSEric Joyner else 3542*c80429ceSEric Joyner data[i] = (u16)((dword >> 16) & 0xFFFF); 3543*c80429ceSEric Joyner } 3544*c80429ceSEric Joyner } else { 3545*c80429ceSEric Joyner offset_to_read = act_offset + i; 3546*c80429ceSEric Joyner if (!(dev_spec->shadow_ram[offset+i].modified) || 3547*c80429ceSEric Joyner !(dev_spec->shadow_ram[offset+i+1].modified)) { 3548*c80429ceSEric Joyner ret_val = 3549*c80429ceSEric Joyner e1000_read_flash_dword_ich8lan(hw, 3550*c80429ceSEric Joyner offset_to_read, 3551*c80429ceSEric Joyner &dword); 3552*c80429ceSEric Joyner if (ret_val) 3553*c80429ceSEric Joyner break; 3554*c80429ceSEric Joyner } 3555*c80429ceSEric Joyner if (dev_spec->shadow_ram[offset+i].modified) 3556*c80429ceSEric Joyner data[i] = dev_spec->shadow_ram[offset+i].value; 3557*c80429ceSEric Joyner else 3558*c80429ceSEric Joyner data[i] = (u16) (dword & 0xFFFF); 3559*c80429ceSEric Joyner if (dev_spec->shadow_ram[offset+i].modified) 3560*c80429ceSEric Joyner data[i+1] = 3561*c80429ceSEric Joyner dev_spec->shadow_ram[offset+i+1].value; 3562*c80429ceSEric Joyner else 3563*c80429ceSEric Joyner data[i+1] = (u16) (dword >> 16 & 0xFFFF); 3564*c80429ceSEric Joyner } 3565*c80429ceSEric Joyner } 3566*c80429ceSEric Joyner 3567*c80429ceSEric Joyner nvm->ops.release(hw); 3568*c80429ceSEric Joyner 3569*c80429ceSEric Joyner out: 3570*c80429ceSEric Joyner if (ret_val) 3571*c80429ceSEric Joyner DEBUGOUT1("NVM read error: %d\n", ret_val); 3572*c80429ceSEric Joyner 3573*c80429ceSEric Joyner return ret_val; 3574*c80429ceSEric Joyner } 3575*c80429ceSEric Joyner 3576*c80429ceSEric Joyner /** 35778cfa0ad2SJack F Vogel * e1000_read_nvm_ich8lan - Read word(s) from the NVM 35788cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 35798cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to read. 35808cfa0ad2SJack F Vogel * @words: Size of data to read in words 35818cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to read at offset. 35828cfa0ad2SJack F Vogel * 35838cfa0ad2SJack F Vogel * Reads a word(s) from the NVM using the flash access registers. 35848cfa0ad2SJack F Vogel **/ 35858cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 35868cfa0ad2SJack F Vogel u16 *data) 35878cfa0ad2SJack F Vogel { 35888cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 3589daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 35908cfa0ad2SJack F Vogel u32 act_offset; 35918cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 35928cfa0ad2SJack F Vogel u32 bank = 0; 35938cfa0ad2SJack F Vogel u16 i, word; 35948cfa0ad2SJack F Vogel 35958cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_nvm_ich8lan"); 35968cfa0ad2SJack F Vogel 35978cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 35988cfa0ad2SJack F Vogel (words == 0)) { 35998cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 36008cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 36018cfa0ad2SJack F Vogel goto out; 36028cfa0ad2SJack F Vogel } 36038cfa0ad2SJack F Vogel 36044edd8523SJack F Vogel nvm->ops.acquire(hw); 36058cfa0ad2SJack F Vogel 36068cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 36074edd8523SJack F Vogel if (ret_val != E1000_SUCCESS) { 36084edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 36094edd8523SJack F Vogel bank = 0; 36104edd8523SJack F Vogel } 36118cfa0ad2SJack F Vogel 36128cfa0ad2SJack F Vogel act_offset = (bank) ? nvm->flash_bank_size : 0; 36138cfa0ad2SJack F Vogel act_offset += offset; 36148cfa0ad2SJack F Vogel 36154edd8523SJack F Vogel ret_val = E1000_SUCCESS; 36168cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 36174dab5c37SJack F Vogel if (dev_spec->shadow_ram[offset+i].modified) { 36188cfa0ad2SJack F Vogel data[i] = dev_spec->shadow_ram[offset+i].value; 36198cfa0ad2SJack F Vogel } else { 36208cfa0ad2SJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, 36218cfa0ad2SJack F Vogel act_offset + i, 36228cfa0ad2SJack F Vogel &word); 36238cfa0ad2SJack F Vogel if (ret_val) 36248cfa0ad2SJack F Vogel break; 36258cfa0ad2SJack F Vogel data[i] = word; 36268cfa0ad2SJack F Vogel } 36278cfa0ad2SJack F Vogel } 36288cfa0ad2SJack F Vogel 36298cfa0ad2SJack F Vogel nvm->ops.release(hw); 36308cfa0ad2SJack F Vogel 36318cfa0ad2SJack F Vogel out: 3632d035aa2dSJack F Vogel if (ret_val) 3633d035aa2dSJack F Vogel DEBUGOUT1("NVM read error: %d\n", ret_val); 3634d035aa2dSJack F Vogel 36358cfa0ad2SJack F Vogel return ret_val; 36368cfa0ad2SJack F Vogel } 36378cfa0ad2SJack F Vogel 36388cfa0ad2SJack F Vogel /** 36398cfa0ad2SJack F Vogel * e1000_flash_cycle_init_ich8lan - Initialize flash 36408cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 36418cfa0ad2SJack F Vogel * 36428cfa0ad2SJack F Vogel * This function does initial flash setup so that a new read/write/erase cycle 36438cfa0ad2SJack F Vogel * can be started. 36448cfa0ad2SJack F Vogel **/ 36458cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) 36468cfa0ad2SJack F Vogel { 36478cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 36488cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 36498cfa0ad2SJack F Vogel 36508cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_init_ich8lan"); 36518cfa0ad2SJack F Vogel 36528cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 36538cfa0ad2SJack F Vogel 36548cfa0ad2SJack F Vogel /* Check if the flash descriptor is valid */ 36556ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.fldesvalid) { 36564dab5c37SJack F Vogel DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used.\n"); 36576ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 36588cfa0ad2SJack F Vogel } 36598cfa0ad2SJack F Vogel 36608cfa0ad2SJack F Vogel /* Clear FCERR and DAEL in hw status by writing 1 */ 36618cfa0ad2SJack F Vogel hsfsts.hsf_status.flcerr = 1; 36628cfa0ad2SJack F Vogel hsfsts.hsf_status.dael = 1; 3663*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 3664*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3665*c80429ceSEric Joyner hsfsts.regval & 0xFFFF); 3666*c80429ceSEric Joyner else 36678cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); 36688cfa0ad2SJack F Vogel 36696ab6bfe3SJack F Vogel /* Either we should have a hardware SPI cycle in progress 36708cfa0ad2SJack F Vogel * bit to check against, in order to start a new cycle or 36718cfa0ad2SJack F Vogel * FDONE bit should be changed in the hardware so that it 36728cfa0ad2SJack F Vogel * is 1 after hardware reset, which can then be used as an 36738cfa0ad2SJack F Vogel * indication whether a cycle is in progress or has been 36748cfa0ad2SJack F Vogel * completed. 36758cfa0ad2SJack F Vogel */ 36768cfa0ad2SJack F Vogel 36776ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcinprog) { 36786ab6bfe3SJack F Vogel /* There is no cycle running at present, 36798cfa0ad2SJack F Vogel * so we can start a cycle. 36808cfa0ad2SJack F Vogel * Begin by setting Flash Cycle Done. 36818cfa0ad2SJack F Vogel */ 36828cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 3683*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 3684*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3685*c80429ceSEric Joyner hsfsts.regval & 0xFFFF); 3686*c80429ceSEric Joyner else 3687*c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, 3688*c80429ceSEric Joyner hsfsts.regval); 36898cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 36908cfa0ad2SJack F Vogel } else { 3691730d3130SJack F Vogel s32 i; 3692730d3130SJack F Vogel 36936ab6bfe3SJack F Vogel /* Otherwise poll for sometime so the current 36948cfa0ad2SJack F Vogel * cycle has a chance to end before giving up. 36958cfa0ad2SJack F Vogel */ 36968cfa0ad2SJack F Vogel for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 36978cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 36988cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 36996ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcinprog) { 37008cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 37018cfa0ad2SJack F Vogel break; 37028cfa0ad2SJack F Vogel } 37038cfa0ad2SJack F Vogel usec_delay(1); 37048cfa0ad2SJack F Vogel } 37058cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 37066ab6bfe3SJack F Vogel /* Successful in waiting for previous cycle to timeout, 37078cfa0ad2SJack F Vogel * now set the Flash Cycle Done. 37088cfa0ad2SJack F Vogel */ 37098cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 3710*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 3711*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3712*c80429ceSEric Joyner hsfsts.regval & 0xFFFF); 3713*c80429ceSEric Joyner else 3714daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, 37158cfa0ad2SJack F Vogel hsfsts.regval); 37168cfa0ad2SJack F Vogel } else { 37174dab5c37SJack F Vogel DEBUGOUT("Flash controller busy, cannot get access\n"); 37188cfa0ad2SJack F Vogel } 37198cfa0ad2SJack F Vogel } 37208cfa0ad2SJack F Vogel 37218cfa0ad2SJack F Vogel return ret_val; 37228cfa0ad2SJack F Vogel } 37238cfa0ad2SJack F Vogel 37248cfa0ad2SJack F Vogel /** 37258cfa0ad2SJack F Vogel * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) 37268cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 37278cfa0ad2SJack F Vogel * @timeout: maximum time to wait for completion 37288cfa0ad2SJack F Vogel * 37298cfa0ad2SJack F Vogel * This function starts a flash cycle and waits for its completion. 37308cfa0ad2SJack F Vogel **/ 37318cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) 37328cfa0ad2SJack F Vogel { 37338cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 37348cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 37358cfa0ad2SJack F Vogel u32 i = 0; 37368cfa0ad2SJack F Vogel 37378cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_ich8lan"); 37388cfa0ad2SJack F Vogel 37398cfa0ad2SJack F Vogel /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 3740*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 3741*c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; 3742*c80429ceSEric Joyner else 37438cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 37448cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcgo = 1; 37458cc64f1eSJack F Vogel 3746*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 3747*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3748*c80429ceSEric Joyner hsflctl.regval << 16); 3749*c80429ceSEric Joyner else 37508cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 37518cfa0ad2SJack F Vogel 37528cfa0ad2SJack F Vogel /* wait till FDONE bit is set to 1 */ 37538cfa0ad2SJack F Vogel do { 37548cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 37556ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcdone) 37568cfa0ad2SJack F Vogel break; 37578cfa0ad2SJack F Vogel usec_delay(1); 37588cfa0ad2SJack F Vogel } while (i++ < timeout); 37598cfa0ad2SJack F Vogel 37606ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr) 37616ab6bfe3SJack F Vogel return E1000_SUCCESS; 37628cfa0ad2SJack F Vogel 37636ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 37648cfa0ad2SJack F Vogel } 37658cfa0ad2SJack F Vogel 37668cfa0ad2SJack F Vogel /** 3767*c80429ceSEric Joyner * e1000_read_flash_dword_ich8lan - Read dword from flash 3768*c80429ceSEric Joyner * @hw: pointer to the HW structure 3769*c80429ceSEric Joyner * @offset: offset to data location 3770*c80429ceSEric Joyner * @data: pointer to the location for storing the data 3771*c80429ceSEric Joyner * 3772*c80429ceSEric Joyner * Reads the flash dword at offset into data. Offset is converted 3773*c80429ceSEric Joyner * to bytes before read. 3774*c80429ceSEric Joyner **/ 3775*c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset, 3776*c80429ceSEric Joyner u32 *data) 3777*c80429ceSEric Joyner { 3778*c80429ceSEric Joyner DEBUGFUNC("e1000_read_flash_dword_ich8lan"); 3779*c80429ceSEric Joyner 3780*c80429ceSEric Joyner if (!data) 3781*c80429ceSEric Joyner return -E1000_ERR_NVM; 3782*c80429ceSEric Joyner 3783*c80429ceSEric Joyner /* Must convert word offset into bytes. */ 3784*c80429ceSEric Joyner offset <<= 1; 3785*c80429ceSEric Joyner 3786*c80429ceSEric Joyner return e1000_read_flash_data32_ich8lan(hw, offset, data); 3787*c80429ceSEric Joyner } 3788*c80429ceSEric Joyner 3789*c80429ceSEric Joyner /** 37908cfa0ad2SJack F Vogel * e1000_read_flash_word_ich8lan - Read word from flash 37918cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 37928cfa0ad2SJack F Vogel * @offset: offset to data location 37938cfa0ad2SJack F Vogel * @data: pointer to the location for storing the data 37948cfa0ad2SJack F Vogel * 37958cfa0ad2SJack F Vogel * Reads the flash word at offset into data. Offset is converted 37968cfa0ad2SJack F Vogel * to bytes before read. 37978cfa0ad2SJack F Vogel **/ 37988cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, 37998cfa0ad2SJack F Vogel u16 *data) 38008cfa0ad2SJack F Vogel { 38018cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_word_ich8lan"); 38028cfa0ad2SJack F Vogel 38036ab6bfe3SJack F Vogel if (!data) 38046ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 38058cfa0ad2SJack F Vogel 38068cfa0ad2SJack F Vogel /* Must convert offset into bytes. */ 38078cfa0ad2SJack F Vogel offset <<= 1; 38088cfa0ad2SJack F Vogel 38096ab6bfe3SJack F Vogel return e1000_read_flash_data_ich8lan(hw, offset, 2, data); 38108cfa0ad2SJack F Vogel } 38118cfa0ad2SJack F Vogel 38128cfa0ad2SJack F Vogel /** 38138cfa0ad2SJack F Vogel * e1000_read_flash_byte_ich8lan - Read byte from flash 38148cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 38158cfa0ad2SJack F Vogel * @offset: The offset of the byte to read. 38168cfa0ad2SJack F Vogel * @data: Pointer to a byte to store the value read. 38178cfa0ad2SJack F Vogel * 38188cfa0ad2SJack F Vogel * Reads a single byte from the NVM using the flash access registers. 38198cfa0ad2SJack F Vogel **/ 38208cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 38218cfa0ad2SJack F Vogel u8 *data) 38228cfa0ad2SJack F Vogel { 38236ab6bfe3SJack F Vogel s32 ret_val; 38248cfa0ad2SJack F Vogel u16 word = 0; 38258cfa0ad2SJack F Vogel 3826*c80429ceSEric Joyner /* In SPT, only 32 bits access is supported, 3827*c80429ceSEric Joyner * so this function should not be called. 3828*c80429ceSEric Joyner */ 3829*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 3830*c80429ceSEric Joyner return -E1000_ERR_NVM; 3831*c80429ceSEric Joyner else 38328cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); 38338cc64f1eSJack F Vogel 38348cfa0ad2SJack F Vogel if (ret_val) 38356ab6bfe3SJack F Vogel return ret_val; 38368cfa0ad2SJack F Vogel 38378cfa0ad2SJack F Vogel *data = (u8)word; 38388cfa0ad2SJack F Vogel 38396ab6bfe3SJack F Vogel return E1000_SUCCESS; 38408cfa0ad2SJack F Vogel } 38418cfa0ad2SJack F Vogel 38428cfa0ad2SJack F Vogel /** 38438cfa0ad2SJack F Vogel * e1000_read_flash_data_ich8lan - Read byte or word from NVM 38448cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 38458cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte or word to read. 38468cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 38478cfa0ad2SJack F Vogel * @data: Pointer to the word to store the value read. 38488cfa0ad2SJack F Vogel * 38498cfa0ad2SJack F Vogel * Reads a byte or word from the NVM using the flash access registers. 38508cfa0ad2SJack F Vogel **/ 38518cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 38528cfa0ad2SJack F Vogel u8 size, u16 *data) 38538cfa0ad2SJack F Vogel { 38548cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 38558cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 38568cfa0ad2SJack F Vogel u32 flash_linear_addr; 38578cfa0ad2SJack F Vogel u32 flash_data = 0; 38588cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 38598cfa0ad2SJack F Vogel u8 count = 0; 38608cfa0ad2SJack F Vogel 38618cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_data_ich8lan"); 38628cfa0ad2SJack F Vogel 38638cfa0ad2SJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 38646ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 38657609433eSJack F Vogel flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 38667609433eSJack F Vogel hw->nvm.flash_base_addr); 38678cfa0ad2SJack F Vogel 38688cfa0ad2SJack F Vogel do { 38698cfa0ad2SJack F Vogel usec_delay(1); 38708cfa0ad2SJack F Vogel /* Steps */ 38718cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 38728cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 38738cfa0ad2SJack F Vogel break; 38748cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 38758cc64f1eSJack F Vogel 38768cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 38778cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 38788cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 38798cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 38808cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 38818cfa0ad2SJack F Vogel 38828cc64f1eSJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 38838cfa0ad2SJack F Vogel ICH_FLASH_READ_COMMAND_TIMEOUT); 38848cfa0ad2SJack F Vogel 38856ab6bfe3SJack F Vogel /* Check if FCERR is set to 1, if set to 1, clear it 38868cfa0ad2SJack F Vogel * and try the whole sequence a few more times, else 38878cfa0ad2SJack F Vogel * read in (shift in) the Flash Data0, the order is 38888cfa0ad2SJack F Vogel * least significant byte first msb to lsb 38898cfa0ad2SJack F Vogel */ 38908cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 38918cfa0ad2SJack F Vogel flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); 3892daf9197cSJack F Vogel if (size == 1) 38938cfa0ad2SJack F Vogel *data = (u8)(flash_data & 0x000000FF); 3894daf9197cSJack F Vogel else if (size == 2) 38958cfa0ad2SJack F Vogel *data = (u16)(flash_data & 0x0000FFFF); 38968cfa0ad2SJack F Vogel break; 38978cfa0ad2SJack F Vogel } else { 38986ab6bfe3SJack F Vogel /* If we've gotten here, then things are probably 38998cfa0ad2SJack F Vogel * completely hosed, but if the error condition is 39008cfa0ad2SJack F Vogel * detected, it won't hurt to give it another try... 39018cfa0ad2SJack F Vogel * ICH_FLASH_CYCLE_REPEAT_COUNT times. 39028cfa0ad2SJack F Vogel */ 39038cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 39048cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 39056ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) { 39068cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 39078cfa0ad2SJack F Vogel continue; 39086ab6bfe3SJack F Vogel } else if (!hsfsts.hsf_status.flcdone) { 39094dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 39108cfa0ad2SJack F Vogel break; 39118cfa0ad2SJack F Vogel } 39128cfa0ad2SJack F Vogel } 39138cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 39148cfa0ad2SJack F Vogel 39158cfa0ad2SJack F Vogel return ret_val; 39168cfa0ad2SJack F Vogel } 39178cfa0ad2SJack F Vogel 3918*c80429ceSEric Joyner /** 3919*c80429ceSEric Joyner * e1000_read_flash_data32_ich8lan - Read dword from NVM 3920*c80429ceSEric Joyner * @hw: pointer to the HW structure 3921*c80429ceSEric Joyner * @offset: The offset (in bytes) of the dword to read. 3922*c80429ceSEric Joyner * @data: Pointer to the dword to store the value read. 3923*c80429ceSEric Joyner * 3924*c80429ceSEric Joyner * Reads a byte or word from the NVM using the flash access registers. 3925*c80429ceSEric Joyner **/ 3926*c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 3927*c80429ceSEric Joyner u32 *data) 3928*c80429ceSEric Joyner { 3929*c80429ceSEric Joyner union ich8_hws_flash_status hsfsts; 3930*c80429ceSEric Joyner union ich8_hws_flash_ctrl hsflctl; 3931*c80429ceSEric Joyner u32 flash_linear_addr; 3932*c80429ceSEric Joyner s32 ret_val = -E1000_ERR_NVM; 3933*c80429ceSEric Joyner u8 count = 0; 3934*c80429ceSEric Joyner 3935*c80429ceSEric Joyner DEBUGFUNC("e1000_read_flash_data_ich8lan"); 3936*c80429ceSEric Joyner 3937*c80429ceSEric Joyner if (offset > ICH_FLASH_LINEAR_ADDR_MASK || 3938*c80429ceSEric Joyner hw->mac.type != e1000_pch_spt) 3939*c80429ceSEric Joyner return -E1000_ERR_NVM; 3940*c80429ceSEric Joyner flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 3941*c80429ceSEric Joyner hw->nvm.flash_base_addr); 3942*c80429ceSEric Joyner 3943*c80429ceSEric Joyner do { 3944*c80429ceSEric Joyner usec_delay(1); 3945*c80429ceSEric Joyner /* Steps */ 3946*c80429ceSEric Joyner ret_val = e1000_flash_cycle_init_ich8lan(hw); 3947*c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) 3948*c80429ceSEric Joyner break; 3949*c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not flash. 3950*c80429ceSEric Joyner * Therefore, only 32 bit access is supported 3951*c80429ceSEric Joyner */ 3952*c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; 3953*c80429ceSEric Joyner 3954*c80429ceSEric Joyner /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 3955*c80429ceSEric Joyner hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1; 3956*c80429ceSEric Joyner hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 3957*c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not flash. 3958*c80429ceSEric Joyner * Therefore, only 32 bit access is supported 3959*c80429ceSEric Joyner */ 3960*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3961*c80429ceSEric Joyner (u32)hsflctl.regval << 16); 3962*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 3963*c80429ceSEric Joyner 3964*c80429ceSEric Joyner ret_val = e1000_flash_cycle_ich8lan(hw, 3965*c80429ceSEric Joyner ICH_FLASH_READ_COMMAND_TIMEOUT); 3966*c80429ceSEric Joyner 3967*c80429ceSEric Joyner /* Check if FCERR is set to 1, if set to 1, clear it 3968*c80429ceSEric Joyner * and try the whole sequence a few more times, else 3969*c80429ceSEric Joyner * read in (shift in) the Flash Data0, the order is 3970*c80429ceSEric Joyner * least significant byte first msb to lsb 3971*c80429ceSEric Joyner */ 3972*c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) { 3973*c80429ceSEric Joyner *data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); 3974*c80429ceSEric Joyner break; 3975*c80429ceSEric Joyner } else { 3976*c80429ceSEric Joyner /* If we've gotten here, then things are probably 3977*c80429ceSEric Joyner * completely hosed, but if the error condition is 3978*c80429ceSEric Joyner * detected, it won't hurt to give it another try... 3979*c80429ceSEric Joyner * ICH_FLASH_CYCLE_REPEAT_COUNT times. 3980*c80429ceSEric Joyner */ 3981*c80429ceSEric Joyner hsfsts.regval = E1000_READ_FLASH_REG16(hw, 3982*c80429ceSEric Joyner ICH_FLASH_HSFSTS); 3983*c80429ceSEric Joyner if (hsfsts.hsf_status.flcerr) { 3984*c80429ceSEric Joyner /* Repeat for some time before giving up. */ 3985*c80429ceSEric Joyner continue; 3986*c80429ceSEric Joyner } else if (!hsfsts.hsf_status.flcdone) { 3987*c80429ceSEric Joyner DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 3988*c80429ceSEric Joyner break; 3989*c80429ceSEric Joyner } 3990*c80429ceSEric Joyner } 3991*c80429ceSEric Joyner } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 3992*c80429ceSEric Joyner 3993*c80429ceSEric Joyner return ret_val; 3994*c80429ceSEric Joyner } 39958cc64f1eSJack F Vogel 39968cfa0ad2SJack F Vogel /** 39978cfa0ad2SJack F Vogel * e1000_write_nvm_ich8lan - Write word(s) to the NVM 39988cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 39998cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to write. 40008cfa0ad2SJack F Vogel * @words: Size of data to write in words 40018cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to write at offset. 40028cfa0ad2SJack F Vogel * 40038cfa0ad2SJack F Vogel * Writes a byte or word to the NVM using the flash access registers. 40048cfa0ad2SJack F Vogel **/ 40058cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 40068cfa0ad2SJack F Vogel u16 *data) 40078cfa0ad2SJack F Vogel { 40088cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 4009daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 40108cfa0ad2SJack F Vogel u16 i; 40118cfa0ad2SJack F Vogel 40128cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_nvm_ich8lan"); 40138cfa0ad2SJack F Vogel 40148cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 40158cfa0ad2SJack F Vogel (words == 0)) { 40168cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 40176ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 40188cfa0ad2SJack F Vogel } 40198cfa0ad2SJack F Vogel 40204edd8523SJack F Vogel nvm->ops.acquire(hw); 40218cfa0ad2SJack F Vogel 40228cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 40238cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].modified = TRUE; 40248cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].value = data[i]; 40258cfa0ad2SJack F Vogel } 40268cfa0ad2SJack F Vogel 40278cfa0ad2SJack F Vogel nvm->ops.release(hw); 40288cfa0ad2SJack F Vogel 40296ab6bfe3SJack F Vogel return E1000_SUCCESS; 40308cfa0ad2SJack F Vogel } 40318cfa0ad2SJack F Vogel 40328cfa0ad2SJack F Vogel /** 4033*c80429ceSEric Joyner * e1000_update_nvm_checksum_spt - Update the checksum for NVM 4034*c80429ceSEric Joyner * @hw: pointer to the HW structure 4035*c80429ceSEric Joyner * 4036*c80429ceSEric Joyner * The NVM checksum is updated by calling the generic update_nvm_checksum, 4037*c80429ceSEric Joyner * which writes the checksum to the shadow ram. The changes in the shadow 4038*c80429ceSEric Joyner * ram are then committed to the EEPROM by processing each bank at a time 4039*c80429ceSEric Joyner * checking for the modified bit and writing only the pending changes. 4040*c80429ceSEric Joyner * After a successful commit, the shadow ram is cleared and is ready for 4041*c80429ceSEric Joyner * future writes. 4042*c80429ceSEric Joyner **/ 4043*c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw) 4044*c80429ceSEric Joyner { 4045*c80429ceSEric Joyner struct e1000_nvm_info *nvm = &hw->nvm; 4046*c80429ceSEric Joyner struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 4047*c80429ceSEric Joyner u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 4048*c80429ceSEric Joyner s32 ret_val; 4049*c80429ceSEric Joyner u32 dword = 0; 4050*c80429ceSEric Joyner 4051*c80429ceSEric Joyner DEBUGFUNC("e1000_update_nvm_checksum_spt"); 4052*c80429ceSEric Joyner 4053*c80429ceSEric Joyner ret_val = e1000_update_nvm_checksum_generic(hw); 4054*c80429ceSEric Joyner if (ret_val) 4055*c80429ceSEric Joyner goto out; 4056*c80429ceSEric Joyner 4057*c80429ceSEric Joyner if (nvm->type != e1000_nvm_flash_sw) 4058*c80429ceSEric Joyner goto out; 4059*c80429ceSEric Joyner 4060*c80429ceSEric Joyner nvm->ops.acquire(hw); 4061*c80429ceSEric Joyner 4062*c80429ceSEric Joyner /* We're writing to the opposite bank so if we're on bank 1, 4063*c80429ceSEric Joyner * write to bank 0 etc. We also need to erase the segment that 4064*c80429ceSEric Joyner * is going to be written 4065*c80429ceSEric Joyner */ 4066*c80429ceSEric Joyner ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 4067*c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) { 4068*c80429ceSEric Joyner DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 4069*c80429ceSEric Joyner bank = 0; 4070*c80429ceSEric Joyner } 4071*c80429ceSEric Joyner 4072*c80429ceSEric Joyner if (bank == 0) { 4073*c80429ceSEric Joyner new_bank_offset = nvm->flash_bank_size; 4074*c80429ceSEric Joyner old_bank_offset = 0; 4075*c80429ceSEric Joyner ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 4076*c80429ceSEric Joyner if (ret_val) 4077*c80429ceSEric Joyner goto release; 4078*c80429ceSEric Joyner } else { 4079*c80429ceSEric Joyner old_bank_offset = nvm->flash_bank_size; 4080*c80429ceSEric Joyner new_bank_offset = 0; 4081*c80429ceSEric Joyner ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 4082*c80429ceSEric Joyner if (ret_val) 4083*c80429ceSEric Joyner goto release; 4084*c80429ceSEric Joyner } 4085*c80429ceSEric Joyner for (i = 0; i < E1000_SHADOW_RAM_WORDS; i += 2) { 4086*c80429ceSEric Joyner /* Determine whether to write the value stored 4087*c80429ceSEric Joyner * in the other NVM bank or a modified value stored 4088*c80429ceSEric Joyner * in the shadow RAM 4089*c80429ceSEric Joyner */ 4090*c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, 4091*c80429ceSEric Joyner i + old_bank_offset, 4092*c80429ceSEric Joyner &dword); 4093*c80429ceSEric Joyner 4094*c80429ceSEric Joyner if (dev_spec->shadow_ram[i].modified) { 4095*c80429ceSEric Joyner dword &= 0xffff0000; 4096*c80429ceSEric Joyner dword |= (dev_spec->shadow_ram[i].value & 0xffff); 4097*c80429ceSEric Joyner } 4098*c80429ceSEric Joyner if (dev_spec->shadow_ram[i + 1].modified) { 4099*c80429ceSEric Joyner dword &= 0x0000ffff; 4100*c80429ceSEric Joyner dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff) 4101*c80429ceSEric Joyner << 16); 4102*c80429ceSEric Joyner } 4103*c80429ceSEric Joyner if (ret_val) 4104*c80429ceSEric Joyner break; 4105*c80429ceSEric Joyner 4106*c80429ceSEric Joyner /* If the word is 0x13, then make sure the signature bits 4107*c80429ceSEric Joyner * (15:14) are 11b until the commit has completed. 4108*c80429ceSEric Joyner * This will allow us to write 10b which indicates the 4109*c80429ceSEric Joyner * signature is valid. We want to do this after the write 4110*c80429ceSEric Joyner * has completed so that we don't mark the segment valid 4111*c80429ceSEric Joyner * while the write is still in progress 4112*c80429ceSEric Joyner */ 4113*c80429ceSEric Joyner if (i == E1000_ICH_NVM_SIG_WORD - 1) 4114*c80429ceSEric Joyner dword |= E1000_ICH_NVM_SIG_MASK << 16; 4115*c80429ceSEric Joyner 4116*c80429ceSEric Joyner /* Convert offset to bytes. */ 4117*c80429ceSEric Joyner act_offset = (i + new_bank_offset) << 1; 4118*c80429ceSEric Joyner 4119*c80429ceSEric Joyner usec_delay(100); 4120*c80429ceSEric Joyner 4121*c80429ceSEric Joyner /* Write the data to the new bank. Offset in words*/ 4122*c80429ceSEric Joyner act_offset = i + new_bank_offset; 4123*c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, 4124*c80429ceSEric Joyner dword); 4125*c80429ceSEric Joyner if (ret_val) 4126*c80429ceSEric Joyner break; 4127*c80429ceSEric Joyner } 4128*c80429ceSEric Joyner 4129*c80429ceSEric Joyner /* Don't bother writing the segment valid bits if sector 4130*c80429ceSEric Joyner * programming failed. 4131*c80429ceSEric Joyner */ 4132*c80429ceSEric Joyner if (ret_val) { 4133*c80429ceSEric Joyner DEBUGOUT("Flash commit failed.\n"); 4134*c80429ceSEric Joyner goto release; 4135*c80429ceSEric Joyner } 4136*c80429ceSEric Joyner 4137*c80429ceSEric Joyner /* Finally validate the new segment by setting bit 15:14 4138*c80429ceSEric Joyner * to 10b in word 0x13 , this can be done without an 4139*c80429ceSEric Joyner * erase as well since these bits are 11 to start with 4140*c80429ceSEric Joyner * and we need to change bit 14 to 0b 4141*c80429ceSEric Joyner */ 4142*c80429ceSEric Joyner act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 4143*c80429ceSEric Joyner 4144*c80429ceSEric Joyner /*offset in words but we read dword*/ 4145*c80429ceSEric Joyner --act_offset; 4146*c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); 4147*c80429ceSEric Joyner 4148*c80429ceSEric Joyner if (ret_val) 4149*c80429ceSEric Joyner goto release; 4150*c80429ceSEric Joyner 4151*c80429ceSEric Joyner dword &= 0xBFFFFFFF; 4152*c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); 4153*c80429ceSEric Joyner 4154*c80429ceSEric Joyner if (ret_val) 4155*c80429ceSEric Joyner goto release; 4156*c80429ceSEric Joyner 4157*c80429ceSEric Joyner /* And invalidate the previously valid segment by setting 4158*c80429ceSEric Joyner * its signature word (0x13) high_byte to 0b. This can be 4159*c80429ceSEric Joyner * done without an erase because flash erase sets all bits 4160*c80429ceSEric Joyner * to 1's. We can write 1's to 0's without an erase 4161*c80429ceSEric Joyner */ 4162*c80429ceSEric Joyner act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 4163*c80429ceSEric Joyner 4164*c80429ceSEric Joyner /* offset in words but we read dword*/ 4165*c80429ceSEric Joyner act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1; 4166*c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); 4167*c80429ceSEric Joyner 4168*c80429ceSEric Joyner if (ret_val) 4169*c80429ceSEric Joyner goto release; 4170*c80429ceSEric Joyner 4171*c80429ceSEric Joyner dword &= 0x00FFFFFF; 4172*c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); 4173*c80429ceSEric Joyner 4174*c80429ceSEric Joyner if (ret_val) 4175*c80429ceSEric Joyner goto release; 4176*c80429ceSEric Joyner 4177*c80429ceSEric Joyner /* Great! Everything worked, we can now clear the cached entries. */ 4178*c80429ceSEric Joyner for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 4179*c80429ceSEric Joyner dev_spec->shadow_ram[i].modified = FALSE; 4180*c80429ceSEric Joyner dev_spec->shadow_ram[i].value = 0xFFFF; 4181*c80429ceSEric Joyner } 4182*c80429ceSEric Joyner 4183*c80429ceSEric Joyner release: 4184*c80429ceSEric Joyner nvm->ops.release(hw); 4185*c80429ceSEric Joyner 4186*c80429ceSEric Joyner /* Reload the EEPROM, or else modifications will not appear 4187*c80429ceSEric Joyner * until after the next adapter reset. 4188*c80429ceSEric Joyner */ 4189*c80429ceSEric Joyner if (!ret_val) { 4190*c80429ceSEric Joyner nvm->ops.reload(hw); 4191*c80429ceSEric Joyner msec_delay(10); 4192*c80429ceSEric Joyner } 4193*c80429ceSEric Joyner 4194*c80429ceSEric Joyner out: 4195*c80429ceSEric Joyner if (ret_val) 4196*c80429ceSEric Joyner DEBUGOUT1("NVM update error: %d\n", ret_val); 4197*c80429ceSEric Joyner 4198*c80429ceSEric Joyner return ret_val; 4199*c80429ceSEric Joyner } 4200*c80429ceSEric Joyner 4201*c80429ceSEric Joyner /** 42028cfa0ad2SJack F Vogel * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM 42038cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 42048cfa0ad2SJack F Vogel * 42058cfa0ad2SJack F Vogel * The NVM checksum is updated by calling the generic update_nvm_checksum, 42068cfa0ad2SJack F Vogel * which writes the checksum to the shadow ram. The changes in the shadow 42078cfa0ad2SJack F Vogel * ram are then committed to the EEPROM by processing each bank at a time 42088cfa0ad2SJack F Vogel * checking for the modified bit and writing only the pending changes. 42098cfa0ad2SJack F Vogel * After a successful commit, the shadow ram is cleared and is ready for 42108cfa0ad2SJack F Vogel * future writes. 42118cfa0ad2SJack F Vogel **/ 42128cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) 42138cfa0ad2SJack F Vogel { 42148cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 4215daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 42168cfa0ad2SJack F Vogel u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 42178cfa0ad2SJack F Vogel s32 ret_val; 42188cc64f1eSJack F Vogel u16 data = 0; 42198cfa0ad2SJack F Vogel 42208cfa0ad2SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_ich8lan"); 42218cfa0ad2SJack F Vogel 42228cfa0ad2SJack F Vogel ret_val = e1000_update_nvm_checksum_generic(hw); 42238cfa0ad2SJack F Vogel if (ret_val) 42248cfa0ad2SJack F Vogel goto out; 42258cfa0ad2SJack F Vogel 42268cfa0ad2SJack F Vogel if (nvm->type != e1000_nvm_flash_sw) 42278cfa0ad2SJack F Vogel goto out; 42288cfa0ad2SJack F Vogel 42294edd8523SJack F Vogel nvm->ops.acquire(hw); 42308cfa0ad2SJack F Vogel 42316ab6bfe3SJack F Vogel /* We're writing to the opposite bank so if we're on bank 1, 42328cfa0ad2SJack F Vogel * write to bank 0 etc. We also need to erase the segment that 42338cfa0ad2SJack F Vogel * is going to be written 42348cfa0ad2SJack F Vogel */ 42358cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 4236d035aa2dSJack F Vogel if (ret_val != E1000_SUCCESS) { 42374edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 42384edd8523SJack F Vogel bank = 0; 4239d035aa2dSJack F Vogel } 42408cfa0ad2SJack F Vogel 42418cfa0ad2SJack F Vogel if (bank == 0) { 42428cfa0ad2SJack F Vogel new_bank_offset = nvm->flash_bank_size; 42438cfa0ad2SJack F Vogel old_bank_offset = 0; 4244d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 4245a69ed8dfSJack F Vogel if (ret_val) 4246a69ed8dfSJack F Vogel goto release; 42478cfa0ad2SJack F Vogel } else { 42488cfa0ad2SJack F Vogel old_bank_offset = nvm->flash_bank_size; 42498cfa0ad2SJack F Vogel new_bank_offset = 0; 4250d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 4251a69ed8dfSJack F Vogel if (ret_val) 4252a69ed8dfSJack F Vogel goto release; 42538cfa0ad2SJack F Vogel } 42548cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 42558cfa0ad2SJack F Vogel if (dev_spec->shadow_ram[i].modified) { 42568cfa0ad2SJack F Vogel data = dev_spec->shadow_ram[i].value; 42578cfa0ad2SJack F Vogel } else { 4258d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, i + 4259d035aa2dSJack F Vogel old_bank_offset, 42608cfa0ad2SJack F Vogel &data); 4261d035aa2dSJack F Vogel if (ret_val) 4262d035aa2dSJack F Vogel break; 42638cfa0ad2SJack F Vogel } 42646ab6bfe3SJack F Vogel /* If the word is 0x13, then make sure the signature bits 42658cfa0ad2SJack F Vogel * (15:14) are 11b until the commit has completed. 42668cfa0ad2SJack F Vogel * This will allow us to write 10b which indicates the 42678cfa0ad2SJack F Vogel * signature is valid. We want to do this after the write 42688cfa0ad2SJack F Vogel * has completed so that we don't mark the segment valid 42698cfa0ad2SJack F Vogel * while the write is still in progress 42708cfa0ad2SJack F Vogel */ 42718cfa0ad2SJack F Vogel if (i == E1000_ICH_NVM_SIG_WORD) 42728cfa0ad2SJack F Vogel data |= E1000_ICH_NVM_SIG_MASK; 42738cfa0ad2SJack F Vogel 42748cfa0ad2SJack F Vogel /* Convert offset to bytes. */ 42758cfa0ad2SJack F Vogel act_offset = (i + new_bank_offset) << 1; 42768cfa0ad2SJack F Vogel 42778cfa0ad2SJack F Vogel usec_delay(100); 42788cc64f1eSJack F Vogel 42798cfa0ad2SJack F Vogel /* Write the bytes to the new bank. */ 42808cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 42818cfa0ad2SJack F Vogel act_offset, 42828cfa0ad2SJack F Vogel (u8)data); 42838cfa0ad2SJack F Vogel if (ret_val) 42848cfa0ad2SJack F Vogel break; 42858cfa0ad2SJack F Vogel 42868cfa0ad2SJack F Vogel usec_delay(100); 42878cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 42888cfa0ad2SJack F Vogel act_offset + 1, 42898cfa0ad2SJack F Vogel (u8)(data >> 8)); 42908cfa0ad2SJack F Vogel if (ret_val) 42918cfa0ad2SJack F Vogel break; 42928cfa0ad2SJack F Vogel } 42938cfa0ad2SJack F Vogel 42946ab6bfe3SJack F Vogel /* Don't bother writing the segment valid bits if sector 42958cfa0ad2SJack F Vogel * programming failed. 42968cfa0ad2SJack F Vogel */ 42978cfa0ad2SJack F Vogel if (ret_val) { 42988cfa0ad2SJack F Vogel DEBUGOUT("Flash commit failed.\n"); 4299a69ed8dfSJack F Vogel goto release; 43008cfa0ad2SJack F Vogel } 43018cfa0ad2SJack F Vogel 43026ab6bfe3SJack F Vogel /* Finally validate the new segment by setting bit 15:14 43038cfa0ad2SJack F Vogel * to 10b in word 0x13 , this can be done without an 43048cfa0ad2SJack F Vogel * erase as well since these bits are 11 to start with 43058cfa0ad2SJack F Vogel * and we need to change bit 14 to 0b 43068cfa0ad2SJack F Vogel */ 43078cfa0ad2SJack F Vogel act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 4308d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); 4309a69ed8dfSJack F Vogel if (ret_val) 4310a69ed8dfSJack F Vogel goto release; 43114edd8523SJack F Vogel 43128cfa0ad2SJack F Vogel data &= 0xBFFF; 43138cc64f1eSJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, 43148cfa0ad2SJack F Vogel (u8)(data >> 8)); 4315a69ed8dfSJack F Vogel if (ret_val) 4316a69ed8dfSJack F Vogel goto release; 43178cfa0ad2SJack F Vogel 43186ab6bfe3SJack F Vogel /* And invalidate the previously valid segment by setting 43198cfa0ad2SJack F Vogel * its signature word (0x13) high_byte to 0b. This can be 43208cfa0ad2SJack F Vogel * done without an erase because flash erase sets all bits 43218cfa0ad2SJack F Vogel * to 1's. We can write 1's to 0's without an erase 43228cfa0ad2SJack F Vogel */ 43238cfa0ad2SJack F Vogel act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 43248cc64f1eSJack F Vogel 43258cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); 43268cc64f1eSJack F Vogel 4327a69ed8dfSJack F Vogel if (ret_val) 4328a69ed8dfSJack F Vogel goto release; 43298cfa0ad2SJack F Vogel 43308cfa0ad2SJack F Vogel /* Great! Everything worked, we can now clear the cached entries. */ 43318cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 43328cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 43338cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 43348cfa0ad2SJack F Vogel } 43358cfa0ad2SJack F Vogel 4336a69ed8dfSJack F Vogel release: 43378cfa0ad2SJack F Vogel nvm->ops.release(hw); 43388cfa0ad2SJack F Vogel 43396ab6bfe3SJack F Vogel /* Reload the EEPROM, or else modifications will not appear 43408cfa0ad2SJack F Vogel * until after the next adapter reset. 43418cfa0ad2SJack F Vogel */ 4342a69ed8dfSJack F Vogel if (!ret_val) { 43438cfa0ad2SJack F Vogel nvm->ops.reload(hw); 43448cfa0ad2SJack F Vogel msec_delay(10); 4345a69ed8dfSJack F Vogel } 43468cfa0ad2SJack F Vogel 43478cfa0ad2SJack F Vogel out: 4348d035aa2dSJack F Vogel if (ret_val) 4349d035aa2dSJack F Vogel DEBUGOUT1("NVM update error: %d\n", ret_val); 4350d035aa2dSJack F Vogel 43518cfa0ad2SJack F Vogel return ret_val; 43528cfa0ad2SJack F Vogel } 43538cfa0ad2SJack F Vogel 43548cfa0ad2SJack F Vogel /** 43558cfa0ad2SJack F Vogel * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum 43568cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 43578cfa0ad2SJack F Vogel * 43588cfa0ad2SJack F Vogel * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. 4359daf9197cSJack F Vogel * If the bit is 0, that the EEPROM had been modified, but the checksum was not 4360daf9197cSJack F Vogel * calculated, in which case we need to calculate the checksum and set bit 6. 43618cfa0ad2SJack F Vogel **/ 43628cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) 43638cfa0ad2SJack F Vogel { 43646ab6bfe3SJack F Vogel s32 ret_val; 43658cfa0ad2SJack F Vogel u16 data; 43666ab6bfe3SJack F Vogel u16 word; 43676ab6bfe3SJack F Vogel u16 valid_csum_mask; 43688cfa0ad2SJack F Vogel 43698cfa0ad2SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan"); 43708cfa0ad2SJack F Vogel 43716ab6bfe3SJack F Vogel /* Read NVM and check Invalid Image CSUM bit. If this bit is 0, 43726ab6bfe3SJack F Vogel * the checksum needs to be fixed. This bit is an indication that 43736ab6bfe3SJack F Vogel * the NVM was prepared by OEM software and did not calculate 43746ab6bfe3SJack F Vogel * the checksum...a likely scenario. 43758cfa0ad2SJack F Vogel */ 43766ab6bfe3SJack F Vogel switch (hw->mac.type) { 43776ab6bfe3SJack F Vogel case e1000_pch_lpt: 4378*c80429ceSEric Joyner case e1000_pch_spt: 43796ab6bfe3SJack F Vogel word = NVM_COMPAT; 43806ab6bfe3SJack F Vogel valid_csum_mask = NVM_COMPAT_VALID_CSUM; 43816ab6bfe3SJack F Vogel break; 43826ab6bfe3SJack F Vogel default: 43836ab6bfe3SJack F Vogel word = NVM_FUTURE_INIT_WORD1; 43846ab6bfe3SJack F Vogel valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM; 43856ab6bfe3SJack F Vogel break; 43868cfa0ad2SJack F Vogel } 43878cfa0ad2SJack F Vogel 43886ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.read(hw, word, 1, &data); 43896ab6bfe3SJack F Vogel if (ret_val) 43908cfa0ad2SJack F Vogel return ret_val; 43916ab6bfe3SJack F Vogel 43926ab6bfe3SJack F Vogel if (!(data & valid_csum_mask)) { 43936ab6bfe3SJack F Vogel data |= valid_csum_mask; 43946ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.write(hw, word, 1, &data); 43956ab6bfe3SJack F Vogel if (ret_val) 43966ab6bfe3SJack F Vogel return ret_val; 43976ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.update(hw); 43986ab6bfe3SJack F Vogel if (ret_val) 43996ab6bfe3SJack F Vogel return ret_val; 44006ab6bfe3SJack F Vogel } 44016ab6bfe3SJack F Vogel 44026ab6bfe3SJack F Vogel return e1000_validate_nvm_checksum_generic(hw); 44038cfa0ad2SJack F Vogel } 44048cfa0ad2SJack F Vogel 44058cfa0ad2SJack F Vogel /** 44068cfa0ad2SJack F Vogel * e1000_write_flash_data_ich8lan - Writes bytes to the NVM 44078cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 44088cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte/word to read. 44098cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 44108cfa0ad2SJack F Vogel * @data: The byte(s) to write to the NVM. 44118cfa0ad2SJack F Vogel * 44128cfa0ad2SJack F Vogel * Writes one/two bytes to the NVM using the flash access registers. 44138cfa0ad2SJack F Vogel **/ 44148cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 44158cfa0ad2SJack F Vogel u8 size, u16 data) 44168cfa0ad2SJack F Vogel { 44178cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 44188cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 44198cfa0ad2SJack F Vogel u32 flash_linear_addr; 44208cfa0ad2SJack F Vogel u32 flash_data = 0; 44216ab6bfe3SJack F Vogel s32 ret_val; 44228cfa0ad2SJack F Vogel u8 count = 0; 44238cfa0ad2SJack F Vogel 44248cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_ich8_data"); 44258cfa0ad2SJack F Vogel 4426*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) { 4427*c80429ceSEric Joyner if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 4428*c80429ceSEric Joyner return -E1000_ERR_NVM; 4429*c80429ceSEric Joyner } else { 44308cc64f1eSJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 44316ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 4432*c80429ceSEric Joyner } 44338cfa0ad2SJack F Vogel 44347609433eSJack F Vogel flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 44357609433eSJack F Vogel hw->nvm.flash_base_addr); 44368cfa0ad2SJack F Vogel 44378cfa0ad2SJack F Vogel do { 44388cfa0ad2SJack F Vogel usec_delay(1); 44398cfa0ad2SJack F Vogel /* Steps */ 44408cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 44418cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 44428cfa0ad2SJack F Vogel break; 4443*c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not 4444*c80429ceSEric Joyner * flash. Therefore, only 32 bit access is supported 4445*c80429ceSEric Joyner */ 4446*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 4447*c80429ceSEric Joyner hsflctl.regval = 4448*c80429ceSEric Joyner E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; 4449*c80429ceSEric Joyner else 4450*c80429ceSEric Joyner hsflctl.regval = 4451*c80429ceSEric Joyner E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 44528cc64f1eSJack F Vogel 44538cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 44548cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 44558cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 4456*c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, 4457*c80429ceSEric Joyner * not flash. Therefore, only 32 bit access is 4458*c80429ceSEric Joyner * supported 4459*c80429ceSEric Joyner */ 4460*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 4461*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4462*c80429ceSEric Joyner hsflctl.regval << 16); 4463*c80429ceSEric Joyner else 4464*c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 4465*c80429ceSEric Joyner hsflctl.regval); 44668cfa0ad2SJack F Vogel 44678cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 44688cfa0ad2SJack F Vogel 44698cfa0ad2SJack F Vogel if (size == 1) 44708cfa0ad2SJack F Vogel flash_data = (u32)data & 0x00FF; 44718cfa0ad2SJack F Vogel else 44728cfa0ad2SJack F Vogel flash_data = (u32)data; 44738cfa0ad2SJack F Vogel 44748cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data); 44758cfa0ad2SJack F Vogel 44766ab6bfe3SJack F Vogel /* check if FCERR is set to 1 , if set to 1, clear it 44778cfa0ad2SJack F Vogel * and try the whole sequence a few more times else done 44788cfa0ad2SJack F Vogel */ 44797609433eSJack F Vogel ret_val = 44807609433eSJack F Vogel e1000_flash_cycle_ich8lan(hw, 44818cfa0ad2SJack F Vogel ICH_FLASH_WRITE_COMMAND_TIMEOUT); 4482daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 44838cfa0ad2SJack F Vogel break; 4484daf9197cSJack F Vogel 44856ab6bfe3SJack F Vogel /* If we're here, then things are most likely 44868cfa0ad2SJack F Vogel * completely hosed, but if the error condition 44878cfa0ad2SJack F Vogel * is detected, it won't hurt to give it another 44888cfa0ad2SJack F Vogel * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 44898cfa0ad2SJack F Vogel */ 4490daf9197cSJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 44916ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) 44928cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 44938cfa0ad2SJack F Vogel continue; 44946ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcdone) { 44954dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 44968cfa0ad2SJack F Vogel break; 44978cfa0ad2SJack F Vogel } 44988cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 44998cfa0ad2SJack F Vogel 45008cfa0ad2SJack F Vogel return ret_val; 45018cfa0ad2SJack F Vogel } 45028cfa0ad2SJack F Vogel 4503*c80429ceSEric Joyner /** 4504*c80429ceSEric Joyner * e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM 4505*c80429ceSEric Joyner * @hw: pointer to the HW structure 4506*c80429ceSEric Joyner * @offset: The offset (in bytes) of the dwords to read. 4507*c80429ceSEric Joyner * @data: The 4 bytes to write to the NVM. 4508*c80429ceSEric Joyner * 4509*c80429ceSEric Joyner * Writes one/two/four bytes to the NVM using the flash access registers. 4510*c80429ceSEric Joyner **/ 4511*c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 4512*c80429ceSEric Joyner u32 data) 4513*c80429ceSEric Joyner { 4514*c80429ceSEric Joyner union ich8_hws_flash_status hsfsts; 4515*c80429ceSEric Joyner union ich8_hws_flash_ctrl hsflctl; 4516*c80429ceSEric Joyner u32 flash_linear_addr; 4517*c80429ceSEric Joyner s32 ret_val; 4518*c80429ceSEric Joyner u8 count = 0; 4519*c80429ceSEric Joyner 4520*c80429ceSEric Joyner DEBUGFUNC("e1000_write_flash_data32_ich8lan"); 4521*c80429ceSEric Joyner 4522*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) { 4523*c80429ceSEric Joyner if (offset > ICH_FLASH_LINEAR_ADDR_MASK) 4524*c80429ceSEric Joyner return -E1000_ERR_NVM; 4525*c80429ceSEric Joyner } 4526*c80429ceSEric Joyner flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 4527*c80429ceSEric Joyner hw->nvm.flash_base_addr); 4528*c80429ceSEric Joyner do { 4529*c80429ceSEric Joyner usec_delay(1); 4530*c80429ceSEric Joyner /* Steps */ 4531*c80429ceSEric Joyner ret_val = e1000_flash_cycle_init_ich8lan(hw); 4532*c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) 4533*c80429ceSEric Joyner break; 4534*c80429ceSEric Joyner 4535*c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not 4536*c80429ceSEric Joyner * flash. Therefore, only 32 bit access is supported 4537*c80429ceSEric Joyner */ 4538*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 4539*c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, 4540*c80429ceSEric Joyner ICH_FLASH_HSFSTS) 4541*c80429ceSEric Joyner >> 16; 4542*c80429ceSEric Joyner else 4543*c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG16(hw, 4544*c80429ceSEric Joyner ICH_FLASH_HSFCTL); 4545*c80429ceSEric Joyner 4546*c80429ceSEric Joyner hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1; 4547*c80429ceSEric Joyner hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 4548*c80429ceSEric Joyner 4549*c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, 4550*c80429ceSEric Joyner * not flash. Therefore, only 32 bit access is 4551*c80429ceSEric Joyner * supported 4552*c80429ceSEric Joyner */ 4553*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 4554*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4555*c80429ceSEric Joyner hsflctl.regval << 16); 4556*c80429ceSEric Joyner else 4557*c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 4558*c80429ceSEric Joyner hsflctl.regval); 4559*c80429ceSEric Joyner 4560*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 4561*c80429ceSEric Joyner 4562*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, data); 4563*c80429ceSEric Joyner 4564*c80429ceSEric Joyner /* check if FCERR is set to 1 , if set to 1, clear it 4565*c80429ceSEric Joyner * and try the whole sequence a few more times else done 4566*c80429ceSEric Joyner */ 4567*c80429ceSEric Joyner ret_val = e1000_flash_cycle_ich8lan(hw, 4568*c80429ceSEric Joyner ICH_FLASH_WRITE_COMMAND_TIMEOUT); 4569*c80429ceSEric Joyner 4570*c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) 4571*c80429ceSEric Joyner break; 4572*c80429ceSEric Joyner 4573*c80429ceSEric Joyner /* If we're here, then things are most likely 4574*c80429ceSEric Joyner * completely hosed, but if the error condition 4575*c80429ceSEric Joyner * is detected, it won't hurt to give it another 4576*c80429ceSEric Joyner * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 4577*c80429ceSEric Joyner */ 4578*c80429ceSEric Joyner hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 4579*c80429ceSEric Joyner 4580*c80429ceSEric Joyner if (hsfsts.hsf_status.flcerr) 4581*c80429ceSEric Joyner /* Repeat for some time before giving up. */ 4582*c80429ceSEric Joyner continue; 4583*c80429ceSEric Joyner if (!hsfsts.hsf_status.flcdone) { 4584*c80429ceSEric Joyner DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 4585*c80429ceSEric Joyner break; 4586*c80429ceSEric Joyner } 4587*c80429ceSEric Joyner } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 4588*c80429ceSEric Joyner 4589*c80429ceSEric Joyner return ret_val; 4590*c80429ceSEric Joyner } 45918cc64f1eSJack F Vogel 45928cfa0ad2SJack F Vogel /** 45938cfa0ad2SJack F Vogel * e1000_write_flash_byte_ich8lan - Write a single byte to NVM 45948cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 45958cfa0ad2SJack F Vogel * @offset: The index of the byte to read. 45968cfa0ad2SJack F Vogel * @data: The byte to write to the NVM. 45978cfa0ad2SJack F Vogel * 45988cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 45998cfa0ad2SJack F Vogel **/ 46008cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 46018cfa0ad2SJack F Vogel u8 data) 46028cfa0ad2SJack F Vogel { 46038cfa0ad2SJack F Vogel u16 word = (u16)data; 46048cfa0ad2SJack F Vogel 46058cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_flash_byte_ich8lan"); 46068cfa0ad2SJack F Vogel 46078cfa0ad2SJack F Vogel return e1000_write_flash_data_ich8lan(hw, offset, 1, word); 46088cfa0ad2SJack F Vogel } 46098cfa0ad2SJack F Vogel 4610*c80429ceSEric Joyner /** 4611*c80429ceSEric Joyner * e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM 4612*c80429ceSEric Joyner * @hw: pointer to the HW structure 4613*c80429ceSEric Joyner * @offset: The offset of the word to write. 4614*c80429ceSEric Joyner * @dword: The dword to write to the NVM. 4615*c80429ceSEric Joyner * 4616*c80429ceSEric Joyner * Writes a single dword to the NVM using the flash access registers. 4617*c80429ceSEric Joyner * Goes through a retry algorithm before giving up. 4618*c80429ceSEric Joyner **/ 4619*c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw, 4620*c80429ceSEric Joyner u32 offset, u32 dword) 4621*c80429ceSEric Joyner { 4622*c80429ceSEric Joyner s32 ret_val; 4623*c80429ceSEric Joyner u16 program_retries; 46248cc64f1eSJack F Vogel 4625*c80429ceSEric Joyner DEBUGFUNC("e1000_retry_write_flash_dword_ich8lan"); 4626*c80429ceSEric Joyner 4627*c80429ceSEric Joyner /* Must convert word offset into bytes. */ 4628*c80429ceSEric Joyner offset <<= 1; 4629*c80429ceSEric Joyner 4630*c80429ceSEric Joyner ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword); 4631*c80429ceSEric Joyner 4632*c80429ceSEric Joyner if (!ret_val) 4633*c80429ceSEric Joyner return ret_val; 4634*c80429ceSEric Joyner for (program_retries = 0; program_retries < 100; program_retries++) { 4635*c80429ceSEric Joyner DEBUGOUT2("Retrying Byte %8.8X at offset %u\n", dword, offset); 4636*c80429ceSEric Joyner usec_delay(100); 4637*c80429ceSEric Joyner ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword); 4638*c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) 4639*c80429ceSEric Joyner break; 4640*c80429ceSEric Joyner } 4641*c80429ceSEric Joyner if (program_retries == 100) 4642*c80429ceSEric Joyner return -E1000_ERR_NVM; 4643*c80429ceSEric Joyner 4644*c80429ceSEric Joyner return E1000_SUCCESS; 4645*c80429ceSEric Joyner } 46468cc64f1eSJack F Vogel 46478cfa0ad2SJack F Vogel /** 46488cfa0ad2SJack F Vogel * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM 46498cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 46508cfa0ad2SJack F Vogel * @offset: The offset of the byte to write. 46518cfa0ad2SJack F Vogel * @byte: The byte to write to the NVM. 46528cfa0ad2SJack F Vogel * 46538cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 46548cfa0ad2SJack F Vogel * Goes through a retry algorithm before giving up. 46558cfa0ad2SJack F Vogel **/ 46568cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 46578cfa0ad2SJack F Vogel u32 offset, u8 byte) 46588cfa0ad2SJack F Vogel { 46598cfa0ad2SJack F Vogel s32 ret_val; 46608cfa0ad2SJack F Vogel u16 program_retries; 46618cfa0ad2SJack F Vogel 46628cfa0ad2SJack F Vogel DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan"); 46638cfa0ad2SJack F Vogel 46648cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 46656ab6bfe3SJack F Vogel if (!ret_val) 46666ab6bfe3SJack F Vogel return ret_val; 46678cfa0ad2SJack F Vogel 46688cfa0ad2SJack F Vogel for (program_retries = 0; program_retries < 100; program_retries++) { 46698cfa0ad2SJack F Vogel DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset); 46708cfa0ad2SJack F Vogel usec_delay(100); 46718cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 46728cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) 46738cfa0ad2SJack F Vogel break; 46748cfa0ad2SJack F Vogel } 46756ab6bfe3SJack F Vogel if (program_retries == 100) 46766ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 46778cfa0ad2SJack F Vogel 46786ab6bfe3SJack F Vogel return E1000_SUCCESS; 46798cfa0ad2SJack F Vogel } 46808cfa0ad2SJack F Vogel 46818cfa0ad2SJack F Vogel /** 46828cfa0ad2SJack F Vogel * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM 46838cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 46848cfa0ad2SJack F Vogel * @bank: 0 for first bank, 1 for second bank, etc. 46858cfa0ad2SJack F Vogel * 46868cfa0ad2SJack F Vogel * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. 46878cfa0ad2SJack F Vogel * bank N is 4096 * N + flash_reg_addr. 46888cfa0ad2SJack F Vogel **/ 46898cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) 46908cfa0ad2SJack F Vogel { 46918cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 46928cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 46938cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 46948cfa0ad2SJack F Vogel u32 flash_linear_addr; 46958cfa0ad2SJack F Vogel /* bank size is in 16bit words - adjust to bytes */ 46968cfa0ad2SJack F Vogel u32 flash_bank_size = nvm->flash_bank_size * 2; 46976ab6bfe3SJack F Vogel s32 ret_val; 46988cfa0ad2SJack F Vogel s32 count = 0; 46998cfa0ad2SJack F Vogel s32 j, iteration, sector_size; 47008cfa0ad2SJack F Vogel 47018cfa0ad2SJack F Vogel DEBUGFUNC("e1000_erase_flash_bank_ich8lan"); 47028cfa0ad2SJack F Vogel 47038cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 47048cfa0ad2SJack F Vogel 47056ab6bfe3SJack F Vogel /* Determine HW Sector size: Read BERASE bits of hw flash status 47068cfa0ad2SJack F Vogel * register 47078cfa0ad2SJack F Vogel * 00: The Hw sector is 256 bytes, hence we need to erase 16 47088cfa0ad2SJack F Vogel * consecutive sectors. The start index for the nth Hw sector 47098cfa0ad2SJack F Vogel * can be calculated as = bank * 4096 + n * 256 47108cfa0ad2SJack F Vogel * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. 47118cfa0ad2SJack F Vogel * The start index for the nth Hw sector can be calculated 47128cfa0ad2SJack F Vogel * as = bank * 4096 47138cfa0ad2SJack F Vogel * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 47148cfa0ad2SJack F Vogel * (ich9 only, otherwise error condition) 47158cfa0ad2SJack F Vogel * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 47168cfa0ad2SJack F Vogel */ 47178cfa0ad2SJack F Vogel switch (hsfsts.hsf_status.berasesz) { 47188cfa0ad2SJack F Vogel case 0: 47198cfa0ad2SJack F Vogel /* Hw sector size 256 */ 47208cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_256; 47218cfa0ad2SJack F Vogel iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; 47228cfa0ad2SJack F Vogel break; 47238cfa0ad2SJack F Vogel case 1: 47248cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_4K; 47259d81738fSJack F Vogel iteration = 1; 47268cfa0ad2SJack F Vogel break; 47278cfa0ad2SJack F Vogel case 2: 47288cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_8K; 47298bd0025fSJack F Vogel iteration = 1; 47308cfa0ad2SJack F Vogel break; 47318cfa0ad2SJack F Vogel case 3: 47328cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_64K; 47339d81738fSJack F Vogel iteration = 1; 47348cfa0ad2SJack F Vogel break; 47358cfa0ad2SJack F Vogel default: 47366ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 47378cfa0ad2SJack F Vogel } 47388cfa0ad2SJack F Vogel 47398cfa0ad2SJack F Vogel /* Start with the base address, then add the sector offset. */ 47408cfa0ad2SJack F Vogel flash_linear_addr = hw->nvm.flash_base_addr; 47414edd8523SJack F Vogel flash_linear_addr += (bank) ? flash_bank_size : 0; 47428cfa0ad2SJack F Vogel 47438cfa0ad2SJack F Vogel for (j = 0; j < iteration; j++) { 47448cfa0ad2SJack F Vogel do { 47457609433eSJack F Vogel u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT; 47467609433eSJack F Vogel 47478cfa0ad2SJack F Vogel /* Steps */ 47488cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 47498cfa0ad2SJack F Vogel if (ret_val) 47506ab6bfe3SJack F Vogel return ret_val; 47518cfa0ad2SJack F Vogel 47526ab6bfe3SJack F Vogel /* Write a value 11 (block Erase) in Flash 47538cfa0ad2SJack F Vogel * Cycle field in hw flash control 47548cfa0ad2SJack F Vogel */ 4755*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 47568cc64f1eSJack F Vogel hsflctl.regval = 4757*c80429ceSEric Joyner E1000_READ_FLASH_REG(hw, 4758*c80429ceSEric Joyner ICH_FLASH_HSFSTS)>>16; 4759*c80429ceSEric Joyner else 4760*c80429ceSEric Joyner hsflctl.regval = 4761*c80429ceSEric Joyner E1000_READ_FLASH_REG16(hw, 4762*c80429ceSEric Joyner ICH_FLASH_HSFCTL); 47638cc64f1eSJack F Vogel 47648cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; 4765*c80429ceSEric Joyner if (hw->mac.type == e1000_pch_spt) 4766*c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4767*c80429ceSEric Joyner hsflctl.regval << 16); 4768*c80429ceSEric Joyner else 4769daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 47708cfa0ad2SJack F Vogel hsflctl.regval); 47718cfa0ad2SJack F Vogel 47726ab6bfe3SJack F Vogel /* Write the last 24 bits of an index within the 47738cfa0ad2SJack F Vogel * block into Flash Linear address field in Flash 47748cfa0ad2SJack F Vogel * Address. 47758cfa0ad2SJack F Vogel */ 47768cfa0ad2SJack F Vogel flash_linear_addr += (j * sector_size); 4777daf9197cSJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, 47788cfa0ad2SJack F Vogel flash_linear_addr); 47798cfa0ad2SJack F Vogel 47807609433eSJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, timeout); 4781daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 47828cfa0ad2SJack F Vogel break; 4783daf9197cSJack F Vogel 47846ab6bfe3SJack F Vogel /* Check if FCERR is set to 1. If 1, 47858cfa0ad2SJack F Vogel * clear it and try the whole sequence 47868cfa0ad2SJack F Vogel * a few more times else Done 47878cfa0ad2SJack F Vogel */ 47888cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 47898cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 47906ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) 4791daf9197cSJack F Vogel /* repeat for some time before giving up */ 47928cfa0ad2SJack F Vogel continue; 47936ab6bfe3SJack F Vogel else if (!hsfsts.hsf_status.flcdone) 47946ab6bfe3SJack F Vogel return ret_val; 47958cfa0ad2SJack F Vogel } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); 47968cfa0ad2SJack F Vogel } 47978cfa0ad2SJack F Vogel 47986ab6bfe3SJack F Vogel return E1000_SUCCESS; 47998cfa0ad2SJack F Vogel } 48008cfa0ad2SJack F Vogel 48018cfa0ad2SJack F Vogel /** 48028cfa0ad2SJack F Vogel * e1000_valid_led_default_ich8lan - Set the default LED settings 48038cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 48048cfa0ad2SJack F Vogel * @data: Pointer to the LED settings 48058cfa0ad2SJack F Vogel * 48068cfa0ad2SJack F Vogel * Reads the LED default settings from the NVM to data. If the NVM LED 48078cfa0ad2SJack F Vogel * settings is all 0's or F's, set the LED default to a valid LED default 48088cfa0ad2SJack F Vogel * setting. 48098cfa0ad2SJack F Vogel **/ 48108cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) 48118cfa0ad2SJack F Vogel { 48128cfa0ad2SJack F Vogel s32 ret_val; 48138cfa0ad2SJack F Vogel 48148cfa0ad2SJack F Vogel DEBUGFUNC("e1000_valid_led_default_ich8lan"); 48158cfa0ad2SJack F Vogel 48168cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 48178cfa0ad2SJack F Vogel if (ret_val) { 48188cfa0ad2SJack F Vogel DEBUGOUT("NVM Read Error\n"); 48196ab6bfe3SJack F Vogel return ret_val; 48208cfa0ad2SJack F Vogel } 48218cfa0ad2SJack F Vogel 48224dab5c37SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) 48238cfa0ad2SJack F Vogel *data = ID_LED_DEFAULT_ICH8LAN; 48248cfa0ad2SJack F Vogel 48256ab6bfe3SJack F Vogel return E1000_SUCCESS; 48268cfa0ad2SJack F Vogel } 48278cfa0ad2SJack F Vogel 48288cfa0ad2SJack F Vogel /** 48299d81738fSJack F Vogel * e1000_id_led_init_pchlan - store LED configurations 48309d81738fSJack F Vogel * @hw: pointer to the HW structure 48319d81738fSJack F Vogel * 48329d81738fSJack F Vogel * PCH does not control LEDs via the LEDCTL register, rather it uses 48339d81738fSJack F Vogel * the PHY LED configuration register. 48349d81738fSJack F Vogel * 48359d81738fSJack F Vogel * PCH also does not have an "always on" or "always off" mode which 48369d81738fSJack F Vogel * complicates the ID feature. Instead of using the "on" mode to indicate 48379d81738fSJack F Vogel * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()), 48389d81738fSJack F Vogel * use "link_up" mode. The LEDs will still ID on request if there is no 48399d81738fSJack F Vogel * link based on logic in e1000_led_[on|off]_pchlan(). 48409d81738fSJack F Vogel **/ 48419d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) 48429d81738fSJack F Vogel { 48439d81738fSJack F Vogel struct e1000_mac_info *mac = &hw->mac; 48449d81738fSJack F Vogel s32 ret_val; 48459d81738fSJack F Vogel const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; 48469d81738fSJack F Vogel const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; 48479d81738fSJack F Vogel u16 data, i, temp, shift; 48489d81738fSJack F Vogel 48499d81738fSJack F Vogel DEBUGFUNC("e1000_id_led_init_pchlan"); 48509d81738fSJack F Vogel 48519d81738fSJack F Vogel /* Get default ID LED modes */ 48529d81738fSJack F Vogel ret_val = hw->nvm.ops.valid_led_default(hw, &data); 48539d81738fSJack F Vogel if (ret_val) 48546ab6bfe3SJack F Vogel return ret_val; 48559d81738fSJack F Vogel 48569d81738fSJack F Vogel mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); 48579d81738fSJack F Vogel mac->ledctl_mode1 = mac->ledctl_default; 48589d81738fSJack F Vogel mac->ledctl_mode2 = mac->ledctl_default; 48599d81738fSJack F Vogel 48609d81738fSJack F Vogel for (i = 0; i < 4; i++) { 48619d81738fSJack F Vogel temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; 48629d81738fSJack F Vogel shift = (i * 5); 48639d81738fSJack F Vogel switch (temp) { 48649d81738fSJack F Vogel case ID_LED_ON1_DEF2: 48659d81738fSJack F Vogel case ID_LED_ON1_ON2: 48669d81738fSJack F Vogel case ID_LED_ON1_OFF2: 48679d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 48689d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_on << shift); 48699d81738fSJack F Vogel break; 48709d81738fSJack F Vogel case ID_LED_OFF1_DEF2: 48719d81738fSJack F Vogel case ID_LED_OFF1_ON2: 48729d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 48739d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 48749d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_off << shift); 48759d81738fSJack F Vogel break; 48769d81738fSJack F Vogel default: 48779d81738fSJack F Vogel /* Do nothing */ 48789d81738fSJack F Vogel break; 48799d81738fSJack F Vogel } 48809d81738fSJack F Vogel switch (temp) { 48819d81738fSJack F Vogel case ID_LED_DEF1_ON2: 48829d81738fSJack F Vogel case ID_LED_ON1_ON2: 48839d81738fSJack F Vogel case ID_LED_OFF1_ON2: 48849d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 48859d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_on << shift); 48869d81738fSJack F Vogel break; 48879d81738fSJack F Vogel case ID_LED_DEF1_OFF2: 48889d81738fSJack F Vogel case ID_LED_ON1_OFF2: 48899d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 48909d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 48919d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_off << shift); 48929d81738fSJack F Vogel break; 48939d81738fSJack F Vogel default: 48949d81738fSJack F Vogel /* Do nothing */ 48959d81738fSJack F Vogel break; 48969d81738fSJack F Vogel } 48979d81738fSJack F Vogel } 48989d81738fSJack F Vogel 48996ab6bfe3SJack F Vogel return E1000_SUCCESS; 49009d81738fSJack F Vogel } 49019d81738fSJack F Vogel 49029d81738fSJack F Vogel /** 49038cfa0ad2SJack F Vogel * e1000_get_bus_info_ich8lan - Get/Set the bus type and width 49048cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 49058cfa0ad2SJack F Vogel * 49068cfa0ad2SJack F Vogel * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability 49076ab6bfe3SJack F Vogel * register, so the the bus width is hard coded. 49088cfa0ad2SJack F Vogel **/ 49098cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) 49108cfa0ad2SJack F Vogel { 49118cfa0ad2SJack F Vogel struct e1000_bus_info *bus = &hw->bus; 49128cfa0ad2SJack F Vogel s32 ret_val; 49138cfa0ad2SJack F Vogel 49148cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_bus_info_ich8lan"); 49158cfa0ad2SJack F Vogel 49168cfa0ad2SJack F Vogel ret_val = e1000_get_bus_info_pcie_generic(hw); 49178cfa0ad2SJack F Vogel 49186ab6bfe3SJack F Vogel /* ICH devices are "PCI Express"-ish. They have 49198cfa0ad2SJack F Vogel * a configuration space, but do not contain 49208cfa0ad2SJack F Vogel * PCI Express Capability registers, so bus width 49218cfa0ad2SJack F Vogel * must be hardcoded. 49228cfa0ad2SJack F Vogel */ 49238cfa0ad2SJack F Vogel if (bus->width == e1000_bus_width_unknown) 49248cfa0ad2SJack F Vogel bus->width = e1000_bus_width_pcie_x1; 49258cfa0ad2SJack F Vogel 49268cfa0ad2SJack F Vogel return ret_val; 49278cfa0ad2SJack F Vogel } 49288cfa0ad2SJack F Vogel 49298cfa0ad2SJack F Vogel /** 49308cfa0ad2SJack F Vogel * e1000_reset_hw_ich8lan - Reset the hardware 49318cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 49328cfa0ad2SJack F Vogel * 49338cfa0ad2SJack F Vogel * Does a full reset of the hardware which includes a reset of the PHY and 49348cfa0ad2SJack F Vogel * MAC. 49358cfa0ad2SJack F Vogel **/ 49368cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) 49378cfa0ad2SJack F Vogel { 49384edd8523SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 49396ab6bfe3SJack F Vogel u16 kum_cfg; 49406ab6bfe3SJack F Vogel u32 ctrl, reg; 49418cfa0ad2SJack F Vogel s32 ret_val; 49428cfa0ad2SJack F Vogel 49438cfa0ad2SJack F Vogel DEBUGFUNC("e1000_reset_hw_ich8lan"); 49448cfa0ad2SJack F Vogel 49456ab6bfe3SJack F Vogel /* Prevent the PCI-E bus from sticking if there is no TLP connection 49468cfa0ad2SJack F Vogel * on the last TLP read/write transaction when MAC is reset. 49478cfa0ad2SJack F Vogel */ 49488cfa0ad2SJack F Vogel ret_val = e1000_disable_pcie_master_generic(hw); 4949daf9197cSJack F Vogel if (ret_val) 49508cfa0ad2SJack F Vogel DEBUGOUT("PCI-E Master disable polling has failed.\n"); 49518cfa0ad2SJack F Vogel 49528cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n"); 49538cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 49548cfa0ad2SJack F Vogel 49556ab6bfe3SJack F Vogel /* Disable the Transmit and Receive units. Then delay to allow 49568cfa0ad2SJack F Vogel * any pending transactions to complete before we hit the MAC 49578cfa0ad2SJack F Vogel * with the global reset. 49588cfa0ad2SJack F Vogel */ 49598cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, 0); 49608cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); 49618cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw); 49628cfa0ad2SJack F Vogel 49638cfa0ad2SJack F Vogel msec_delay(10); 49648cfa0ad2SJack F Vogel 49658cfa0ad2SJack F Vogel /* Workaround for ICH8 bit corruption issue in FIFO memory */ 49668cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 49678cfa0ad2SJack F Vogel /* Set Tx and Rx buffer allocation to 8k apiece. */ 49688cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K); 49698cfa0ad2SJack F Vogel /* Set Packet Buffer Size to 16k. */ 49708cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); 49718cfa0ad2SJack F Vogel } 49728cfa0ad2SJack F Vogel 49734edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) { 49744edd8523SJack F Vogel /* Save the NVM K1 bit setting*/ 49756ab6bfe3SJack F Vogel ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg); 49764edd8523SJack F Vogel if (ret_val) 49774edd8523SJack F Vogel return ret_val; 49784edd8523SJack F Vogel 49796ab6bfe3SJack F Vogel if (kum_cfg & E1000_NVM_K1_ENABLE) 49804edd8523SJack F Vogel dev_spec->nvm_k1_enabled = TRUE; 49814edd8523SJack F Vogel else 49824edd8523SJack F Vogel dev_spec->nvm_k1_enabled = FALSE; 49834edd8523SJack F Vogel } 49844edd8523SJack F Vogel 49858cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 49868cfa0ad2SJack F Vogel 49877d9119bdSJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) { 49886ab6bfe3SJack F Vogel /* Full-chip reset requires MAC and PHY reset at the same 49898cfa0ad2SJack F Vogel * time to make sure the interface between MAC and the 49908cfa0ad2SJack F Vogel * external PHY is reset. 49918cfa0ad2SJack F Vogel */ 49928cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_PHY_RST; 49937d9119bdSJack F Vogel 49946ab6bfe3SJack F Vogel /* Gate automatic PHY configuration by hardware on 49957d9119bdSJack F Vogel * non-managed 82579 49967d9119bdSJack F Vogel */ 49977d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 49987d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 49997d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 50008cfa0ad2SJack F Vogel } 50018cfa0ad2SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 5002daf9197cSJack F Vogel DEBUGOUT("Issuing a global reset to ich8lan\n"); 50038cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); 50044dab5c37SJack F Vogel /* cannot issue a flush here because it hangs the hardware */ 50058cfa0ad2SJack F Vogel msec_delay(20); 50068cfa0ad2SJack F Vogel 50076ab6bfe3SJack F Vogel /* Set Phy Config Counter to 50msec */ 50086ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pch2lan) { 50096ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_FEXTNVM3); 50106ab6bfe3SJack F Vogel reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; 50116ab6bfe3SJack F Vogel reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; 50126ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg); 50136ab6bfe3SJack F Vogel } 50146ab6bfe3SJack F Vogel 50159d81738fSJack F Vogel if (!ret_val) 50164dab5c37SJack F Vogel E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); 50179d81738fSJack F Vogel 50187d9119bdSJack F Vogel if (ctrl & E1000_CTRL_PHY_RST) { 50199d81738fSJack F Vogel ret_val = hw->phy.ops.get_cfg_done(hw); 50204edd8523SJack F Vogel if (ret_val) 50216ab6bfe3SJack F Vogel return ret_val; 50224edd8523SJack F Vogel 50237d9119bdSJack F Vogel ret_val = e1000_post_phy_reset_ich8lan(hw); 50244edd8523SJack F Vogel if (ret_val) 50256ab6bfe3SJack F Vogel return ret_val; 50267d9119bdSJack F Vogel } 50277d9119bdSJack F Vogel 50286ab6bfe3SJack F Vogel /* For PCH, this write will make sure that any noise 50294edd8523SJack F Vogel * will be detected as a CRC error and be dropped rather than show up 50304edd8523SJack F Vogel * as a bad packet to the DMA engine. 50314edd8523SJack F Vogel */ 50324edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) 50334edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565); 50348cfa0ad2SJack F Vogel 50358cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 5036730d3130SJack F Vogel E1000_READ_REG(hw, E1000_ICR); 50378cfa0ad2SJack F Vogel 50386ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_KABGTXD); 50396ab6bfe3SJack F Vogel reg |= E1000_KABGTXD_BGSQLBIAS; 50406ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_KABGTXD, reg); 50418cfa0ad2SJack F Vogel 50426ab6bfe3SJack F Vogel return E1000_SUCCESS; 50438cfa0ad2SJack F Vogel } 50448cfa0ad2SJack F Vogel 50458cfa0ad2SJack F Vogel /** 50468cfa0ad2SJack F Vogel * e1000_init_hw_ich8lan - Initialize the hardware 50478cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 50488cfa0ad2SJack F Vogel * 50498cfa0ad2SJack F Vogel * Prepares the hardware for transmit and receive by doing the following: 50508cfa0ad2SJack F Vogel * - initialize hardware bits 50518cfa0ad2SJack F Vogel * - initialize LED identification 50528cfa0ad2SJack F Vogel * - setup receive address registers 50538cfa0ad2SJack F Vogel * - setup flow control 50548cfa0ad2SJack F Vogel * - setup transmit descriptors 50558cfa0ad2SJack F Vogel * - clear statistics 50568cfa0ad2SJack F Vogel **/ 50578cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) 50588cfa0ad2SJack F Vogel { 50598cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 50608cfa0ad2SJack F Vogel u32 ctrl_ext, txdctl, snoop; 50618cfa0ad2SJack F Vogel s32 ret_val; 50628cfa0ad2SJack F Vogel u16 i; 50638cfa0ad2SJack F Vogel 50648cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_hw_ich8lan"); 50658cfa0ad2SJack F Vogel 50668cfa0ad2SJack F Vogel e1000_initialize_hw_bits_ich8lan(hw); 50678cfa0ad2SJack F Vogel 50688cfa0ad2SJack F Vogel /* Initialize identification LED */ 5069d035aa2dSJack F Vogel ret_val = mac->ops.id_led_init(hw); 50706ab6bfe3SJack F Vogel /* An error is not fatal and we should not stop init due to this */ 5071d035aa2dSJack F Vogel if (ret_val) 5072d035aa2dSJack F Vogel DEBUGOUT("Error initializing identification LED\n"); 50738cfa0ad2SJack F Vogel 50748cfa0ad2SJack F Vogel /* Setup the receive address. */ 50758cfa0ad2SJack F Vogel e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); 50768cfa0ad2SJack F Vogel 50778cfa0ad2SJack F Vogel /* Zero out the Multicast HASH table */ 50788cfa0ad2SJack F Vogel DEBUGOUT("Zeroing the MTA\n"); 50798cfa0ad2SJack F Vogel for (i = 0; i < mac->mta_reg_count; i++) 50808cfa0ad2SJack F Vogel E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 50818cfa0ad2SJack F Vogel 50826ab6bfe3SJack F Vogel /* The 82578 Rx buffer will stall if wakeup is enabled in host and 50834dab5c37SJack F Vogel * the ME. Disable wakeup by clearing the host wakeup bit. 50849d81738fSJack F Vogel * Reset the phy after disabling host wakeup to reset the Rx buffer. 50859d81738fSJack F Vogel */ 50869d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 50874dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i); 50884dab5c37SJack F Vogel i &= ~BM_WUC_HOST_WU_BIT; 50894dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i); 50909d81738fSJack F Vogel ret_val = e1000_phy_hw_reset_ich8lan(hw); 50919d81738fSJack F Vogel if (ret_val) 50929d81738fSJack F Vogel return ret_val; 50939d81738fSJack F Vogel } 50949d81738fSJack F Vogel 50958cfa0ad2SJack F Vogel /* Setup link and flow control */ 50968cfa0ad2SJack F Vogel ret_val = mac->ops.setup_link(hw); 50978cfa0ad2SJack F Vogel 50988cfa0ad2SJack F Vogel /* Set the transmit descriptor write-back policy for both queues */ 50998cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); 51007609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) | 51017609433eSJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB); 51027609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) | 51037609433eSJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH); 51048cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); 51058cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1)); 51067609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) | 51077609433eSJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB); 51087609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) | 51097609433eSJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH); 51108cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl); 51118cfa0ad2SJack F Vogel 51126ab6bfe3SJack F Vogel /* ICH8 has opposite polarity of no_snoop bits. 51138cfa0ad2SJack F Vogel * By default, we should use snoop behavior. 51148cfa0ad2SJack F Vogel */ 51158cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 51168cfa0ad2SJack F Vogel snoop = PCIE_ICH8_SNOOP_ALL; 51178cfa0ad2SJack F Vogel else 51188cfa0ad2SJack F Vogel snoop = (u32) ~(PCIE_NO_SNOOP_ALL); 51198cfa0ad2SJack F Vogel e1000_set_pcie_no_snoop_generic(hw, snoop); 51208cfa0ad2SJack F Vogel 51218cfa0ad2SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 51228cfa0ad2SJack F Vogel ctrl_ext |= E1000_CTRL_EXT_RO_DIS; 51238cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 51248cfa0ad2SJack F Vogel 51256ab6bfe3SJack F Vogel /* Clear all of the statistics registers (clear on read). It is 51268cfa0ad2SJack F Vogel * important that we do this after we have tried to establish link 51278cfa0ad2SJack F Vogel * because the symbol error count will increment wildly if there 51288cfa0ad2SJack F Vogel * is no link. 51298cfa0ad2SJack F Vogel */ 51308cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_ich8lan(hw); 51318cfa0ad2SJack F Vogel 51328cfa0ad2SJack F Vogel return ret_val; 51338cfa0ad2SJack F Vogel } 51346ab6bfe3SJack F Vogel 51358cfa0ad2SJack F Vogel /** 51368cfa0ad2SJack F Vogel * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits 51378cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 51388cfa0ad2SJack F Vogel * 51398cfa0ad2SJack F Vogel * Sets/Clears required hardware bits necessary for correctly setting up the 51408cfa0ad2SJack F Vogel * hardware for transmit and receive. 51418cfa0ad2SJack F Vogel **/ 51428cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) 51438cfa0ad2SJack F Vogel { 51448cfa0ad2SJack F Vogel u32 reg; 51458cfa0ad2SJack F Vogel 51468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_initialize_hw_bits_ich8lan"); 51478cfa0ad2SJack F Vogel 51488cfa0ad2SJack F Vogel /* Extended Device Control */ 51498cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 51508cfa0ad2SJack F Vogel reg |= (1 << 22); 51519d81738fSJack F Vogel /* Enable PHY low-power state when MAC is at D3 w/o WoL */ 51529d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan) 51539d81738fSJack F Vogel reg |= E1000_CTRL_EXT_PHYPDEN; 51548cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); 51558cfa0ad2SJack F Vogel 51568cfa0ad2SJack F Vogel /* Transmit Descriptor Control 0 */ 51578cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); 51588cfa0ad2SJack F Vogel reg |= (1 << 22); 51598cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); 51608cfa0ad2SJack F Vogel 51618cfa0ad2SJack F Vogel /* Transmit Descriptor Control 1 */ 51628cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); 51638cfa0ad2SJack F Vogel reg |= (1 << 22); 51648cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); 51658cfa0ad2SJack F Vogel 51668cfa0ad2SJack F Vogel /* Transmit Arbitration Control 0 */ 51678cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(0)); 51688cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 51698cfa0ad2SJack F Vogel reg |= (1 << 28) | (1 << 29); 51708cfa0ad2SJack F Vogel reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); 51718cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(0), reg); 51728cfa0ad2SJack F Vogel 51738cfa0ad2SJack F Vogel /* Transmit Arbitration Control 1 */ 51748cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(1)); 51758cfa0ad2SJack F Vogel if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) 51768cfa0ad2SJack F Vogel reg &= ~(1 << 28); 51778cfa0ad2SJack F Vogel else 51788cfa0ad2SJack F Vogel reg |= (1 << 28); 51798cfa0ad2SJack F Vogel reg |= (1 << 24) | (1 << 26) | (1 << 30); 51808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(1), reg); 51818cfa0ad2SJack F Vogel 51828cfa0ad2SJack F Vogel /* Device Status */ 51838cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 51848cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_STATUS); 51858cc64f1eSJack F Vogel reg &= ~(1 << 31); 51868cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, reg); 51878cfa0ad2SJack F Vogel } 51888cfa0ad2SJack F Vogel 51896ab6bfe3SJack F Vogel /* work-around descriptor data corruption issue during nfs v2 udp 51908ec87fc5SJack F Vogel * traffic, just disable the nfs filtering capability 51918ec87fc5SJack F Vogel */ 51928ec87fc5SJack F Vogel reg = E1000_READ_REG(hw, E1000_RFCTL); 51938ec87fc5SJack F Vogel reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); 51947609433eSJack F Vogel 51956ab6bfe3SJack F Vogel /* Disable IPv6 extension header parsing because some malformed 51966ab6bfe3SJack F Vogel * IPv6 headers can hang the Rx. 51976ab6bfe3SJack F Vogel */ 51986ab6bfe3SJack F Vogel if (hw->mac.type == e1000_ich8lan) 51996ab6bfe3SJack F Vogel reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); 52008ec87fc5SJack F Vogel E1000_WRITE_REG(hw, E1000_RFCTL, reg); 52018ec87fc5SJack F Vogel 52026ab6bfe3SJack F Vogel /* Enable ECC on Lynxpoint */ 5203*c80429ceSEric Joyner if ((hw->mac.type == e1000_pch_lpt) || 5204*c80429ceSEric Joyner (hw->mac.type == e1000_pch_spt)) { 52056ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_PBECCSTS); 52066ab6bfe3SJack F Vogel reg |= E1000_PBECCSTS_ECC_ENABLE; 52076ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_PBECCSTS, reg); 52086ab6bfe3SJack F Vogel 52096ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL); 52106ab6bfe3SJack F Vogel reg |= E1000_CTRL_MEHE; 52116ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg); 52126ab6bfe3SJack F Vogel } 52136ab6bfe3SJack F Vogel 52148cfa0ad2SJack F Vogel return; 52158cfa0ad2SJack F Vogel } 52168cfa0ad2SJack F Vogel 52178cfa0ad2SJack F Vogel /** 52188cfa0ad2SJack F Vogel * e1000_setup_link_ich8lan - Setup flow control and link settings 52198cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 52208cfa0ad2SJack F Vogel * 52218cfa0ad2SJack F Vogel * Determines which flow control settings to use, then configures flow 52228cfa0ad2SJack F Vogel * control. Calls the appropriate media-specific link configuration 52238cfa0ad2SJack F Vogel * function. Assuming the adapter has a valid link partner, a valid link 52248cfa0ad2SJack F Vogel * should be established. Assumes the hardware has previously been reset 52258cfa0ad2SJack F Vogel * and the transmitter and receiver are not enabled. 52268cfa0ad2SJack F Vogel **/ 52278cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) 52288cfa0ad2SJack F Vogel { 52296ab6bfe3SJack F Vogel s32 ret_val; 52308cfa0ad2SJack F Vogel 52318cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_link_ich8lan"); 52328cfa0ad2SJack F Vogel 52338cfa0ad2SJack F Vogel if (hw->phy.ops.check_reset_block(hw)) 52346ab6bfe3SJack F Vogel return E1000_SUCCESS; 52358cfa0ad2SJack F Vogel 52366ab6bfe3SJack F Vogel /* ICH parts do not have a word in the NVM to determine 52378cfa0ad2SJack F Vogel * the default flow control setting, so we explicitly 52388cfa0ad2SJack F Vogel * set it to full. 52398cfa0ad2SJack F Vogel */ 5240daf9197cSJack F Vogel if (hw->fc.requested_mode == e1000_fc_default) 5241daf9197cSJack F Vogel hw->fc.requested_mode = e1000_fc_full; 52428cfa0ad2SJack F Vogel 52436ab6bfe3SJack F Vogel /* Save off the requested flow control mode for use later. Depending 5244daf9197cSJack F Vogel * on the link partner's capabilities, we may or may not use this mode. 5245daf9197cSJack F Vogel */ 5246daf9197cSJack F Vogel hw->fc.current_mode = hw->fc.requested_mode; 52478cfa0ad2SJack F Vogel 5248daf9197cSJack F Vogel DEBUGOUT1("After fix-ups FlowControl is now = %x\n", 5249daf9197cSJack F Vogel hw->fc.current_mode); 52508cfa0ad2SJack F Vogel 52518cfa0ad2SJack F Vogel /* Continue to configure the copper link. */ 52528cfa0ad2SJack F Vogel ret_val = hw->mac.ops.setup_physical_interface(hw); 52538cfa0ad2SJack F Vogel if (ret_val) 52546ab6bfe3SJack F Vogel return ret_val; 52558cfa0ad2SJack F Vogel 52568cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); 52579d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 52587d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) || 52596ab6bfe3SJack F Vogel (hw->phy.type == e1000_phy_i217) || 52609d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 52617d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time); 52627d9119bdSJack F Vogel 52639d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, 52649d81738fSJack F Vogel PHY_REG(BM_PORT_CTRL_PAGE, 27), 52659d81738fSJack F Vogel hw->fc.pause_time); 52669d81738fSJack F Vogel if (ret_val) 52676ab6bfe3SJack F Vogel return ret_val; 52689d81738fSJack F Vogel } 52698cfa0ad2SJack F Vogel 52706ab6bfe3SJack F Vogel return e1000_set_fc_watermarks_generic(hw); 52718cfa0ad2SJack F Vogel } 52728cfa0ad2SJack F Vogel 52738cfa0ad2SJack F Vogel /** 52748cfa0ad2SJack F Vogel * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface 52758cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 52768cfa0ad2SJack F Vogel * 52778cfa0ad2SJack F Vogel * Configures the kumeran interface to the PHY to wait the appropriate time 52788cfa0ad2SJack F Vogel * when polling the PHY, then call the generic setup_copper_link to finish 52798cfa0ad2SJack F Vogel * configuring the copper link. 52808cfa0ad2SJack F Vogel **/ 52818cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) 52828cfa0ad2SJack F Vogel { 52838cfa0ad2SJack F Vogel u32 ctrl; 52848cfa0ad2SJack F Vogel s32 ret_val; 52858cfa0ad2SJack F Vogel u16 reg_data; 52868cfa0ad2SJack F Vogel 52878cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_ich8lan"); 52888cfa0ad2SJack F Vogel 52898cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 52908cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_SLU; 52918cfa0ad2SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 52928cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 52938cfa0ad2SJack F Vogel 52946ab6bfe3SJack F Vogel /* Set the mac to wait the maximum time between each iteration 52958cfa0ad2SJack F Vogel * and increase the max iterations when polling the phy; 52968cfa0ad2SJack F Vogel * this fixes erroneous timeouts at 10Mbps. 52978cfa0ad2SJack F Vogel */ 52984edd8523SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS, 52998cfa0ad2SJack F Vogel 0xFFFF); 53008cfa0ad2SJack F Vogel if (ret_val) 53016ab6bfe3SJack F Vogel return ret_val; 53029d81738fSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 53039d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 53048cfa0ad2SJack F Vogel ®_data); 53058cfa0ad2SJack F Vogel if (ret_val) 53066ab6bfe3SJack F Vogel return ret_val; 53078cfa0ad2SJack F Vogel reg_data |= 0x3F; 53089d81738fSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 53099d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 53108cfa0ad2SJack F Vogel reg_data); 53118cfa0ad2SJack F Vogel if (ret_val) 53126ab6bfe3SJack F Vogel return ret_val; 53138cfa0ad2SJack F Vogel 5314d035aa2dSJack F Vogel switch (hw->phy.type) { 5315d035aa2dSJack F Vogel case e1000_phy_igp_3: 53168cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_igp(hw); 53178cfa0ad2SJack F Vogel if (ret_val) 53186ab6bfe3SJack F Vogel return ret_val; 5319d035aa2dSJack F Vogel break; 5320d035aa2dSJack F Vogel case e1000_phy_bm: 53219d81738fSJack F Vogel case e1000_phy_82578: 53228cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_m88(hw); 53238cfa0ad2SJack F Vogel if (ret_val) 53246ab6bfe3SJack F Vogel return ret_val; 5325d035aa2dSJack F Vogel break; 53269d81738fSJack F Vogel case e1000_phy_82577: 53277d9119bdSJack F Vogel case e1000_phy_82579: 53289d81738fSJack F Vogel ret_val = e1000_copper_link_setup_82577(hw); 53299d81738fSJack F Vogel if (ret_val) 53306ab6bfe3SJack F Vogel return ret_val; 53319d81738fSJack F Vogel break; 5332d035aa2dSJack F Vogel case e1000_phy_ife: 53338cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, 53348cfa0ad2SJack F Vogel ®_data); 53358cfa0ad2SJack F Vogel if (ret_val) 53366ab6bfe3SJack F Vogel return ret_val; 53378cfa0ad2SJack F Vogel 53388cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_AUTO_MDIX; 53398cfa0ad2SJack F Vogel 53408cfa0ad2SJack F Vogel switch (hw->phy.mdix) { 53418cfa0ad2SJack F Vogel case 1: 53428cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_FORCE_MDIX; 53438cfa0ad2SJack F Vogel break; 53448cfa0ad2SJack F Vogel case 2: 53458cfa0ad2SJack F Vogel reg_data |= IFE_PMC_FORCE_MDIX; 53468cfa0ad2SJack F Vogel break; 53478cfa0ad2SJack F Vogel case 0: 53488cfa0ad2SJack F Vogel default: 53498cfa0ad2SJack F Vogel reg_data |= IFE_PMC_AUTO_MDIX; 53508cfa0ad2SJack F Vogel break; 53518cfa0ad2SJack F Vogel } 53528cfa0ad2SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, 53538cfa0ad2SJack F Vogel reg_data); 53548cfa0ad2SJack F Vogel if (ret_val) 53556ab6bfe3SJack F Vogel return ret_val; 5356d035aa2dSJack F Vogel break; 5357d035aa2dSJack F Vogel default: 5358d035aa2dSJack F Vogel break; 53598cfa0ad2SJack F Vogel } 53608cfa0ad2SJack F Vogel 53616ab6bfe3SJack F Vogel return e1000_setup_copper_link_generic(hw); 53626ab6bfe3SJack F Vogel } 53636ab6bfe3SJack F Vogel 53646ab6bfe3SJack F Vogel /** 53656ab6bfe3SJack F Vogel * e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface 53666ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 53676ab6bfe3SJack F Vogel * 53686ab6bfe3SJack F Vogel * Calls the PHY specific link setup function and then calls the 53696ab6bfe3SJack F Vogel * generic setup_copper_link to finish configuring the link for 53706ab6bfe3SJack F Vogel * Lynxpoint PCH devices 53716ab6bfe3SJack F Vogel **/ 53726ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw) 53736ab6bfe3SJack F Vogel { 53746ab6bfe3SJack F Vogel u32 ctrl; 53756ab6bfe3SJack F Vogel s32 ret_val; 53766ab6bfe3SJack F Vogel 53776ab6bfe3SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_pch_lpt"); 53786ab6bfe3SJack F Vogel 53796ab6bfe3SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 53806ab6bfe3SJack F Vogel ctrl |= E1000_CTRL_SLU; 53816ab6bfe3SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 53826ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 53836ab6bfe3SJack F Vogel 53846ab6bfe3SJack F Vogel ret_val = e1000_copper_link_setup_82577(hw); 53856ab6bfe3SJack F Vogel if (ret_val) 53868cfa0ad2SJack F Vogel return ret_val; 53876ab6bfe3SJack F Vogel 53886ab6bfe3SJack F Vogel return e1000_setup_copper_link_generic(hw); 53898cfa0ad2SJack F Vogel } 53908cfa0ad2SJack F Vogel 53918cfa0ad2SJack F Vogel /** 53928cfa0ad2SJack F Vogel * e1000_get_link_up_info_ich8lan - Get current link speed and duplex 53938cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 53948cfa0ad2SJack F Vogel * @speed: pointer to store current link speed 53958cfa0ad2SJack F Vogel * @duplex: pointer to store the current link duplex 53968cfa0ad2SJack F Vogel * 53978cfa0ad2SJack F Vogel * Calls the generic get_speed_and_duplex to retrieve the current link 53988cfa0ad2SJack F Vogel * information and then calls the Kumeran lock loss workaround for links at 53998cfa0ad2SJack F Vogel * gigabit speeds. 54008cfa0ad2SJack F Vogel **/ 54018cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, 54028cfa0ad2SJack F Vogel u16 *duplex) 54038cfa0ad2SJack F Vogel { 54048cfa0ad2SJack F Vogel s32 ret_val; 54058cfa0ad2SJack F Vogel 54068cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_link_up_info_ich8lan"); 54078cfa0ad2SJack F Vogel 54088cfa0ad2SJack F Vogel ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); 54098cfa0ad2SJack F Vogel if (ret_val) 54106ab6bfe3SJack F Vogel return ret_val; 54118cfa0ad2SJack F Vogel 54128cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_ich8lan) && 54138cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3) && 54148cfa0ad2SJack F Vogel (*speed == SPEED_1000)) { 54158cfa0ad2SJack F Vogel ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); 54168cfa0ad2SJack F Vogel } 54178cfa0ad2SJack F Vogel 54188cfa0ad2SJack F Vogel return ret_val; 54198cfa0ad2SJack F Vogel } 54208cfa0ad2SJack F Vogel 54218cfa0ad2SJack F Vogel /** 54228cfa0ad2SJack F Vogel * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround 54238cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 54248cfa0ad2SJack F Vogel * 54258cfa0ad2SJack F Vogel * Work-around for 82566 Kumeran PCS lock loss: 54268cfa0ad2SJack F Vogel * On link status change (i.e. PCI reset, speed change) and link is up and 54278cfa0ad2SJack F Vogel * speed is gigabit- 54288cfa0ad2SJack F Vogel * 0) if workaround is optionally disabled do nothing 54298cfa0ad2SJack F Vogel * 1) wait 1ms for Kumeran link to come up 54308cfa0ad2SJack F Vogel * 2) check Kumeran Diagnostic register PCS lock loss bit 54318cfa0ad2SJack F Vogel * 3) if not set the link is locked (all is good), otherwise... 54328cfa0ad2SJack F Vogel * 4) reset the PHY 54338cfa0ad2SJack F Vogel * 5) repeat up to 10 times 54348cfa0ad2SJack F Vogel * Note: this is only called for IGP3 copper when speed is 1gb. 54358cfa0ad2SJack F Vogel **/ 54368cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) 54378cfa0ad2SJack F Vogel { 5438daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 54398cfa0ad2SJack F Vogel u32 phy_ctrl; 54406ab6bfe3SJack F Vogel s32 ret_val; 54418cfa0ad2SJack F Vogel u16 i, data; 54428cfa0ad2SJack F Vogel bool link; 54438cfa0ad2SJack F Vogel 54448cfa0ad2SJack F Vogel DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan"); 54458cfa0ad2SJack F Vogel 5446730d3130SJack F Vogel if (!dev_spec->kmrn_lock_loss_workaround_enabled) 54476ab6bfe3SJack F Vogel return E1000_SUCCESS; 54488cfa0ad2SJack F Vogel 54496ab6bfe3SJack F Vogel /* Make sure link is up before proceeding. If not just return. 54508cfa0ad2SJack F Vogel * Attempting this while link is negotiating fouled up link 54518cfa0ad2SJack F Vogel * stability 54528cfa0ad2SJack F Vogel */ 54538cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 54546ab6bfe3SJack F Vogel if (!link) 54556ab6bfe3SJack F Vogel return E1000_SUCCESS; 54568cfa0ad2SJack F Vogel 54578cfa0ad2SJack F Vogel for (i = 0; i < 10; i++) { 54588cfa0ad2SJack F Vogel /* read once to clear */ 54598cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 54608cfa0ad2SJack F Vogel if (ret_val) 54616ab6bfe3SJack F Vogel return ret_val; 54628cfa0ad2SJack F Vogel /* and again to get new status */ 54638cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 54648cfa0ad2SJack F Vogel if (ret_val) 54656ab6bfe3SJack F Vogel return ret_val; 54668cfa0ad2SJack F Vogel 54678cfa0ad2SJack F Vogel /* check for PCS lock */ 54686ab6bfe3SJack F Vogel if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) 54696ab6bfe3SJack F Vogel return E1000_SUCCESS; 54708cfa0ad2SJack F Vogel 54718cfa0ad2SJack F Vogel /* Issue PHY reset */ 54728cfa0ad2SJack F Vogel hw->phy.ops.reset(hw); 54738cfa0ad2SJack F Vogel msec_delay_irq(5); 54748cfa0ad2SJack F Vogel } 54758cfa0ad2SJack F Vogel /* Disable GigE link negotiation */ 54768cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 54778cfa0ad2SJack F Vogel phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | 54788cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 54798cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 54808cfa0ad2SJack F Vogel 54816ab6bfe3SJack F Vogel /* Call gig speed drop workaround on Gig disable before accessing 54828cfa0ad2SJack F Vogel * any PHY registers 54838cfa0ad2SJack F Vogel */ 54848cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 54858cfa0ad2SJack F Vogel 54868cfa0ad2SJack F Vogel /* unable to acquire PCS lock */ 54876ab6bfe3SJack F Vogel return -E1000_ERR_PHY; 54888cfa0ad2SJack F Vogel } 54898cfa0ad2SJack F Vogel 54908cfa0ad2SJack F Vogel /** 54918cfa0ad2SJack F Vogel * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state 54928cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 54938cfa0ad2SJack F Vogel * @state: boolean value used to set the current Kumeran workaround state 54948cfa0ad2SJack F Vogel * 54958cfa0ad2SJack F Vogel * If ICH8, set the current Kumeran workaround state (enabled - TRUE 54968cfa0ad2SJack F Vogel * /disabled - FALSE). 54978cfa0ad2SJack F Vogel **/ 54988cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, 54998cfa0ad2SJack F Vogel bool state) 55008cfa0ad2SJack F Vogel { 5501daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 55028cfa0ad2SJack F Vogel 55038cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan"); 55048cfa0ad2SJack F Vogel 55058cfa0ad2SJack F Vogel if (hw->mac.type != e1000_ich8lan) { 55068cfa0ad2SJack F Vogel DEBUGOUT("Workaround applies to ICH8 only.\n"); 5507daf9197cSJack F Vogel return; 55088cfa0ad2SJack F Vogel } 55098cfa0ad2SJack F Vogel 55108cfa0ad2SJack F Vogel dev_spec->kmrn_lock_loss_workaround_enabled = state; 55118cfa0ad2SJack F Vogel 55128cfa0ad2SJack F Vogel return; 55138cfa0ad2SJack F Vogel } 55148cfa0ad2SJack F Vogel 55158cfa0ad2SJack F Vogel /** 55168cfa0ad2SJack F Vogel * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 55178cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 55188cfa0ad2SJack F Vogel * 55198cfa0ad2SJack F Vogel * Workaround for 82566 power-down on D3 entry: 55208cfa0ad2SJack F Vogel * 1) disable gigabit link 55218cfa0ad2SJack F Vogel * 2) write VR power-down enable 55228cfa0ad2SJack F Vogel * 3) read it back 55238cfa0ad2SJack F Vogel * Continue if successful, else issue LCD reset and repeat 55248cfa0ad2SJack F Vogel **/ 55258cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) 55268cfa0ad2SJack F Vogel { 55278cfa0ad2SJack F Vogel u32 reg; 55288cfa0ad2SJack F Vogel u16 data; 55298cfa0ad2SJack F Vogel u8 retry = 0; 55308cfa0ad2SJack F Vogel 55318cfa0ad2SJack F Vogel DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan"); 55328cfa0ad2SJack F Vogel 55338cfa0ad2SJack F Vogel if (hw->phy.type != e1000_phy_igp_3) 55346ab6bfe3SJack F Vogel return; 55358cfa0ad2SJack F Vogel 55368cfa0ad2SJack F Vogel /* Try the workaround twice (if needed) */ 55378cfa0ad2SJack F Vogel do { 55388cfa0ad2SJack F Vogel /* Disable link */ 55398cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 55408cfa0ad2SJack F Vogel reg |= (E1000_PHY_CTRL_GBE_DISABLE | 55418cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 55428cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg); 55438cfa0ad2SJack F Vogel 55446ab6bfe3SJack F Vogel /* Call gig speed drop workaround on Gig disable before 55458cfa0ad2SJack F Vogel * accessing any PHY registers 55468cfa0ad2SJack F Vogel */ 55478cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 55488cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 55498cfa0ad2SJack F Vogel 55508cfa0ad2SJack F Vogel /* Write VR power-down enable */ 55518cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 55528cfa0ad2SJack F Vogel data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 5553daf9197cSJack F Vogel hw->phy.ops.write_reg(hw, IGP3_VR_CTRL, 55548cfa0ad2SJack F Vogel data | IGP3_VR_CTRL_MODE_SHUTDOWN); 55558cfa0ad2SJack F Vogel 55568cfa0ad2SJack F Vogel /* Read it back and test */ 55578cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 55588cfa0ad2SJack F Vogel data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 55598cfa0ad2SJack F Vogel if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) 55608cfa0ad2SJack F Vogel break; 55618cfa0ad2SJack F Vogel 55628cfa0ad2SJack F Vogel /* Issue PHY reset and repeat at most one more time */ 55638cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL); 55648cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST); 55658cfa0ad2SJack F Vogel retry++; 55668cfa0ad2SJack F Vogel } while (retry); 55678cfa0ad2SJack F Vogel } 55688cfa0ad2SJack F Vogel 55698cfa0ad2SJack F Vogel /** 55708cfa0ad2SJack F Vogel * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working 55718cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 55728cfa0ad2SJack F Vogel * 55738cfa0ad2SJack F Vogel * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), 55748cfa0ad2SJack F Vogel * LPLU, Gig disable, MDIC PHY reset): 55758cfa0ad2SJack F Vogel * 1) Set Kumeran Near-end loopback 55768cfa0ad2SJack F Vogel * 2) Clear Kumeran Near-end loopback 55774dab5c37SJack F Vogel * Should only be called for ICH8[m] devices with any 1G Phy. 55788cfa0ad2SJack F Vogel **/ 55798cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) 55808cfa0ad2SJack F Vogel { 55816ab6bfe3SJack F Vogel s32 ret_val; 55828cfa0ad2SJack F Vogel u16 reg_data; 55838cfa0ad2SJack F Vogel 55848cfa0ad2SJack F Vogel DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); 55858cfa0ad2SJack F Vogel 55868cfa0ad2SJack F Vogel if ((hw->mac.type != e1000_ich8lan) || 55874dab5c37SJack F Vogel (hw->phy.type == e1000_phy_ife)) 55886ab6bfe3SJack F Vogel return; 55898cfa0ad2SJack F Vogel 55908cfa0ad2SJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 55918cfa0ad2SJack F Vogel ®_data); 55928cfa0ad2SJack F Vogel if (ret_val) 55936ab6bfe3SJack F Vogel return; 55948cfa0ad2SJack F Vogel reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; 55958cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 55968cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET, 55978cfa0ad2SJack F Vogel reg_data); 55988cfa0ad2SJack F Vogel if (ret_val) 55998cfa0ad2SJack F Vogel return; 56006ab6bfe3SJack F Vogel reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; 56016ab6bfe3SJack F Vogel e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 56026ab6bfe3SJack F Vogel reg_data); 56038cfa0ad2SJack F Vogel } 56048cfa0ad2SJack F Vogel 56058cfa0ad2SJack F Vogel /** 56064dab5c37SJack F Vogel * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx 56078cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 56088cfa0ad2SJack F Vogel * 56098cfa0ad2SJack F Vogel * During S0 to Sx transition, it is possible the link remains at gig 56108cfa0ad2SJack F Vogel * instead of negotiating to a lower speed. Before going to Sx, set 56114dab5c37SJack F Vogel * 'Gig Disable' to force link speed negotiation to a lower speed based on 56124dab5c37SJack F Vogel * the LPLU setting in the NVM or custom setting. For PCH and newer parts, 56134dab5c37SJack F Vogel * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also 56144dab5c37SJack F Vogel * needs to be written. 56156ab6bfe3SJack F Vogel * Parts that support (and are linked to a partner which support) EEE in 56166ab6bfe3SJack F Vogel * 100Mbps should disable LPLU since 100Mbps w/ EEE requires less power 56176ab6bfe3SJack F Vogel * than 10Mbps w/o EEE. 56188cfa0ad2SJack F Vogel **/ 56194dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) 56208cfa0ad2SJack F Vogel { 56216ab6bfe3SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 56228cfa0ad2SJack F Vogel u32 phy_ctrl; 56237d9119bdSJack F Vogel s32 ret_val; 56248cfa0ad2SJack F Vogel 56254dab5c37SJack F Vogel DEBUGFUNC("e1000_suspend_workarounds_ich8lan"); 56267d9119bdSJack F Vogel 56278cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 56284dab5c37SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; 56296ab6bfe3SJack F Vogel 56306ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) { 56316ab6bfe3SJack F Vogel u16 phy_reg, device_id = hw->device_id; 56326ab6bfe3SJack F Vogel 56336ab6bfe3SJack F Vogel if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || 56348cc64f1eSJack F Vogel (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || 56358cc64f1eSJack F Vogel (device_id == E1000_DEV_ID_PCH_I218_LM3) || 5636*c80429ceSEric Joyner (device_id == E1000_DEV_ID_PCH_I218_V3) || 5637*c80429ceSEric Joyner (hw->mac.type == e1000_pch_spt)) { 56386ab6bfe3SJack F Vogel u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); 56396ab6bfe3SJack F Vogel 56406ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, 56416ab6bfe3SJack F Vogel fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); 56426ab6bfe3SJack F Vogel } 56436ab6bfe3SJack F Vogel 56446ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 56456ab6bfe3SJack F Vogel if (ret_val) 56466ab6bfe3SJack F Vogel goto out; 56476ab6bfe3SJack F Vogel 56486ab6bfe3SJack F Vogel if (!dev_spec->eee_disable) { 56496ab6bfe3SJack F Vogel u16 eee_advert; 56506ab6bfe3SJack F Vogel 56516ab6bfe3SJack F Vogel ret_val = 56526ab6bfe3SJack F Vogel e1000_read_emi_reg_locked(hw, 56536ab6bfe3SJack F Vogel I217_EEE_ADVERTISEMENT, 56546ab6bfe3SJack F Vogel &eee_advert); 56556ab6bfe3SJack F Vogel if (ret_val) 56566ab6bfe3SJack F Vogel goto release; 56576ab6bfe3SJack F Vogel 56586ab6bfe3SJack F Vogel /* Disable LPLU if both link partners support 100BaseT 56596ab6bfe3SJack F Vogel * EEE and 100Full is advertised on both ends of the 56607609433eSJack F Vogel * link, and enable Auto Enable LPI since there will 56617609433eSJack F Vogel * be no driver to enable LPI while in Sx. 56626ab6bfe3SJack F Vogel */ 56636ab6bfe3SJack F Vogel if ((eee_advert & I82579_EEE_100_SUPPORTED) && 56646ab6bfe3SJack F Vogel (dev_spec->eee_lp_ability & 56656ab6bfe3SJack F Vogel I82579_EEE_100_SUPPORTED) && 56667609433eSJack F Vogel (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) { 56676ab6bfe3SJack F Vogel phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU | 56686ab6bfe3SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU); 56697609433eSJack F Vogel 56707609433eSJack F Vogel /* Set Auto Enable LPI after link up */ 56717609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, 56727609433eSJack F Vogel I217_LPI_GPIO_CTRL, 56737609433eSJack F Vogel &phy_reg); 56747609433eSJack F Vogel phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI; 56757609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, 56767609433eSJack F Vogel I217_LPI_GPIO_CTRL, 56777609433eSJack F Vogel phy_reg); 56787609433eSJack F Vogel } 56796ab6bfe3SJack F Vogel } 56806ab6bfe3SJack F Vogel 56816ab6bfe3SJack F Vogel /* For i217 Intel Rapid Start Technology support, 56826ab6bfe3SJack F Vogel * when the system is going into Sx and no manageability engine 56836ab6bfe3SJack F Vogel * is present, the driver must configure proxy to reset only on 56846ab6bfe3SJack F Vogel * power good. LPI (Low Power Idle) state must also reset only 56856ab6bfe3SJack F Vogel * on power good, as well as the MTA (Multicast table array). 56866ab6bfe3SJack F Vogel * The SMBus release must also be disabled on LCD reset. 56876ab6bfe3SJack F Vogel */ 56886ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 56896ab6bfe3SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 56906ab6bfe3SJack F Vogel /* Enable proxy to reset only on power good. */ 56916ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_PROXY_CTRL, 56926ab6bfe3SJack F Vogel &phy_reg); 56936ab6bfe3SJack F Vogel phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE; 56946ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 56956ab6bfe3SJack F Vogel phy_reg); 56966ab6bfe3SJack F Vogel 56976ab6bfe3SJack F Vogel /* Set bit enable LPI (EEE) to reset only on 56986ab6bfe3SJack F Vogel * power good. 56996ab6bfe3SJack F Vogel */ 57006ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_SxCTRL, &phy_reg); 57016ab6bfe3SJack F Vogel phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET; 57026ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_SxCTRL, phy_reg); 57036ab6bfe3SJack F Vogel 57046ab6bfe3SJack F Vogel /* Disable the SMB release on LCD reset. */ 57056ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, &phy_reg); 57066ab6bfe3SJack F Vogel phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE; 57076ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg); 57086ab6bfe3SJack F Vogel } 57096ab6bfe3SJack F Vogel 57106ab6bfe3SJack F Vogel /* Enable MTA to reset for Intel Rapid Start Technology 57116ab6bfe3SJack F Vogel * Support 57126ab6bfe3SJack F Vogel */ 57136ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_CGFREG, &phy_reg); 57146ab6bfe3SJack F Vogel phy_reg |= I217_CGFREG_ENABLE_MTA_RESET; 57156ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg); 57166ab6bfe3SJack F Vogel 57176ab6bfe3SJack F Vogel release: 57186ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 57196ab6bfe3SJack F Vogel } 57206ab6bfe3SJack F Vogel out: 57218cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 57226ab6bfe3SJack F Vogel 57234dab5c37SJack F Vogel if (hw->mac.type == e1000_ich8lan) 57244dab5c37SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 57259d81738fSJack F Vogel 57267d9119bdSJack F Vogel if (hw->mac.type >= e1000_pchlan) { 57277d9119bdSJack F Vogel e1000_oem_bits_config_ich8lan(hw, FALSE); 57286ab6bfe3SJack F Vogel 57296ab6bfe3SJack F Vogel /* Reset PHY to activate OEM bits on 82577/8 */ 57306ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pchlan) 57316ab6bfe3SJack F Vogel e1000_phy_hw_reset_generic(hw); 57326ab6bfe3SJack F Vogel 57337d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 57347d9119bdSJack F Vogel if (ret_val) 57357d9119bdSJack F Vogel return; 57367d9119bdSJack F Vogel e1000_write_smbus_addr(hw); 57377d9119bdSJack F Vogel hw->phy.ops.release(hw); 57388cfa0ad2SJack F Vogel } 57398cfa0ad2SJack F Vogel 57408cfa0ad2SJack F Vogel return; 57418cfa0ad2SJack F Vogel } 57428cfa0ad2SJack F Vogel 57438cfa0ad2SJack F Vogel /** 57444dab5c37SJack F Vogel * e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0 57454dab5c37SJack F Vogel * @hw: pointer to the HW structure 57464dab5c37SJack F Vogel * 57474dab5c37SJack F Vogel * During Sx to S0 transitions on non-managed devices or managed devices 57484dab5c37SJack F Vogel * on which PHY resets are not blocked, if the PHY registers cannot be 57494dab5c37SJack F Vogel * accessed properly by the s/w toggle the LANPHYPC value to power cycle 57504dab5c37SJack F Vogel * the PHY. 57516ab6bfe3SJack F Vogel * On i217, setup Intel Rapid Start Technology. 57524dab5c37SJack F Vogel **/ 5753*c80429ceSEric Joyner u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw) 57544dab5c37SJack F Vogel { 57554dab5c37SJack F Vogel s32 ret_val; 57564dab5c37SJack F Vogel 57574dab5c37SJack F Vogel DEBUGFUNC("e1000_resume_workarounds_pchlan"); 57586ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan) 5759*c80429ceSEric Joyner return E1000_SUCCESS; 57604dab5c37SJack F Vogel 57616ab6bfe3SJack F Vogel ret_val = e1000_init_phy_workarounds_pchlan(hw); 57624dab5c37SJack F Vogel if (ret_val) { 57636ab6bfe3SJack F Vogel DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val); 5764*c80429ceSEric Joyner return ret_val; 57654dab5c37SJack F Vogel } 57664dab5c37SJack F Vogel 57676ab6bfe3SJack F Vogel /* For i217 Intel Rapid Start Technology support when the system 57686ab6bfe3SJack F Vogel * is transitioning from Sx and no manageability engine is present 57696ab6bfe3SJack F Vogel * configure SMBus to restore on reset, disable proxy, and enable 57706ab6bfe3SJack F Vogel * the reset on MTA (Multicast table array). 57716ab6bfe3SJack F Vogel */ 57726ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) { 57736ab6bfe3SJack F Vogel u16 phy_reg; 57744dab5c37SJack F Vogel 57756ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 57766ab6bfe3SJack F Vogel if (ret_val) { 57776ab6bfe3SJack F Vogel DEBUGOUT("Failed to setup iRST\n"); 5778*c80429ceSEric Joyner return ret_val; 57796ab6bfe3SJack F Vogel } 57804dab5c37SJack F Vogel 57817609433eSJack F Vogel /* Clear Auto Enable LPI after link up */ 57827609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg); 57837609433eSJack F Vogel phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI; 57847609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg); 57857609433eSJack F Vogel 57866ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 57876ab6bfe3SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 57886ab6bfe3SJack F Vogel /* Restore clear on SMB if no manageability engine 57896ab6bfe3SJack F Vogel * is present 57906ab6bfe3SJack F Vogel */ 57916ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, 57926ab6bfe3SJack F Vogel &phy_reg); 57936ab6bfe3SJack F Vogel if (ret_val) 57946ab6bfe3SJack F Vogel goto release; 57956ab6bfe3SJack F Vogel phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE; 57966ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg); 57976ab6bfe3SJack F Vogel 57986ab6bfe3SJack F Vogel /* Disable Proxy */ 57996ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 0); 58006ab6bfe3SJack F Vogel } 58016ab6bfe3SJack F Vogel /* Enable reset on MTA */ 58026ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I217_CGFREG, 58036ab6bfe3SJack F Vogel &phy_reg); 58046ab6bfe3SJack F Vogel if (ret_val) 58056ab6bfe3SJack F Vogel goto release; 58066ab6bfe3SJack F Vogel phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET; 58076ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg); 58084dab5c37SJack F Vogel release: 58096ab6bfe3SJack F Vogel if (ret_val) 58106ab6bfe3SJack F Vogel DEBUGOUT1("Error %d in resume workarounds\n", ret_val); 58114dab5c37SJack F Vogel hw->phy.ops.release(hw); 5812*c80429ceSEric Joyner return ret_val; 58136ab6bfe3SJack F Vogel } 5814*c80429ceSEric Joyner return E1000_SUCCESS; 58154dab5c37SJack F Vogel } 58164dab5c37SJack F Vogel 58174dab5c37SJack F Vogel /** 58188cfa0ad2SJack F Vogel * e1000_cleanup_led_ich8lan - Restore the default LED operation 58198cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 58208cfa0ad2SJack F Vogel * 58218cfa0ad2SJack F Vogel * Return the LED back to the default configuration. 58228cfa0ad2SJack F Vogel **/ 58238cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) 58248cfa0ad2SJack F Vogel { 58258cfa0ad2SJack F Vogel DEBUGFUNC("e1000_cleanup_led_ich8lan"); 58268cfa0ad2SJack F Vogel 58278cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 5828a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 58298cfa0ad2SJack F Vogel 0); 58308cfa0ad2SJack F Vogel 5831a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); 5832a69ed8dfSJack F Vogel return E1000_SUCCESS; 58338cfa0ad2SJack F Vogel } 58348cfa0ad2SJack F Vogel 58358cfa0ad2SJack F Vogel /** 58368cfa0ad2SJack F Vogel * e1000_led_on_ich8lan - Turn LEDs on 58378cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 58388cfa0ad2SJack F Vogel * 58398cfa0ad2SJack F Vogel * Turn on the LEDs. 58408cfa0ad2SJack F Vogel **/ 58418cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) 58428cfa0ad2SJack F Vogel { 58438cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_on_ich8lan"); 58448cfa0ad2SJack F Vogel 58458cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 5846a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 58478cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); 58488cfa0ad2SJack F Vogel 5849a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); 5850a69ed8dfSJack F Vogel return E1000_SUCCESS; 58518cfa0ad2SJack F Vogel } 58528cfa0ad2SJack F Vogel 58538cfa0ad2SJack F Vogel /** 58548cfa0ad2SJack F Vogel * e1000_led_off_ich8lan - Turn LEDs off 58558cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 58568cfa0ad2SJack F Vogel * 58578cfa0ad2SJack F Vogel * Turn off the LEDs. 58588cfa0ad2SJack F Vogel **/ 58598cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) 58608cfa0ad2SJack F Vogel { 58618cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_off_ich8lan"); 58628cfa0ad2SJack F Vogel 58638cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 5864a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 58658cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); 58668cfa0ad2SJack F Vogel 5867a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); 5868a69ed8dfSJack F Vogel return E1000_SUCCESS; 58698cfa0ad2SJack F Vogel } 58708cfa0ad2SJack F Vogel 58718cfa0ad2SJack F Vogel /** 58729d81738fSJack F Vogel * e1000_setup_led_pchlan - Configures SW controllable LED 58739d81738fSJack F Vogel * @hw: pointer to the HW structure 58749d81738fSJack F Vogel * 58759d81738fSJack F Vogel * This prepares the SW controllable LED for use. 58769d81738fSJack F Vogel **/ 58779d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) 58789d81738fSJack F Vogel { 58799d81738fSJack F Vogel DEBUGFUNC("e1000_setup_led_pchlan"); 58809d81738fSJack F Vogel 58819d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 58829d81738fSJack F Vogel (u16)hw->mac.ledctl_mode1); 58839d81738fSJack F Vogel } 58849d81738fSJack F Vogel 58859d81738fSJack F Vogel /** 58869d81738fSJack F Vogel * e1000_cleanup_led_pchlan - Restore the default LED operation 58879d81738fSJack F Vogel * @hw: pointer to the HW structure 58889d81738fSJack F Vogel * 58899d81738fSJack F Vogel * Return the LED back to the default configuration. 58909d81738fSJack F Vogel **/ 58919d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) 58929d81738fSJack F Vogel { 58939d81738fSJack F Vogel DEBUGFUNC("e1000_cleanup_led_pchlan"); 58949d81738fSJack F Vogel 58959d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 58969d81738fSJack F Vogel (u16)hw->mac.ledctl_default); 58979d81738fSJack F Vogel } 58989d81738fSJack F Vogel 58999d81738fSJack F Vogel /** 59009d81738fSJack F Vogel * e1000_led_on_pchlan - Turn LEDs on 59019d81738fSJack F Vogel * @hw: pointer to the HW structure 59029d81738fSJack F Vogel * 59039d81738fSJack F Vogel * Turn on the LEDs. 59049d81738fSJack F Vogel **/ 59059d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw) 59069d81738fSJack F Vogel { 59079d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode2; 59089d81738fSJack F Vogel u32 i, led; 59099d81738fSJack F Vogel 59109d81738fSJack F Vogel DEBUGFUNC("e1000_led_on_pchlan"); 59119d81738fSJack F Vogel 59126ab6bfe3SJack F Vogel /* If no link, then turn LED on by setting the invert bit 59139d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode2. 59149d81738fSJack F Vogel */ 59159d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 59169d81738fSJack F Vogel for (i = 0; i < 3; i++) { 59179d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 59189d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 59199d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 59209d81738fSJack F Vogel continue; 59219d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 59229d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 59239d81738fSJack F Vogel else 59249d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 59259d81738fSJack F Vogel } 59269d81738fSJack F Vogel } 59279d81738fSJack F Vogel 59289d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 59299d81738fSJack F Vogel } 59309d81738fSJack F Vogel 59319d81738fSJack F Vogel /** 59329d81738fSJack F Vogel * e1000_led_off_pchlan - Turn LEDs off 59339d81738fSJack F Vogel * @hw: pointer to the HW structure 59349d81738fSJack F Vogel * 59359d81738fSJack F Vogel * Turn off the LEDs. 59369d81738fSJack F Vogel **/ 59379d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw) 59389d81738fSJack F Vogel { 59399d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode1; 59409d81738fSJack F Vogel u32 i, led; 59419d81738fSJack F Vogel 59429d81738fSJack F Vogel DEBUGFUNC("e1000_led_off_pchlan"); 59439d81738fSJack F Vogel 59446ab6bfe3SJack F Vogel /* If no link, then turn LED off by clearing the invert bit 59459d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode1. 59469d81738fSJack F Vogel */ 59479d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 59489d81738fSJack F Vogel for (i = 0; i < 3; i++) { 59499d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 59509d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 59519d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 59529d81738fSJack F Vogel continue; 59539d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 59549d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 59559d81738fSJack F Vogel else 59569d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 59579d81738fSJack F Vogel } 59589d81738fSJack F Vogel } 59599d81738fSJack F Vogel 59609d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 59619d81738fSJack F Vogel } 59629d81738fSJack F Vogel 59639d81738fSJack F Vogel /** 59647d9119bdSJack F Vogel * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset 59658cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 59668cfa0ad2SJack F Vogel * 59677d9119bdSJack F Vogel * Read appropriate register for the config done bit for completion status 59687d9119bdSJack F Vogel * and configure the PHY through s/w for EEPROM-less parts. 59697d9119bdSJack F Vogel * 59707d9119bdSJack F Vogel * NOTE: some silicon which is EEPROM-less will fail trying to read the 59717d9119bdSJack F Vogel * config done bit, so only an error is logged and continues. If we were 59727d9119bdSJack F Vogel * to return with error, EEPROM-less silicon would not be able to be reset 59737d9119bdSJack F Vogel * or change link. 59748cfa0ad2SJack F Vogel **/ 59758cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) 59768cfa0ad2SJack F Vogel { 59778cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 59788cfa0ad2SJack F Vogel u32 bank = 0; 59797d9119bdSJack F Vogel u32 status; 59808cfa0ad2SJack F Vogel 59817d9119bdSJack F Vogel DEBUGFUNC("e1000_get_cfg_done_ich8lan"); 59829d81738fSJack F Vogel 59838cfa0ad2SJack F Vogel e1000_get_cfg_done_generic(hw); 59848cfa0ad2SJack F Vogel 59857d9119bdSJack F Vogel /* Wait for indication from h/w that it has completed basic config */ 59867d9119bdSJack F Vogel if (hw->mac.type >= e1000_ich10lan) { 59877d9119bdSJack F Vogel e1000_lan_init_done_ich8lan(hw); 59887d9119bdSJack F Vogel } else { 59897d9119bdSJack F Vogel ret_val = e1000_get_auto_rd_done_generic(hw); 59907d9119bdSJack F Vogel if (ret_val) { 59916ab6bfe3SJack F Vogel /* When auto config read does not complete, do not 59927d9119bdSJack F Vogel * return with an error. This can happen in situations 59937d9119bdSJack F Vogel * where there is no eeprom and prevents getting link. 59947d9119bdSJack F Vogel */ 59957d9119bdSJack F Vogel DEBUGOUT("Auto Read Done did not complete\n"); 59967d9119bdSJack F Vogel ret_val = E1000_SUCCESS; 59977d9119bdSJack F Vogel } 59987d9119bdSJack F Vogel } 59997d9119bdSJack F Vogel 60007d9119bdSJack F Vogel /* Clear PHY Reset Asserted bit */ 60017d9119bdSJack F Vogel status = E1000_READ_REG(hw, E1000_STATUS); 60027d9119bdSJack F Vogel if (status & E1000_STATUS_PHYRA) 60037d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA); 60047d9119bdSJack F Vogel else 60057d9119bdSJack F Vogel DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); 60067d9119bdSJack F Vogel 60078cfa0ad2SJack F Vogel /* If EEPROM is not marked present, init the IGP 3 PHY manually */ 60084edd8523SJack F Vogel if (hw->mac.type <= e1000_ich9lan) { 60096ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) && 60108cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3)) { 60118cfa0ad2SJack F Vogel e1000_phy_init_script_igp3(hw); 60128cfa0ad2SJack F Vogel } 60138cfa0ad2SJack F Vogel } else { 60148cfa0ad2SJack F Vogel if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { 6015daf9197cSJack F Vogel /* Maybe we should do a basic PHY config */ 60168cfa0ad2SJack F Vogel DEBUGOUT("EEPROM not present\n"); 60178cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 60188cfa0ad2SJack F Vogel } 60198cfa0ad2SJack F Vogel } 60208cfa0ad2SJack F Vogel 60218cfa0ad2SJack F Vogel return ret_val; 60228cfa0ad2SJack F Vogel } 60238cfa0ad2SJack F Vogel 60248cfa0ad2SJack F Vogel /** 60258cfa0ad2SJack F Vogel * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down 60268cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 60278cfa0ad2SJack F Vogel * 60288cfa0ad2SJack F Vogel * In the case of a PHY power down to save power, or to turn off link during a 60298cfa0ad2SJack F Vogel * driver unload, or wake on lan is not enabled, remove the link. 60308cfa0ad2SJack F Vogel **/ 60318cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) 60328cfa0ad2SJack F Vogel { 60338cfa0ad2SJack F Vogel /* If the management interface is not enabled, then power down */ 6034daf9197cSJack F Vogel if (!(hw->mac.ops.check_mng_mode(hw) || 6035daf9197cSJack F Vogel hw->phy.ops.check_reset_block(hw))) 60368cfa0ad2SJack F Vogel e1000_power_down_phy_copper(hw); 60378cfa0ad2SJack F Vogel 60388cfa0ad2SJack F Vogel return; 60398cfa0ad2SJack F Vogel } 60408cfa0ad2SJack F Vogel 60418cfa0ad2SJack F Vogel /** 60428cfa0ad2SJack F Vogel * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters 60438cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 60448cfa0ad2SJack F Vogel * 60458cfa0ad2SJack F Vogel * Clears hardware counters specific to the silicon family and calls 60468cfa0ad2SJack F Vogel * clear_hw_cntrs_generic to clear all general purpose counters. 60478cfa0ad2SJack F Vogel **/ 60488cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) 60498cfa0ad2SJack F Vogel { 60509d81738fSJack F Vogel u16 phy_data; 60514dab5c37SJack F Vogel s32 ret_val; 60529d81738fSJack F Vogel 60538cfa0ad2SJack F Vogel DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); 60548cfa0ad2SJack F Vogel 60558cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_base_generic(hw); 60568cfa0ad2SJack F Vogel 6057daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ALGNERRC); 6058daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_RXERRC); 6059daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TNCRS); 6060daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_CEXTERR); 6061daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTC); 6062daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTFC); 60638cfa0ad2SJack F Vogel 6064daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPRC); 6065daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPDC); 6066daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPTC); 60678cfa0ad2SJack F Vogel 6068daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_IAC); 6069daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ICRXOC); 60709d81738fSJack F Vogel 60719d81738fSJack F Vogel /* Clear PHY statistics registers */ 60729d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 60737d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) || 60746ab6bfe3SJack F Vogel (hw->phy.type == e1000_phy_i217) || 60759d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 60764dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 60774dab5c37SJack F Vogel if (ret_val) 60784dab5c37SJack F Vogel return; 60794dab5c37SJack F Vogel ret_val = hw->phy.ops.set_page(hw, 60804dab5c37SJack F Vogel HV_STATS_PAGE << IGP_PAGE_SHIFT); 60814dab5c37SJack F Vogel if (ret_val) 60824dab5c37SJack F Vogel goto release; 60834dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data); 60844dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data); 60854dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data); 60864dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data); 60874dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data); 60884dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data); 60894dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data); 60904dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data); 60914dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data); 60924dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data); 60934dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data); 60944dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data); 60954dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data); 60964dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data); 60974dab5c37SJack F Vogel release: 60984dab5c37SJack F Vogel hw->phy.ops.release(hw); 60999d81738fSJack F Vogel } 61008cfa0ad2SJack F Vogel } 61018cfa0ad2SJack F Vogel 6102