1ab5d0362SJack F Vogel /****************************************************************************** 27282444bSPedro F. Giffuni SPDX-License-Identifier: BSD-3-Clause 3ab5d0362SJack F Vogel 47c669ab6SSean Bruno Copyright (c) 2001-2015, Intel Corporation 5ab5d0362SJack F Vogel All rights reserved. 6ab5d0362SJack F Vogel 7ab5d0362SJack F Vogel Redistribution and use in source and binary forms, with or without 8ab5d0362SJack F Vogel modification, are permitted provided that the following conditions are met: 9ab5d0362SJack F Vogel 10ab5d0362SJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 11ab5d0362SJack F Vogel this list of conditions and the following disclaimer. 12ab5d0362SJack F Vogel 13ab5d0362SJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 14ab5d0362SJack F Vogel notice, this list of conditions and the following disclaimer in the 15ab5d0362SJack F Vogel documentation and/or other materials provided with the distribution. 16ab5d0362SJack F Vogel 17ab5d0362SJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 18ab5d0362SJack F Vogel contributors may be used to endorse or promote products derived from 19ab5d0362SJack F Vogel this software without specific prior written permission. 20ab5d0362SJack F Vogel 21ab5d0362SJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22ab5d0362SJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23ab5d0362SJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24ab5d0362SJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25ab5d0362SJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26ab5d0362SJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27ab5d0362SJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28ab5d0362SJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29ab5d0362SJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30ab5d0362SJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31ab5d0362SJack F Vogel POSSIBILITY OF SUCH DAMAGE. 32ab5d0362SJack F Vogel 33ab5d0362SJack F Vogel ******************************************************************************/ 34ab5d0362SJack F Vogel /*$FreeBSD$*/ 35ab5d0362SJack F Vogel 36ab5d0362SJack F Vogel #include "e1000_api.h" 37ab5d0362SJack F Vogel 38ab5d0362SJack F Vogel 39ab5d0362SJack F Vogel static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw); 40ab5d0362SJack F Vogel static void e1000_release_nvm_i210(struct e1000_hw *hw); 41ab5d0362SJack F Vogel static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, 42ab5d0362SJack F Vogel u16 *data); 43ab5d0362SJack F Vogel static s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw); 44ab5d0362SJack F Vogel static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data); 45ab5d0362SJack F Vogel 46ab5d0362SJack F Vogel /** 47ab5d0362SJack F Vogel * e1000_acquire_nvm_i210 - Request for access to EEPROM 48ab5d0362SJack F Vogel * @hw: pointer to the HW structure 49ab5d0362SJack F Vogel * 50ab5d0362SJack F Vogel * Acquire the necessary semaphores for exclusive access to the EEPROM. 51ab5d0362SJack F Vogel * Set the EEPROM access request bit and wait for EEPROM access grant bit. 52ab5d0362SJack F Vogel * Return successful if access grant bit set, else clear the request for 53ab5d0362SJack F Vogel * EEPROM access and return -E1000_ERR_NVM (-1). 54ab5d0362SJack F Vogel **/ 55ab5d0362SJack F Vogel static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw) 56ab5d0362SJack F Vogel { 57ab5d0362SJack F Vogel s32 ret_val; 58ab5d0362SJack F Vogel 59ab5d0362SJack F Vogel DEBUGFUNC("e1000_acquire_nvm_i210"); 60ab5d0362SJack F Vogel 61d5210708SMatt Macy ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM); 62ab5d0362SJack F Vogel 63ab5d0362SJack F Vogel return ret_val; 64ab5d0362SJack F Vogel } 65ab5d0362SJack F Vogel 66ab5d0362SJack F Vogel /** 67ab5d0362SJack F Vogel * e1000_release_nvm_i210 - Release exclusive access to EEPROM 68ab5d0362SJack F Vogel * @hw: pointer to the HW structure 69ab5d0362SJack F Vogel * 70ab5d0362SJack F Vogel * Stop any current commands to the EEPROM and clear the EEPROM request bit, 71ab5d0362SJack F Vogel * then release the semaphores acquired. 72ab5d0362SJack F Vogel **/ 73ab5d0362SJack F Vogel static void e1000_release_nvm_i210(struct e1000_hw *hw) 74ab5d0362SJack F Vogel { 75ab5d0362SJack F Vogel DEBUGFUNC("e1000_release_nvm_i210"); 76ab5d0362SJack F Vogel 77d5210708SMatt Macy e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM); 78ab5d0362SJack F Vogel } 79ab5d0362SJack F Vogel 80ab5d0362SJack F Vogel /** 81ab5d0362SJack F Vogel * e1000_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register 82ab5d0362SJack F Vogel * @hw: pointer to the HW structure 83ab5d0362SJack F Vogel * @offset: offset of word in the Shadow Ram to read 84ab5d0362SJack F Vogel * @words: number of words to read 85ab5d0362SJack F Vogel * @data: word read from the Shadow Ram 86ab5d0362SJack F Vogel * 87ab5d0362SJack F Vogel * Reads a 16 bit word from the Shadow Ram using the EERD register. 88ab5d0362SJack F Vogel * Uses necessary synchronization semaphores. 89ab5d0362SJack F Vogel **/ 90ab5d0362SJack F Vogel s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, 91ab5d0362SJack F Vogel u16 *data) 92ab5d0362SJack F Vogel { 93ab5d0362SJack F Vogel s32 status = E1000_SUCCESS; 94ab5d0362SJack F Vogel u16 i, count; 95ab5d0362SJack F Vogel 96ab5d0362SJack F Vogel DEBUGFUNC("e1000_read_nvm_srrd_i210"); 97ab5d0362SJack F Vogel 98ab5d0362SJack F Vogel /* We cannot hold synchronization semaphores for too long, 99ab5d0362SJack F Vogel * because of forceful takeover procedure. However it is more efficient 100ab5d0362SJack F Vogel * to read in bursts than synchronizing access for each word. */ 101ab5d0362SJack F Vogel for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { 102ab5d0362SJack F Vogel count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? 103ab5d0362SJack F Vogel E1000_EERD_EEWR_MAX_COUNT : (words - i); 104ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { 105ab5d0362SJack F Vogel status = e1000_read_nvm_eerd(hw, offset, count, 106ab5d0362SJack F Vogel data + i); 107ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 108ab5d0362SJack F Vogel } else { 109ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC; 110ab5d0362SJack F Vogel } 111ab5d0362SJack F Vogel 112ab5d0362SJack F Vogel if (status != E1000_SUCCESS) 113ab5d0362SJack F Vogel break; 114ab5d0362SJack F Vogel } 115ab5d0362SJack F Vogel 116ab5d0362SJack F Vogel return status; 117ab5d0362SJack F Vogel } 118ab5d0362SJack F Vogel 119ab5d0362SJack F Vogel /** 120ab5d0362SJack F Vogel * e1000_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR 121ab5d0362SJack F Vogel * @hw: pointer to the HW structure 122ab5d0362SJack F Vogel * @offset: offset within the Shadow RAM to be written to 123ab5d0362SJack F Vogel * @words: number of words to write 124ab5d0362SJack F Vogel * @data: 16 bit word(s) to be written to the Shadow RAM 125ab5d0362SJack F Vogel * 126ab5d0362SJack F Vogel * Writes data to Shadow RAM at offset using EEWR register. 127ab5d0362SJack F Vogel * 128ab5d0362SJack F Vogel * If e1000_update_nvm_checksum is not called after this function , the 129ab5d0362SJack F Vogel * data will not be committed to FLASH and also Shadow RAM will most likely 130ab5d0362SJack F Vogel * contain an invalid checksum. 131ab5d0362SJack F Vogel * 132ab5d0362SJack F Vogel * If error code is returned, data and Shadow RAM may be inconsistent - buffer 133ab5d0362SJack F Vogel * partially written. 134ab5d0362SJack F Vogel **/ 135ab5d0362SJack F Vogel s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, 136ab5d0362SJack F Vogel u16 *data) 137ab5d0362SJack F Vogel { 138ab5d0362SJack F Vogel s32 status = E1000_SUCCESS; 139ab5d0362SJack F Vogel u16 i, count; 140ab5d0362SJack F Vogel 141ab5d0362SJack F Vogel DEBUGFUNC("e1000_write_nvm_srwr_i210"); 142ab5d0362SJack F Vogel 143ab5d0362SJack F Vogel /* We cannot hold synchronization semaphores for too long, 144ab5d0362SJack F Vogel * because of forceful takeover procedure. However it is more efficient 145ab5d0362SJack F Vogel * to write in bursts than synchronizing access for each word. */ 146ab5d0362SJack F Vogel for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { 147ab5d0362SJack F Vogel count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? 148ab5d0362SJack F Vogel E1000_EERD_EEWR_MAX_COUNT : (words - i); 149ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { 150ab5d0362SJack F Vogel status = e1000_write_nvm_srwr(hw, offset, count, 151ab5d0362SJack F Vogel data + i); 152ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 153ab5d0362SJack F Vogel } else { 154ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC; 155ab5d0362SJack F Vogel } 156ab5d0362SJack F Vogel 157ab5d0362SJack F Vogel if (status != E1000_SUCCESS) 158ab5d0362SJack F Vogel break; 159ab5d0362SJack F Vogel } 160ab5d0362SJack F Vogel 161ab5d0362SJack F Vogel return status; 162ab5d0362SJack F Vogel } 163ab5d0362SJack F Vogel 164ab5d0362SJack F Vogel /** 165ab5d0362SJack F Vogel * e1000_write_nvm_srwr - Write to Shadow Ram using EEWR 166ab5d0362SJack F Vogel * @hw: pointer to the HW structure 167ab5d0362SJack F Vogel * @offset: offset within the Shadow Ram to be written to 168ab5d0362SJack F Vogel * @words: number of words to write 169ab5d0362SJack F Vogel * @data: 16 bit word(s) to be written to the Shadow Ram 170ab5d0362SJack F Vogel * 171ab5d0362SJack F Vogel * Writes data to Shadow Ram at offset using EEWR register. 172ab5d0362SJack F Vogel * 173ab5d0362SJack F Vogel * If e1000_update_nvm_checksum is not called after this function , the 174ab5d0362SJack F Vogel * Shadow Ram will most likely contain an invalid checksum. 175ab5d0362SJack F Vogel **/ 176ab5d0362SJack F Vogel static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, 177ab5d0362SJack F Vogel u16 *data) 178ab5d0362SJack F Vogel { 179ab5d0362SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 180ab5d0362SJack F Vogel u32 i, k, eewr = 0; 181ab5d0362SJack F Vogel u32 attempts = 100000; 182ab5d0362SJack F Vogel s32 ret_val = E1000_SUCCESS; 183ab5d0362SJack F Vogel 184ab5d0362SJack F Vogel DEBUGFUNC("e1000_write_nvm_srwr"); 185ab5d0362SJack F Vogel 186ab5d0362SJack F Vogel /* 187ab5d0362SJack F Vogel * A check for invalid values: offset too large, too many words, 188ab5d0362SJack F Vogel * too many words for the offset, and not enough words. 189ab5d0362SJack F Vogel */ 190ab5d0362SJack F Vogel if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || 191ab5d0362SJack F Vogel (words == 0)) { 192ab5d0362SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 193ab5d0362SJack F Vogel ret_val = -E1000_ERR_NVM; 194ab5d0362SJack F Vogel goto out; 195ab5d0362SJack F Vogel } 196ab5d0362SJack F Vogel 197ab5d0362SJack F Vogel for (i = 0; i < words; i++) { 198ab5d0362SJack F Vogel eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | 199ab5d0362SJack F Vogel (data[i] << E1000_NVM_RW_REG_DATA) | 200ab5d0362SJack F Vogel E1000_NVM_RW_REG_START; 201ab5d0362SJack F Vogel 202ab5d0362SJack F Vogel E1000_WRITE_REG(hw, E1000_SRWR, eewr); 203ab5d0362SJack F Vogel 204ab5d0362SJack F Vogel for (k = 0; k < attempts; k++) { 205ab5d0362SJack F Vogel if (E1000_NVM_RW_REG_DONE & 206ab5d0362SJack F Vogel E1000_READ_REG(hw, E1000_SRWR)) { 207ab5d0362SJack F Vogel ret_val = E1000_SUCCESS; 208ab5d0362SJack F Vogel break; 209ab5d0362SJack F Vogel } 210ab5d0362SJack F Vogel usec_delay(5); 211ab5d0362SJack F Vogel } 212ab5d0362SJack F Vogel 213ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) { 214ab5d0362SJack F Vogel DEBUGOUT("Shadow RAM write EEWR timed out\n"); 215ab5d0362SJack F Vogel break; 216ab5d0362SJack F Vogel } 217ab5d0362SJack F Vogel } 218ab5d0362SJack F Vogel 219ab5d0362SJack F Vogel out: 220ab5d0362SJack F Vogel return ret_val; 221ab5d0362SJack F Vogel } 222ab5d0362SJack F Vogel 2237609433eSJack F Vogel /** e1000_read_invm_word_i210 - Reads OTP 224ab5d0362SJack F Vogel * @hw: pointer to the HW structure 225ab5d0362SJack F Vogel * @address: the word address (aka eeprom offset) to read 226ab5d0362SJack F Vogel * @data: pointer to the data read 227ab5d0362SJack F Vogel * 228ab5d0362SJack F Vogel * Reads 16-bit words from the OTP. Return error when the word is not 229ab5d0362SJack F Vogel * stored in OTP. 230ab5d0362SJack F Vogel **/ 2317609433eSJack F Vogel static s32 e1000_read_invm_word_i210(struct e1000_hw *hw, u8 address, u16 *data) 232ab5d0362SJack F Vogel { 233ab5d0362SJack F Vogel s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; 234ab5d0362SJack F Vogel u32 invm_dword; 235ab5d0362SJack F Vogel u16 i; 236ab5d0362SJack F Vogel u8 record_type, word_address; 237ab5d0362SJack F Vogel 2387609433eSJack F Vogel DEBUGFUNC("e1000_read_invm_word_i210"); 239ab5d0362SJack F Vogel 240ab5d0362SJack F Vogel for (i = 0; i < E1000_INVM_SIZE; i++) { 241ab5d0362SJack F Vogel invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i)); 242ab5d0362SJack F Vogel /* Get record type */ 243ab5d0362SJack F Vogel record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); 244ab5d0362SJack F Vogel if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE) 245ab5d0362SJack F Vogel break; 246ab5d0362SJack F Vogel if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE) 247ab5d0362SJack F Vogel i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS; 248ab5d0362SJack F Vogel if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE) 249ab5d0362SJack F Vogel i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS; 250ab5d0362SJack F Vogel if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) { 251ab5d0362SJack F Vogel word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword); 252ab5d0362SJack F Vogel if (word_address == address) { 253ab5d0362SJack F Vogel *data = INVM_DWORD_TO_WORD_DATA(invm_dword); 254ab5d0362SJack F Vogel DEBUGOUT2("Read INVM Word 0x%02x = %x", 255ab5d0362SJack F Vogel address, *data); 256ab5d0362SJack F Vogel status = E1000_SUCCESS; 257ab5d0362SJack F Vogel break; 258ab5d0362SJack F Vogel } 259ab5d0362SJack F Vogel } 260ab5d0362SJack F Vogel } 261ab5d0362SJack F Vogel if (status != E1000_SUCCESS) 262ab5d0362SJack F Vogel DEBUGOUT1("Requested word 0x%02x not found in OTP\n", address); 263ab5d0362SJack F Vogel return status; 264ab5d0362SJack F Vogel } 265ab5d0362SJack F Vogel 2667609433eSJack F Vogel /** e1000_read_invm_i210 - Read invm wrapper function for I210/I211 2677609433eSJack F Vogel * @hw: pointer to the HW structure 2687609433eSJack F Vogel * @address: the word address (aka eeprom offset) to read 2697609433eSJack F Vogel * @data: pointer to the data read 2707609433eSJack F Vogel * 2717609433eSJack F Vogel * Wrapper function to return data formerly found in the NVM. 2727609433eSJack F Vogel **/ 2737609433eSJack F Vogel static s32 e1000_read_invm_i210(struct e1000_hw *hw, u16 offset, 2747609433eSJack F Vogel u16 E1000_UNUSEDARG words, u16 *data) 2757609433eSJack F Vogel { 2767609433eSJack F Vogel s32 ret_val = E1000_SUCCESS; 2777609433eSJack F Vogel 2787609433eSJack F Vogel DEBUGFUNC("e1000_read_invm_i210"); 2797609433eSJack F Vogel 2807609433eSJack F Vogel /* Only the MAC addr is required to be present in the iNVM */ 2817609433eSJack F Vogel switch (offset) { 2827609433eSJack F Vogel case NVM_MAC_ADDR: 2837609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, &data[0]); 2847609433eSJack F Vogel ret_val |= e1000_read_invm_word_i210(hw, (u8)offset+1, 2857609433eSJack F Vogel &data[1]); 2867609433eSJack F Vogel ret_val |= e1000_read_invm_word_i210(hw, (u8)offset+2, 2877609433eSJack F Vogel &data[2]); 2887609433eSJack F Vogel if (ret_val != E1000_SUCCESS) 2897609433eSJack F Vogel DEBUGOUT("MAC Addr not found in iNVM\n"); 2907609433eSJack F Vogel break; 2917609433eSJack F Vogel case NVM_INIT_CTRL_2: 2927609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 2937609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 2947609433eSJack F Vogel *data = NVM_INIT_CTRL_2_DEFAULT_I211; 2957609433eSJack F Vogel ret_val = E1000_SUCCESS; 2967609433eSJack F Vogel } 2977609433eSJack F Vogel break; 2987609433eSJack F Vogel case NVM_INIT_CTRL_4: 2997609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3007609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3017609433eSJack F Vogel *data = NVM_INIT_CTRL_4_DEFAULT_I211; 3027609433eSJack F Vogel ret_val = E1000_SUCCESS; 3037609433eSJack F Vogel } 3047609433eSJack F Vogel break; 3057609433eSJack F Vogel case NVM_LED_1_CFG: 3067609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3077609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3087609433eSJack F Vogel *data = NVM_LED_1_CFG_DEFAULT_I211; 3097609433eSJack F Vogel ret_val = E1000_SUCCESS; 3107609433eSJack F Vogel } 3117609433eSJack F Vogel break; 3127609433eSJack F Vogel case NVM_LED_0_2_CFG: 3137609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3147609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3157609433eSJack F Vogel *data = NVM_LED_0_2_CFG_DEFAULT_I211; 3167609433eSJack F Vogel ret_val = E1000_SUCCESS; 3177609433eSJack F Vogel } 3187609433eSJack F Vogel break; 3197609433eSJack F Vogel case NVM_ID_LED_SETTINGS: 3207609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3217609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3227609433eSJack F Vogel *data = ID_LED_RESERVED_FFFF; 3237609433eSJack F Vogel ret_val = E1000_SUCCESS; 3247609433eSJack F Vogel } 3257609433eSJack F Vogel break; 3267609433eSJack F Vogel case NVM_SUB_DEV_ID: 3277609433eSJack F Vogel *data = hw->subsystem_device_id; 3287609433eSJack F Vogel break; 3297609433eSJack F Vogel case NVM_SUB_VEN_ID: 3307609433eSJack F Vogel *data = hw->subsystem_vendor_id; 3317609433eSJack F Vogel break; 3327609433eSJack F Vogel case NVM_DEV_ID: 3337609433eSJack F Vogel *data = hw->device_id; 3347609433eSJack F Vogel break; 3357609433eSJack F Vogel case NVM_VEN_ID: 3367609433eSJack F Vogel *data = hw->vendor_id; 3377609433eSJack F Vogel break; 3387609433eSJack F Vogel default: 3397609433eSJack F Vogel DEBUGOUT1("NVM word 0x%02x is not mapped.\n", offset); 3407609433eSJack F Vogel *data = NVM_RESERVED_WORD; 3417609433eSJack F Vogel break; 3427609433eSJack F Vogel } 3437609433eSJack F Vogel return ret_val; 3447609433eSJack F Vogel } 3457609433eSJack F Vogel 346ab5d0362SJack F Vogel /** 347ab5d0362SJack F Vogel * e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum 348ab5d0362SJack F Vogel * @hw: pointer to the HW structure 349ab5d0362SJack F Vogel * 350ab5d0362SJack F Vogel * Calculates the EEPROM checksum by reading/adding each word of the EEPROM 351ab5d0362SJack F Vogel * and then verifies that the sum of the EEPROM is equal to 0xBABA. 352ab5d0362SJack F Vogel **/ 353ab5d0362SJack F Vogel s32 e1000_validate_nvm_checksum_i210(struct e1000_hw *hw) 354ab5d0362SJack F Vogel { 355ab5d0362SJack F Vogel s32 status = E1000_SUCCESS; 356ab5d0362SJack F Vogel s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); 357ab5d0362SJack F Vogel 358ab5d0362SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_i210"); 359ab5d0362SJack F Vogel 360ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { 361ab5d0362SJack F Vogel 362ab5d0362SJack F Vogel /* 363ab5d0362SJack F Vogel * Replace the read function with semaphore grabbing with 364ab5d0362SJack F Vogel * the one that skips this for a while. 365ab5d0362SJack F Vogel * We have semaphore taken already here. 366ab5d0362SJack F Vogel */ 367ab5d0362SJack F Vogel read_op_ptr = hw->nvm.ops.read; 368ab5d0362SJack F Vogel hw->nvm.ops.read = e1000_read_nvm_eerd; 369ab5d0362SJack F Vogel 370ab5d0362SJack F Vogel status = e1000_validate_nvm_checksum_generic(hw); 371ab5d0362SJack F Vogel 372ab5d0362SJack F Vogel /* Revert original read operation. */ 373ab5d0362SJack F Vogel hw->nvm.ops.read = read_op_ptr; 374ab5d0362SJack F Vogel 375ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 376ab5d0362SJack F Vogel } else { 377ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC; 378ab5d0362SJack F Vogel } 379ab5d0362SJack F Vogel 380ab5d0362SJack F Vogel return status; 381ab5d0362SJack F Vogel } 382ab5d0362SJack F Vogel 383ab5d0362SJack F Vogel 384ab5d0362SJack F Vogel /** 385ab5d0362SJack F Vogel * e1000_update_nvm_checksum_i210 - Update EEPROM checksum 386ab5d0362SJack F Vogel * @hw: pointer to the HW structure 387ab5d0362SJack F Vogel * 388ab5d0362SJack F Vogel * Updates the EEPROM checksum by reading/adding each word of the EEPROM 389ab5d0362SJack F Vogel * up to the checksum. Then calculates the EEPROM checksum and writes the 390ab5d0362SJack F Vogel * value to the EEPROM. Next commit EEPROM data onto the Flash. 391ab5d0362SJack F Vogel **/ 392ab5d0362SJack F Vogel s32 e1000_update_nvm_checksum_i210(struct e1000_hw *hw) 393ab5d0362SJack F Vogel { 3948cc64f1eSJack F Vogel s32 ret_val; 395ab5d0362SJack F Vogel u16 checksum = 0; 396ab5d0362SJack F Vogel u16 i, nvm_data; 397ab5d0362SJack F Vogel 398ab5d0362SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_i210"); 399ab5d0362SJack F Vogel 400ab5d0362SJack F Vogel /* 401ab5d0362SJack F Vogel * Read the first word from the EEPROM. If this times out or fails, do 402ab5d0362SJack F Vogel * not continue or we could be in for a very long wait while every 403ab5d0362SJack F Vogel * EEPROM read fails 404ab5d0362SJack F Vogel */ 405ab5d0362SJack F Vogel ret_val = e1000_read_nvm_eerd(hw, 0, 1, &nvm_data); 406ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) { 407ab5d0362SJack F Vogel DEBUGOUT("EEPROM read failed\n"); 408ab5d0362SJack F Vogel goto out; 409ab5d0362SJack F Vogel } 410ab5d0362SJack F Vogel 411ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { 412ab5d0362SJack F Vogel /* 413ab5d0362SJack F Vogel * Do not use hw->nvm.ops.write, hw->nvm.ops.read 414ab5d0362SJack F Vogel * because we do not want to take the synchronization 415ab5d0362SJack F Vogel * semaphores twice here. 416ab5d0362SJack F Vogel */ 417ab5d0362SJack F Vogel 418ab5d0362SJack F Vogel for (i = 0; i < NVM_CHECKSUM_REG; i++) { 419ab5d0362SJack F Vogel ret_val = e1000_read_nvm_eerd(hw, i, 1, &nvm_data); 420ab5d0362SJack F Vogel if (ret_val) { 421ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 422ab5d0362SJack F Vogel DEBUGOUT("NVM Read Error while updating checksum.\n"); 423ab5d0362SJack F Vogel goto out; 424ab5d0362SJack F Vogel } 425ab5d0362SJack F Vogel checksum += nvm_data; 426ab5d0362SJack F Vogel } 427ab5d0362SJack F Vogel checksum = (u16) NVM_SUM - checksum; 428ab5d0362SJack F Vogel ret_val = e1000_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, 429ab5d0362SJack F Vogel &checksum); 430ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) { 431ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 432ab5d0362SJack F Vogel DEBUGOUT("NVM Write Error while updating checksum.\n"); 433ab5d0362SJack F Vogel goto out; 434ab5d0362SJack F Vogel } 435ab5d0362SJack F Vogel 436ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 437ab5d0362SJack F Vogel 438ab5d0362SJack F Vogel ret_val = e1000_update_flash_i210(hw); 439ab5d0362SJack F Vogel } else { 440ab5d0362SJack F Vogel ret_val = E1000_ERR_SWFW_SYNC; 441ab5d0362SJack F Vogel } 442ab5d0362SJack F Vogel out: 443ab5d0362SJack F Vogel return ret_val; 444ab5d0362SJack F Vogel } 445ab5d0362SJack F Vogel 446ab5d0362SJack F Vogel /** 4477609433eSJack F Vogel * e1000_get_flash_presence_i210 - Check if flash device is detected. 4487609433eSJack F Vogel * @hw: pointer to the HW structure 4497609433eSJack F Vogel * 4507609433eSJack F Vogel **/ 4517609433eSJack F Vogel bool e1000_get_flash_presence_i210(struct e1000_hw *hw) 4527609433eSJack F Vogel { 4537609433eSJack F Vogel u32 eec = 0; 4547609433eSJack F Vogel bool ret_val = FALSE; 4557609433eSJack F Vogel 4567609433eSJack F Vogel DEBUGFUNC("e1000_get_flash_presence_i210"); 4577609433eSJack F Vogel 4587609433eSJack F Vogel eec = E1000_READ_REG(hw, E1000_EECD); 4597609433eSJack F Vogel 4607609433eSJack F Vogel if (eec & E1000_EECD_FLASH_DETECTED_I210) 4617609433eSJack F Vogel ret_val = TRUE; 4627609433eSJack F Vogel 4637609433eSJack F Vogel return ret_val; 4647609433eSJack F Vogel } 4657609433eSJack F Vogel 4667609433eSJack F Vogel /** 467ab5d0362SJack F Vogel * e1000_update_flash_i210 - Commit EEPROM to the flash 468ab5d0362SJack F Vogel * @hw: pointer to the HW structure 469ab5d0362SJack F Vogel * 470ab5d0362SJack F Vogel **/ 471ab5d0362SJack F Vogel s32 e1000_update_flash_i210(struct e1000_hw *hw) 472ab5d0362SJack F Vogel { 4738cc64f1eSJack F Vogel s32 ret_val; 474ab5d0362SJack F Vogel u32 flup; 475ab5d0362SJack F Vogel 476ab5d0362SJack F Vogel DEBUGFUNC("e1000_update_flash_i210"); 477ab5d0362SJack F Vogel 478ab5d0362SJack F Vogel ret_val = e1000_pool_flash_update_done_i210(hw); 479ab5d0362SJack F Vogel if (ret_val == -E1000_ERR_NVM) { 480ab5d0362SJack F Vogel DEBUGOUT("Flash update time out\n"); 481ab5d0362SJack F Vogel goto out; 482ab5d0362SJack F Vogel } 483ab5d0362SJack F Vogel 484ab5d0362SJack F Vogel flup = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD_I210; 485ab5d0362SJack F Vogel E1000_WRITE_REG(hw, E1000_EECD, flup); 486ab5d0362SJack F Vogel 487ab5d0362SJack F Vogel ret_val = e1000_pool_flash_update_done_i210(hw); 488ab5d0362SJack F Vogel if (ret_val == E1000_SUCCESS) 489ab5d0362SJack F Vogel DEBUGOUT("Flash update complete\n"); 490ab5d0362SJack F Vogel else 491ab5d0362SJack F Vogel DEBUGOUT("Flash update time out\n"); 492ab5d0362SJack F Vogel 493ab5d0362SJack F Vogel out: 494ab5d0362SJack F Vogel return ret_val; 495ab5d0362SJack F Vogel } 496ab5d0362SJack F Vogel 497ab5d0362SJack F Vogel /** 498ab5d0362SJack F Vogel * e1000_pool_flash_update_done_i210 - Pool FLUDONE status. 499ab5d0362SJack F Vogel * @hw: pointer to the HW structure 500ab5d0362SJack F Vogel * 501ab5d0362SJack F Vogel **/ 502ab5d0362SJack F Vogel s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw) 503ab5d0362SJack F Vogel { 504ab5d0362SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 505ab5d0362SJack F Vogel u32 i, reg; 506ab5d0362SJack F Vogel 507ab5d0362SJack F Vogel DEBUGFUNC("e1000_pool_flash_update_done_i210"); 508ab5d0362SJack F Vogel 509ab5d0362SJack F Vogel for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { 510ab5d0362SJack F Vogel reg = E1000_READ_REG(hw, E1000_EECD); 511ab5d0362SJack F Vogel if (reg & E1000_EECD_FLUDONE_I210) { 512ab5d0362SJack F Vogel ret_val = E1000_SUCCESS; 513ab5d0362SJack F Vogel break; 514ab5d0362SJack F Vogel } 515ab5d0362SJack F Vogel usec_delay(5); 516ab5d0362SJack F Vogel } 517ab5d0362SJack F Vogel 518ab5d0362SJack F Vogel return ret_val; 519ab5d0362SJack F Vogel } 520ab5d0362SJack F Vogel 521ab5d0362SJack F Vogel /** 522ab5d0362SJack F Vogel * e1000_init_nvm_params_i210 - Initialize i210 NVM function pointers 523ab5d0362SJack F Vogel * @hw: pointer to the HW structure 524ab5d0362SJack F Vogel * 5257609433eSJack F Vogel * Initialize the i210/i211 NVM parameters and function pointers. 526ab5d0362SJack F Vogel **/ 527ab5d0362SJack F Vogel static s32 e1000_init_nvm_params_i210(struct e1000_hw *hw) 528ab5d0362SJack F Vogel { 5298cc64f1eSJack F Vogel s32 ret_val; 530ab5d0362SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 531ab5d0362SJack F Vogel 532ab5d0362SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_i210"); 533ab5d0362SJack F Vogel 534ab5d0362SJack F Vogel ret_val = e1000_init_nvm_params_82575(hw); 535ab5d0362SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_i210; 536ab5d0362SJack F Vogel nvm->ops.release = e1000_release_nvm_i210; 5377609433eSJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_i210; 5387609433eSJack F Vogel if (e1000_get_flash_presence_i210(hw)) { 5397609433eSJack F Vogel hw->nvm.type = e1000_nvm_flash_hw; 540ab5d0362SJack F Vogel nvm->ops.read = e1000_read_nvm_srrd_i210; 541ab5d0362SJack F Vogel nvm->ops.write = e1000_write_nvm_srwr_i210; 542ab5d0362SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_i210; 543ab5d0362SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_i210; 5447609433eSJack F Vogel } else { 5457609433eSJack F Vogel hw->nvm.type = e1000_nvm_invm; 5467609433eSJack F Vogel nvm->ops.read = e1000_read_invm_i210; 547ab5d0362SJack F Vogel nvm->ops.write = e1000_null_write_nvm; 548ab5d0362SJack F Vogel nvm->ops.validate = e1000_null_ops_generic; 549ab5d0362SJack F Vogel nvm->ops.update = e1000_null_ops_generic; 5507609433eSJack F Vogel } 5517609433eSJack F Vogel return ret_val; 552ab5d0362SJack F Vogel } 553ab5d0362SJack F Vogel 554ab5d0362SJack F Vogel /** 555ab5d0362SJack F Vogel * e1000_init_function_pointers_i210 - Init func ptrs. 556ab5d0362SJack F Vogel * @hw: pointer to the HW structure 557ab5d0362SJack F Vogel * 558ab5d0362SJack F Vogel * Called to initialize all function pointers and parameters. 559ab5d0362SJack F Vogel **/ 560ab5d0362SJack F Vogel void e1000_init_function_pointers_i210(struct e1000_hw *hw) 561ab5d0362SJack F Vogel { 562ab5d0362SJack F Vogel e1000_init_function_pointers_82575(hw); 563ab5d0362SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_i210; 5647609433eSJack F Vogel 565ab5d0362SJack F Vogel return; 566ab5d0362SJack F Vogel } 567ab5d0362SJack F Vogel 568ab5d0362SJack F Vogel /** 569ab5d0362SJack F Vogel * e1000_valid_led_default_i210 - Verify a valid default LED config 570ab5d0362SJack F Vogel * @hw: pointer to the HW structure 571ab5d0362SJack F Vogel * @data: pointer to the NVM (EEPROM) 572ab5d0362SJack F Vogel * 573ab5d0362SJack F Vogel * Read the EEPROM for the current default LED configuration. If the 574ab5d0362SJack F Vogel * LED configuration is not valid, set to a valid LED configuration. 575ab5d0362SJack F Vogel **/ 576ab5d0362SJack F Vogel static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data) 577ab5d0362SJack F Vogel { 578ab5d0362SJack F Vogel s32 ret_val; 579ab5d0362SJack F Vogel 580ab5d0362SJack F Vogel DEBUGFUNC("e1000_valid_led_default_i210"); 581ab5d0362SJack F Vogel 582ab5d0362SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 583ab5d0362SJack F Vogel if (ret_val) { 584ab5d0362SJack F Vogel DEBUGOUT("NVM Read Error\n"); 585ab5d0362SJack F Vogel goto out; 586ab5d0362SJack F Vogel } 587ab5d0362SJack F Vogel 588ab5d0362SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { 589ab5d0362SJack F Vogel switch (hw->phy.media_type) { 590ab5d0362SJack F Vogel case e1000_media_type_internal_serdes: 591ab5d0362SJack F Vogel *data = ID_LED_DEFAULT_I210_SERDES; 592ab5d0362SJack F Vogel break; 593ab5d0362SJack F Vogel case e1000_media_type_copper: 594ab5d0362SJack F Vogel default: 595ab5d0362SJack F Vogel *data = ID_LED_DEFAULT_I210; 596ab5d0362SJack F Vogel break; 597ab5d0362SJack F Vogel } 598ab5d0362SJack F Vogel } 599ab5d0362SJack F Vogel out: 600ab5d0362SJack F Vogel return ret_val; 601ab5d0362SJack F Vogel } 6027609433eSJack F Vogel 6037609433eSJack F Vogel /** 6047609433eSJack F Vogel * __e1000_access_xmdio_reg - Read/write XMDIO register 6057609433eSJack F Vogel * @hw: pointer to the HW structure 6067609433eSJack F Vogel * @address: XMDIO address to program 6077609433eSJack F Vogel * @dev_addr: device address to program 6087609433eSJack F Vogel * @data: pointer to value to read/write from/to the XMDIO address 6097609433eSJack F Vogel * @read: boolean flag to indicate read or write 6107609433eSJack F Vogel **/ 6117609433eSJack F Vogel static s32 __e1000_access_xmdio_reg(struct e1000_hw *hw, u16 address, 6127609433eSJack F Vogel u8 dev_addr, u16 *data, bool read) 6137609433eSJack F Vogel { 6148cc64f1eSJack F Vogel s32 ret_val; 6157609433eSJack F Vogel 6167609433eSJack F Vogel DEBUGFUNC("__e1000_access_xmdio_reg"); 6177609433eSJack F Vogel 6187609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, dev_addr); 6197609433eSJack F Vogel if (ret_val) 6207609433eSJack F Vogel return ret_val; 6217609433eSJack F Vogel 6227609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, address); 6237609433eSJack F Vogel if (ret_val) 6247609433eSJack F Vogel return ret_val; 6257609433eSJack F Vogel 6267609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, E1000_MMDAC_FUNC_DATA | 6277609433eSJack F Vogel dev_addr); 6287609433eSJack F Vogel if (ret_val) 6297609433eSJack F Vogel return ret_val; 6307609433eSJack F Vogel 6317609433eSJack F Vogel if (read) 6327609433eSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, E1000_MMDAAD, data); 6337609433eSJack F Vogel else 6347609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, *data); 6357609433eSJack F Vogel if (ret_val) 6367609433eSJack F Vogel return ret_val; 6377609433eSJack F Vogel 6387609433eSJack F Vogel /* Recalibrate the device back to 0 */ 6397609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0); 6407609433eSJack F Vogel if (ret_val) 6417609433eSJack F Vogel return ret_val; 6427609433eSJack F Vogel 6437609433eSJack F Vogel return ret_val; 6447609433eSJack F Vogel } 6457609433eSJack F Vogel 6467609433eSJack F Vogel /** 6477609433eSJack F Vogel * e1000_read_xmdio_reg - Read XMDIO register 6487609433eSJack F Vogel * @hw: pointer to the HW structure 6497609433eSJack F Vogel * @addr: XMDIO address to program 6507609433eSJack F Vogel * @dev_addr: device address to program 6517609433eSJack F Vogel * @data: value to be read from the EMI address 6527609433eSJack F Vogel **/ 6537609433eSJack F Vogel s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data) 6547609433eSJack F Vogel { 6557609433eSJack F Vogel DEBUGFUNC("e1000_read_xmdio_reg"); 6567609433eSJack F Vogel 6577609433eSJack F Vogel return __e1000_access_xmdio_reg(hw, addr, dev_addr, data, TRUE); 6587609433eSJack F Vogel } 6597609433eSJack F Vogel 6607609433eSJack F Vogel /** 6617609433eSJack F Vogel * e1000_write_xmdio_reg - Write XMDIO register 6627609433eSJack F Vogel * @hw: pointer to the HW structure 6637609433eSJack F Vogel * @addr: XMDIO address to program 6647609433eSJack F Vogel * @dev_addr: device address to program 6657609433eSJack F Vogel * @data: value to be written to the XMDIO address 6667609433eSJack F Vogel **/ 6677609433eSJack F Vogel s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data) 6687609433eSJack F Vogel { 6697609433eSJack F Vogel DEBUGFUNC("e1000_read_xmdio_reg"); 6707609433eSJack F Vogel 6717609433eSJack F Vogel return __e1000_access_xmdio_reg(hw, addr, dev_addr, &data, FALSE); 6727609433eSJack F Vogel } 6738cc64f1eSJack F Vogel 6748cc64f1eSJack F Vogel /** 6758cc64f1eSJack F Vogel * e1000_pll_workaround_i210 6768cc64f1eSJack F Vogel * @hw: pointer to the HW structure 6778cc64f1eSJack F Vogel * 6788cc64f1eSJack F Vogel * Works around an errata in the PLL circuit where it occasionally 6798cc64f1eSJack F Vogel * provides the wrong clock frequency after power up. 6808cc64f1eSJack F Vogel **/ 6818cc64f1eSJack F Vogel static s32 e1000_pll_workaround_i210(struct e1000_hw *hw) 6828cc64f1eSJack F Vogel { 6838cc64f1eSJack F Vogel s32 ret_val; 6848cc64f1eSJack F Vogel u32 wuc, mdicnfg, ctrl, ctrl_ext, reg_val; 6858cc64f1eSJack F Vogel u16 nvm_word, phy_word, pci_word, tmp_nvm; 6868cc64f1eSJack F Vogel int i; 6878cc64f1eSJack F Vogel 6888cc64f1eSJack F Vogel /* Get and set needed register values */ 6898cc64f1eSJack F Vogel wuc = E1000_READ_REG(hw, E1000_WUC); 6908cc64f1eSJack F Vogel mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG); 6918cc64f1eSJack F Vogel reg_val = mdicnfg & ~E1000_MDICNFG_EXT_MDIO; 6928cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_MDICNFG, reg_val); 6938cc64f1eSJack F Vogel 6948cc64f1eSJack F Vogel /* Get data from NVM, or set default */ 6958cc64f1eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, E1000_INVM_AUTOLOAD, 6968cc64f1eSJack F Vogel &nvm_word); 6978cc64f1eSJack F Vogel if (ret_val != E1000_SUCCESS) 6988cc64f1eSJack F Vogel nvm_word = E1000_INVM_DEFAULT_AL; 6998cc64f1eSJack F Vogel tmp_nvm = nvm_word | E1000_INVM_PLL_WO_VAL; 7008cc64f1eSJack F Vogel for (i = 0; i < E1000_MAX_PLL_TRIES; i++) { 7018cc64f1eSJack F Vogel /* check current state directly from internal PHY */ 7028cc64f1eSJack F Vogel e1000_read_phy_reg_gs40g(hw, (E1000_PHY_PLL_FREQ_PAGE | 7038cc64f1eSJack F Vogel E1000_PHY_PLL_FREQ_REG), &phy_word); 7048cc64f1eSJack F Vogel if ((phy_word & E1000_PHY_PLL_UNCONF) 7058cc64f1eSJack F Vogel != E1000_PHY_PLL_UNCONF) { 7068cc64f1eSJack F Vogel ret_val = E1000_SUCCESS; 7078cc64f1eSJack F Vogel break; 7088cc64f1eSJack F Vogel } else { 7098cc64f1eSJack F Vogel ret_val = -E1000_ERR_PHY; 7108cc64f1eSJack F Vogel } 7118cc64f1eSJack F Vogel /* directly reset the internal PHY */ 7128cc64f1eSJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 7138cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl|E1000_CTRL_PHY_RST); 7148cc64f1eSJack F Vogel 7158cc64f1eSJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 7168cc64f1eSJack F Vogel ctrl_ext |= (E1000_CTRL_EXT_PHYPDEN | E1000_CTRL_EXT_SDLPE); 7178cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 7188cc64f1eSJack F Vogel 7198cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_WUC, 0); 7208cc64f1eSJack F Vogel reg_val = (E1000_INVM_AUTOLOAD << 4) | (tmp_nvm << 16); 7218cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_EEARBC_I210, reg_val); 7228cc64f1eSJack F Vogel 7238cc64f1eSJack F Vogel e1000_read_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word); 7248cc64f1eSJack F Vogel pci_word |= E1000_PCI_PMCSR_D3; 7258cc64f1eSJack F Vogel e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word); 7268cc64f1eSJack F Vogel msec_delay(1); 7278cc64f1eSJack F Vogel pci_word &= ~E1000_PCI_PMCSR_D3; 7288cc64f1eSJack F Vogel e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word); 7298cc64f1eSJack F Vogel reg_val = (E1000_INVM_AUTOLOAD << 4) | (nvm_word << 16); 7308cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_EEARBC_I210, reg_val); 7318cc64f1eSJack F Vogel 7328cc64f1eSJack F Vogel /* restore WUC register */ 7338cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_WUC, wuc); 7348cc64f1eSJack F Vogel } 7358cc64f1eSJack F Vogel /* restore MDICNFG setting */ 7368cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg); 7378cc64f1eSJack F Vogel return ret_val; 7388cc64f1eSJack F Vogel } 7398cc64f1eSJack F Vogel 7408cc64f1eSJack F Vogel /** 741c80429ceSEric Joyner * e1000_get_cfg_done_i210 - Read config done bit 742c80429ceSEric Joyner * @hw: pointer to the HW structure 743c80429ceSEric Joyner * 744c80429ceSEric Joyner * Read the management control register for the config done bit for 745c80429ceSEric Joyner * completion status. NOTE: silicon which is EEPROM-less will fail trying 746c80429ceSEric Joyner * to read the config done bit, so an error is *ONLY* logged and returns 747c80429ceSEric Joyner * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon 748c80429ceSEric Joyner * would not be able to be reset or change link. 749c80429ceSEric Joyner **/ 750c80429ceSEric Joyner static s32 e1000_get_cfg_done_i210(struct e1000_hw *hw) 751c80429ceSEric Joyner { 752c80429ceSEric Joyner s32 timeout = PHY_CFG_TIMEOUT; 753c80429ceSEric Joyner u32 mask = E1000_NVM_CFG_DONE_PORT_0; 754c80429ceSEric Joyner 755c80429ceSEric Joyner DEBUGFUNC("e1000_get_cfg_done_i210"); 756c80429ceSEric Joyner 757c80429ceSEric Joyner while (timeout) { 758c80429ceSEric Joyner if (E1000_READ_REG(hw, E1000_EEMNGCTL_I210) & mask) 759c80429ceSEric Joyner break; 760c80429ceSEric Joyner msec_delay(1); 761c80429ceSEric Joyner timeout--; 762c80429ceSEric Joyner } 763c80429ceSEric Joyner if (!timeout) 764c80429ceSEric Joyner DEBUGOUT("MNG configuration cycle has not completed.\n"); 765c80429ceSEric Joyner 766c80429ceSEric Joyner return E1000_SUCCESS; 767c80429ceSEric Joyner } 768c80429ceSEric Joyner 769c80429ceSEric Joyner /** 7708cc64f1eSJack F Vogel * e1000_init_hw_i210 - Init hw for I210/I211 7718cc64f1eSJack F Vogel * @hw: pointer to the HW structure 7728cc64f1eSJack F Vogel * 7738cc64f1eSJack F Vogel * Called to initialize hw for i210 hw family. 7748cc64f1eSJack F Vogel **/ 7758cc64f1eSJack F Vogel s32 e1000_init_hw_i210(struct e1000_hw *hw) 7768cc64f1eSJack F Vogel { 777*51569bd7SEric Joyner struct e1000_mac_info *mac = &hw->mac; 7788cc64f1eSJack F Vogel s32 ret_val; 7798cc64f1eSJack F Vogel 7808cc64f1eSJack F Vogel DEBUGFUNC("e1000_init_hw_i210"); 7818cc64f1eSJack F Vogel if ((hw->mac.type >= e1000_i210) && 7828cc64f1eSJack F Vogel !(e1000_get_flash_presence_i210(hw))) { 7838cc64f1eSJack F Vogel ret_val = e1000_pll_workaround_i210(hw); 7848cc64f1eSJack F Vogel if (ret_val != E1000_SUCCESS) 7858cc64f1eSJack F Vogel return ret_val; 7868cc64f1eSJack F Vogel } 787c80429ceSEric Joyner hw->phy.ops.get_cfg_done = e1000_get_cfg_done_i210; 788*51569bd7SEric Joyner 789*51569bd7SEric Joyner /* Initialize identification LED */ 790*51569bd7SEric Joyner mac->ops.id_led_init(hw); 791*51569bd7SEric Joyner 7928cc64f1eSJack F Vogel ret_val = e1000_init_hw_82575(hw); 7938cc64f1eSJack F Vogel return ret_val; 7948cc64f1eSJack F Vogel } 795