1ab5d0362SJack F Vogel /****************************************************************************** 27282444bSPedro F. Giffuni SPDX-License-Identifier: BSD-3-Clause 3ab5d0362SJack F Vogel 4702cac6cSKevin Bowling Copyright (c) 2001-2020, 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++) { 198f6517a7eSChengwen Feng ret_val = -E1000_ERR_NVM; 199f6517a7eSChengwen Feng 200ab5d0362SJack F Vogel eewr = ((offset + i) << E1000_NVM_RW_ADDR_SHIFT) | 201ab5d0362SJack F Vogel (data[i] << E1000_NVM_RW_REG_DATA) | 202ab5d0362SJack F Vogel E1000_NVM_RW_REG_START; 203ab5d0362SJack F Vogel 204ab5d0362SJack F Vogel E1000_WRITE_REG(hw, E1000_SRWR, eewr); 205ab5d0362SJack F Vogel 206ab5d0362SJack F Vogel for (k = 0; k < attempts; k++) { 207ab5d0362SJack F Vogel if (E1000_NVM_RW_REG_DONE & 208ab5d0362SJack F Vogel E1000_READ_REG(hw, E1000_SRWR)) { 209ab5d0362SJack F Vogel ret_val = E1000_SUCCESS; 210ab5d0362SJack F Vogel break; 211ab5d0362SJack F Vogel } 212ab5d0362SJack F Vogel usec_delay(5); 213ab5d0362SJack F Vogel } 214ab5d0362SJack F Vogel 215ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) { 216ab5d0362SJack F Vogel DEBUGOUT("Shadow RAM write EEWR timed out\n"); 217ab5d0362SJack F Vogel break; 218ab5d0362SJack F Vogel } 219ab5d0362SJack F Vogel } 220ab5d0362SJack F Vogel 221ab5d0362SJack F Vogel out: 222ab5d0362SJack F Vogel return ret_val; 223ab5d0362SJack F Vogel } 224ab5d0362SJack F Vogel 2257609433eSJack F Vogel /** e1000_read_invm_word_i210 - Reads OTP 226ab5d0362SJack F Vogel * @hw: pointer to the HW structure 227ab5d0362SJack F Vogel * @address: the word address (aka eeprom offset) to read 228ab5d0362SJack F Vogel * @data: pointer to the data read 229ab5d0362SJack F Vogel * 230ab5d0362SJack F Vogel * Reads 16-bit words from the OTP. Return error when the word is not 231ab5d0362SJack F Vogel * stored in OTP. 232ab5d0362SJack F Vogel **/ 2337609433eSJack F Vogel static s32 e1000_read_invm_word_i210(struct e1000_hw *hw, u8 address, u16 *data) 234ab5d0362SJack F Vogel { 235ab5d0362SJack F Vogel s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; 236ab5d0362SJack F Vogel u32 invm_dword; 237ab5d0362SJack F Vogel u16 i; 238ab5d0362SJack F Vogel u8 record_type, word_address; 239ab5d0362SJack F Vogel 2407609433eSJack F Vogel DEBUGFUNC("e1000_read_invm_word_i210"); 241ab5d0362SJack F Vogel 242ab5d0362SJack F Vogel for (i = 0; i < E1000_INVM_SIZE; i++) { 243ab5d0362SJack F Vogel invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i)); 244ab5d0362SJack F Vogel /* Get record type */ 245ab5d0362SJack F Vogel record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); 246ab5d0362SJack F Vogel if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE) 247ab5d0362SJack F Vogel break; 248ab5d0362SJack F Vogel if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE) 249ab5d0362SJack F Vogel i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS; 250ab5d0362SJack F Vogel if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE) 251ab5d0362SJack F Vogel i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS; 252ab5d0362SJack F Vogel if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) { 253ab5d0362SJack F Vogel word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword); 254ab5d0362SJack F Vogel if (word_address == address) { 255ab5d0362SJack F Vogel *data = INVM_DWORD_TO_WORD_DATA(invm_dword); 256ab5d0362SJack F Vogel DEBUGOUT2("Read INVM Word 0x%02x = %x", 257ab5d0362SJack F Vogel address, *data); 258ab5d0362SJack F Vogel status = E1000_SUCCESS; 259ab5d0362SJack F Vogel break; 260ab5d0362SJack F Vogel } 261ab5d0362SJack F Vogel } 262ab5d0362SJack F Vogel } 263ab5d0362SJack F Vogel if (status != E1000_SUCCESS) 264ab5d0362SJack F Vogel DEBUGOUT1("Requested word 0x%02x not found in OTP\n", address); 265ab5d0362SJack F Vogel return status; 266ab5d0362SJack F Vogel } 267ab5d0362SJack F Vogel 2687609433eSJack F Vogel /** e1000_read_invm_i210 - Read invm wrapper function for I210/I211 2697609433eSJack F Vogel * @hw: pointer to the HW structure 2707609433eSJack F Vogel * @address: the word address (aka eeprom offset) to read 2717609433eSJack F Vogel * @data: pointer to the data read 2727609433eSJack F Vogel * 2737609433eSJack F Vogel * Wrapper function to return data formerly found in the NVM. 2747609433eSJack F Vogel **/ 2757609433eSJack F Vogel static s32 e1000_read_invm_i210(struct e1000_hw *hw, u16 offset, 2767609433eSJack F Vogel u16 E1000_UNUSEDARG words, u16 *data) 2777609433eSJack F Vogel { 2787609433eSJack F Vogel s32 ret_val = E1000_SUCCESS; 2797609433eSJack F Vogel 2807609433eSJack F Vogel DEBUGFUNC("e1000_read_invm_i210"); 2817609433eSJack F Vogel 2827609433eSJack F Vogel /* Only the MAC addr is required to be present in the iNVM */ 2837609433eSJack F Vogel switch (offset) { 2847609433eSJack F Vogel case NVM_MAC_ADDR: 2857609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, &data[0]); 2867609433eSJack F Vogel ret_val |= e1000_read_invm_word_i210(hw, (u8)offset + 1, 2877609433eSJack F Vogel &data[1]); 2887609433eSJack F Vogel ret_val |= e1000_read_invm_word_i210(hw, (u8)offset + 2, 2897609433eSJack F Vogel &data[2]); 2907609433eSJack F Vogel if (ret_val != E1000_SUCCESS) 2917609433eSJack F Vogel DEBUGOUT("MAC Addr not found in iNVM\n"); 2927609433eSJack F Vogel break; 2937609433eSJack F Vogel case NVM_INIT_CTRL_2: 2947609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 2957609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 2967609433eSJack F Vogel *data = NVM_INIT_CTRL_2_DEFAULT_I211; 2977609433eSJack F Vogel ret_val = E1000_SUCCESS; 2987609433eSJack F Vogel } 2997609433eSJack F Vogel break; 3007609433eSJack F Vogel case NVM_INIT_CTRL_4: 3017609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3027609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3037609433eSJack F Vogel *data = NVM_INIT_CTRL_4_DEFAULT_I211; 3047609433eSJack F Vogel ret_val = E1000_SUCCESS; 3057609433eSJack F Vogel } 3067609433eSJack F Vogel break; 3077609433eSJack F Vogel case NVM_LED_1_CFG: 3087609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3097609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3107609433eSJack F Vogel *data = NVM_LED_1_CFG_DEFAULT_I211; 3117609433eSJack F Vogel ret_val = E1000_SUCCESS; 3127609433eSJack F Vogel } 3137609433eSJack F Vogel break; 3147609433eSJack F Vogel case NVM_LED_0_2_CFG: 3157609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3167609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3177609433eSJack F Vogel *data = NVM_LED_0_2_CFG_DEFAULT_I211; 3187609433eSJack F Vogel ret_val = E1000_SUCCESS; 3197609433eSJack F Vogel } 3207609433eSJack F Vogel break; 3217609433eSJack F Vogel case NVM_ID_LED_SETTINGS: 3227609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data); 3237609433eSJack F Vogel if (ret_val != E1000_SUCCESS) { 3247609433eSJack F Vogel *data = ID_LED_RESERVED_FFFF; 3257609433eSJack F Vogel ret_val = E1000_SUCCESS; 3267609433eSJack F Vogel } 3277609433eSJack F Vogel break; 3287609433eSJack F Vogel case NVM_SUB_DEV_ID: 3297609433eSJack F Vogel *data = hw->subsystem_device_id; 3307609433eSJack F Vogel break; 3317609433eSJack F Vogel case NVM_SUB_VEN_ID: 3327609433eSJack F Vogel *data = hw->subsystem_vendor_id; 3337609433eSJack F Vogel break; 3347609433eSJack F Vogel case NVM_DEV_ID: 3357609433eSJack F Vogel *data = hw->device_id; 3367609433eSJack F Vogel break; 3377609433eSJack F Vogel case NVM_VEN_ID: 3387609433eSJack F Vogel *data = hw->vendor_id; 3397609433eSJack F Vogel break; 3407609433eSJack F Vogel default: 3417609433eSJack F Vogel DEBUGOUT1("NVM word 0x%02x is not mapped.\n", offset); 3427609433eSJack F Vogel *data = NVM_RESERVED_WORD; 3437609433eSJack F Vogel break; 3447609433eSJack F Vogel } 3457609433eSJack F Vogel return ret_val; 3467609433eSJack F Vogel } 3477609433eSJack F Vogel 348ab5d0362SJack F Vogel /** 349984d1616SKevin Bowling * e1000_read_invm_version - Reads iNVM version and image type 350984d1616SKevin Bowling * @hw: pointer to the HW structure 351984d1616SKevin Bowling * @invm_ver: version structure for the version read 352984d1616SKevin Bowling * 353984d1616SKevin Bowling * Reads iNVM version and image type. 354984d1616SKevin Bowling **/ 355984d1616SKevin Bowling s32 e1000_read_invm_version(struct e1000_hw *hw, 356984d1616SKevin Bowling struct e1000_fw_version *invm_ver) 357984d1616SKevin Bowling { 358984d1616SKevin Bowling u32 *record = NULL; 359984d1616SKevin Bowling u32 *next_record = NULL; 360984d1616SKevin Bowling u32 i = 0; 361984d1616SKevin Bowling u32 invm_dword = 0; 362984d1616SKevin Bowling u32 invm_blocks = E1000_INVM_SIZE - (E1000_INVM_ULT_BYTES_SIZE / 363984d1616SKevin Bowling E1000_INVM_RECORD_SIZE_IN_BYTES); 364984d1616SKevin Bowling u32 buffer[E1000_INVM_SIZE]; 365984d1616SKevin Bowling s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; 366984d1616SKevin Bowling u16 version = 0; 367984d1616SKevin Bowling 368984d1616SKevin Bowling DEBUGFUNC("e1000_read_invm_version"); 369984d1616SKevin Bowling 370984d1616SKevin Bowling /* Read iNVM memory */ 371984d1616SKevin Bowling for (i = 0; i < E1000_INVM_SIZE; i++) { 372984d1616SKevin Bowling invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i)); 373984d1616SKevin Bowling buffer[i] = invm_dword; 374984d1616SKevin Bowling } 375984d1616SKevin Bowling 376984d1616SKevin Bowling /* Read version number */ 377984d1616SKevin Bowling for (i = 1; i < invm_blocks; i++) { 378984d1616SKevin Bowling record = &buffer[invm_blocks - i]; 379984d1616SKevin Bowling next_record = &buffer[invm_blocks - i + 1]; 380984d1616SKevin Bowling 381984d1616SKevin Bowling /* Check if we have first version location used */ 382984d1616SKevin Bowling if ((i == 1) && ((*record & E1000_INVM_VER_FIELD_ONE) == 0)) { 383984d1616SKevin Bowling version = 0; 384984d1616SKevin Bowling status = E1000_SUCCESS; 385984d1616SKevin Bowling break; 386984d1616SKevin Bowling } 387984d1616SKevin Bowling /* Check if we have second version location used */ 388984d1616SKevin Bowling else if ((i == 1) && 389984d1616SKevin Bowling ((*record & E1000_INVM_VER_FIELD_TWO) == 0)) { 390984d1616SKevin Bowling version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3; 391984d1616SKevin Bowling status = E1000_SUCCESS; 392984d1616SKevin Bowling break; 393984d1616SKevin Bowling } 394984d1616SKevin Bowling /* 395984d1616SKevin Bowling * Check if we have odd version location 396984d1616SKevin Bowling * used and it is the last one used 397984d1616SKevin Bowling */ 398984d1616SKevin Bowling else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) && 399984d1616SKevin Bowling ((*record & 0x3) == 0)) || (((*record & 0x3) != 0) && 400984d1616SKevin Bowling (i != 1))) { 401984d1616SKevin Bowling version = (*next_record & E1000_INVM_VER_FIELD_TWO) 402984d1616SKevin Bowling >> 13; 403984d1616SKevin Bowling status = E1000_SUCCESS; 404984d1616SKevin Bowling break; 405984d1616SKevin Bowling } 406984d1616SKevin Bowling /* 407984d1616SKevin Bowling * Check if we have even version location 408984d1616SKevin Bowling * used and it is the last one used 409984d1616SKevin Bowling */ 410984d1616SKevin Bowling else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) && 411984d1616SKevin Bowling ((*record & 0x3) == 0)) { 412984d1616SKevin Bowling version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3; 413984d1616SKevin Bowling status = E1000_SUCCESS; 414984d1616SKevin Bowling break; 415984d1616SKevin Bowling } 416984d1616SKevin Bowling } 417984d1616SKevin Bowling 418984d1616SKevin Bowling if (status == E1000_SUCCESS) { 419984d1616SKevin Bowling invm_ver->invm_major = (version & E1000_INVM_MAJOR_MASK) 420984d1616SKevin Bowling >> E1000_INVM_MAJOR_SHIFT; 421984d1616SKevin Bowling invm_ver->invm_minor = version & E1000_INVM_MINOR_MASK; 422984d1616SKevin Bowling } 423984d1616SKevin Bowling /* Read Image Type */ 424984d1616SKevin Bowling for (i = 1; i < invm_blocks; i++) { 425984d1616SKevin Bowling record = &buffer[invm_blocks - i]; 426984d1616SKevin Bowling next_record = &buffer[invm_blocks - i + 1]; 427984d1616SKevin Bowling 428984d1616SKevin Bowling /* Check if we have image type in first location used */ 429984d1616SKevin Bowling if ((i == 1) && ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) { 430984d1616SKevin Bowling invm_ver->invm_img_type = 0; 431984d1616SKevin Bowling status = E1000_SUCCESS; 432984d1616SKevin Bowling break; 433984d1616SKevin Bowling } 434984d1616SKevin Bowling /* Check if we have image type in first location used */ 435984d1616SKevin Bowling else if ((((*record & 0x3) == 0) && 436984d1616SKevin Bowling ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) || 437984d1616SKevin Bowling ((((*record & 0x3) != 0) && (i != 1)))) { 438984d1616SKevin Bowling invm_ver->invm_img_type = 439984d1616SKevin Bowling (*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23; 440984d1616SKevin Bowling status = E1000_SUCCESS; 441984d1616SKevin Bowling break; 442984d1616SKevin Bowling } 443984d1616SKevin Bowling } 444984d1616SKevin Bowling return status; 445984d1616SKevin Bowling } 446984d1616SKevin Bowling 447984d1616SKevin Bowling /** 448ab5d0362SJack F Vogel * e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum 449ab5d0362SJack F Vogel * @hw: pointer to the HW structure 450ab5d0362SJack F Vogel * 451ab5d0362SJack F Vogel * Calculates the EEPROM checksum by reading/adding each word of the EEPROM 452ab5d0362SJack F Vogel * and then verifies that the sum of the EEPROM is equal to 0xBABA. 453ab5d0362SJack F Vogel **/ 454ab5d0362SJack F Vogel s32 e1000_validate_nvm_checksum_i210(struct e1000_hw *hw) 455ab5d0362SJack F Vogel { 456ab5d0362SJack F Vogel s32 status = E1000_SUCCESS; 457ab5d0362SJack F Vogel s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); 458ab5d0362SJack F Vogel 459ab5d0362SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_i210"); 460ab5d0362SJack F Vogel 461ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { 462ab5d0362SJack F Vogel 463ab5d0362SJack F Vogel /* 464ab5d0362SJack F Vogel * Replace the read function with semaphore grabbing with 465ab5d0362SJack F Vogel * the one that skips this for a while. 466ab5d0362SJack F Vogel * We have semaphore taken already here. 467ab5d0362SJack F Vogel */ 468ab5d0362SJack F Vogel read_op_ptr = hw->nvm.ops.read; 469ab5d0362SJack F Vogel hw->nvm.ops.read = e1000_read_nvm_eerd; 470ab5d0362SJack F Vogel 471ab5d0362SJack F Vogel status = e1000_validate_nvm_checksum_generic(hw); 472ab5d0362SJack F Vogel 473ab5d0362SJack F Vogel /* Revert original read operation. */ 474ab5d0362SJack F Vogel hw->nvm.ops.read = read_op_ptr; 475ab5d0362SJack F Vogel 476ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 477ab5d0362SJack F Vogel } else { 478ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC; 479ab5d0362SJack F Vogel } 480ab5d0362SJack F Vogel 481ab5d0362SJack F Vogel return status; 482ab5d0362SJack F Vogel } 483ab5d0362SJack F Vogel 484ab5d0362SJack F Vogel 485ab5d0362SJack F Vogel /** 486ab5d0362SJack F Vogel * e1000_update_nvm_checksum_i210 - Update EEPROM checksum 487ab5d0362SJack F Vogel * @hw: pointer to the HW structure 488ab5d0362SJack F Vogel * 489ab5d0362SJack F Vogel * Updates the EEPROM checksum by reading/adding each word of the EEPROM 490ab5d0362SJack F Vogel * up to the checksum. Then calculates the EEPROM checksum and writes the 491ab5d0362SJack F Vogel * value to the EEPROM. Next commit EEPROM data onto the Flash. 492ab5d0362SJack F Vogel **/ 493ab5d0362SJack F Vogel s32 e1000_update_nvm_checksum_i210(struct e1000_hw *hw) 494ab5d0362SJack F Vogel { 4958cc64f1eSJack F Vogel s32 ret_val; 496ab5d0362SJack F Vogel u16 checksum = 0; 497ab5d0362SJack F Vogel u16 i, nvm_data; 498ab5d0362SJack F Vogel 499ab5d0362SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_i210"); 500ab5d0362SJack F Vogel 501ab5d0362SJack F Vogel /* 502ab5d0362SJack F Vogel * Read the first word from the EEPROM. If this times out or fails, do 503ab5d0362SJack F Vogel * not continue or we could be in for a very long wait while every 504ab5d0362SJack F Vogel * EEPROM read fails 505ab5d0362SJack F Vogel */ 506ab5d0362SJack F Vogel ret_val = e1000_read_nvm_eerd(hw, 0, 1, &nvm_data); 507ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) { 508ab5d0362SJack F Vogel DEBUGOUT("EEPROM read failed\n"); 509ab5d0362SJack F Vogel goto out; 510ab5d0362SJack F Vogel } 511ab5d0362SJack F Vogel 512ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { 513ab5d0362SJack F Vogel /* 514ab5d0362SJack F Vogel * Do not use hw->nvm.ops.write, hw->nvm.ops.read 515ab5d0362SJack F Vogel * because we do not want to take the synchronization 516ab5d0362SJack F Vogel * semaphores twice here. 517ab5d0362SJack F Vogel */ 518ab5d0362SJack F Vogel 519ab5d0362SJack F Vogel for (i = 0; i < NVM_CHECKSUM_REG; i++) { 520ab5d0362SJack F Vogel ret_val = e1000_read_nvm_eerd(hw, i, 1, &nvm_data); 521ab5d0362SJack F Vogel if (ret_val) { 522ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 523ab5d0362SJack F Vogel DEBUGOUT("NVM Read Error while updating checksum.\n"); 524ab5d0362SJack F Vogel goto out; 525ab5d0362SJack F Vogel } 526ab5d0362SJack F Vogel checksum += nvm_data; 527ab5d0362SJack F Vogel } 528ab5d0362SJack F Vogel checksum = (u16) NVM_SUM - checksum; 529ab5d0362SJack F Vogel ret_val = e1000_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, 530ab5d0362SJack F Vogel &checksum); 531ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) { 532ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 533ab5d0362SJack F Vogel DEBUGOUT("NVM Write Error while updating checksum.\n"); 534ab5d0362SJack F Vogel goto out; 535ab5d0362SJack F Vogel } 536ab5d0362SJack F Vogel 537ab5d0362SJack F Vogel hw->nvm.ops.release(hw); 538ab5d0362SJack F Vogel 539ab5d0362SJack F Vogel ret_val = e1000_update_flash_i210(hw); 540ab5d0362SJack F Vogel } else { 541ab5d0362SJack F Vogel ret_val = E1000_ERR_SWFW_SYNC; 542ab5d0362SJack F Vogel } 543ab5d0362SJack F Vogel out: 544ab5d0362SJack F Vogel return ret_val; 545ab5d0362SJack F Vogel } 546ab5d0362SJack F Vogel 547ab5d0362SJack F Vogel /** 5487609433eSJack F Vogel * e1000_get_flash_presence_i210 - Check if flash device is detected. 5497609433eSJack F Vogel * @hw: pointer to the HW structure 5507609433eSJack F Vogel * 5517609433eSJack F Vogel **/ 5527609433eSJack F Vogel bool e1000_get_flash_presence_i210(struct e1000_hw *hw) 5537609433eSJack F Vogel { 5547609433eSJack F Vogel u32 eec = 0; 555*1bbdc25fSKevin Bowling bool ret_val = false; 5567609433eSJack F Vogel 5577609433eSJack F Vogel DEBUGFUNC("e1000_get_flash_presence_i210"); 5587609433eSJack F Vogel 5597609433eSJack F Vogel eec = E1000_READ_REG(hw, E1000_EECD); 5607609433eSJack F Vogel 5617609433eSJack F Vogel if (eec & E1000_EECD_FLASH_DETECTED_I210) 562*1bbdc25fSKevin Bowling ret_val = true; 5637609433eSJack F Vogel 5647609433eSJack F Vogel return ret_val; 5657609433eSJack F Vogel } 5667609433eSJack F Vogel 5677609433eSJack F Vogel /** 568ab5d0362SJack F Vogel * e1000_update_flash_i210 - Commit EEPROM to the flash 569ab5d0362SJack F Vogel * @hw: pointer to the HW structure 570ab5d0362SJack F Vogel * 571ab5d0362SJack F Vogel **/ 572ab5d0362SJack F Vogel s32 e1000_update_flash_i210(struct e1000_hw *hw) 573ab5d0362SJack F Vogel { 5748cc64f1eSJack F Vogel s32 ret_val; 575ab5d0362SJack F Vogel u32 flup; 576ab5d0362SJack F Vogel 577ab5d0362SJack F Vogel DEBUGFUNC("e1000_update_flash_i210"); 578ab5d0362SJack F Vogel 579ab5d0362SJack F Vogel ret_val = e1000_pool_flash_update_done_i210(hw); 580ab5d0362SJack F Vogel if (ret_val == -E1000_ERR_NVM) { 581ab5d0362SJack F Vogel DEBUGOUT("Flash update time out\n"); 582ab5d0362SJack F Vogel goto out; 583ab5d0362SJack F Vogel } 584ab5d0362SJack F Vogel 585ab5d0362SJack F Vogel flup = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD_I210; 586ab5d0362SJack F Vogel E1000_WRITE_REG(hw, E1000_EECD, flup); 587ab5d0362SJack F Vogel 588ab5d0362SJack F Vogel ret_val = e1000_pool_flash_update_done_i210(hw); 589ab5d0362SJack F Vogel if (ret_val == E1000_SUCCESS) 590ab5d0362SJack F Vogel DEBUGOUT("Flash update complete\n"); 591ab5d0362SJack F Vogel else 592ab5d0362SJack F Vogel DEBUGOUT("Flash update time out\n"); 593ab5d0362SJack F Vogel 594ab5d0362SJack F Vogel out: 595ab5d0362SJack F Vogel return ret_val; 596ab5d0362SJack F Vogel } 597ab5d0362SJack F Vogel 598ab5d0362SJack F Vogel /** 599ab5d0362SJack F Vogel * e1000_pool_flash_update_done_i210 - Pool FLUDONE status. 600ab5d0362SJack F Vogel * @hw: pointer to the HW structure 601ab5d0362SJack F Vogel * 602ab5d0362SJack F Vogel **/ 603ab5d0362SJack F Vogel s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw) 604ab5d0362SJack F Vogel { 605ab5d0362SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 606ab5d0362SJack F Vogel u32 i, reg; 607ab5d0362SJack F Vogel 608ab5d0362SJack F Vogel DEBUGFUNC("e1000_pool_flash_update_done_i210"); 609ab5d0362SJack F Vogel 610ab5d0362SJack F Vogel for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { 611ab5d0362SJack F Vogel reg = E1000_READ_REG(hw, E1000_EECD); 612ab5d0362SJack F Vogel if (reg & E1000_EECD_FLUDONE_I210) { 613ab5d0362SJack F Vogel ret_val = E1000_SUCCESS; 614ab5d0362SJack F Vogel break; 615ab5d0362SJack F Vogel } 616ab5d0362SJack F Vogel usec_delay(5); 617ab5d0362SJack F Vogel } 618ab5d0362SJack F Vogel 619ab5d0362SJack F Vogel return ret_val; 620ab5d0362SJack F Vogel } 621ab5d0362SJack F Vogel 622ab5d0362SJack F Vogel /** 623ab5d0362SJack F Vogel * e1000_init_nvm_params_i210 - Initialize i210 NVM function pointers 624ab5d0362SJack F Vogel * @hw: pointer to the HW structure 625ab5d0362SJack F Vogel * 6267609433eSJack F Vogel * Initialize the i210/i211 NVM parameters and function pointers. 627ab5d0362SJack F Vogel **/ 628ab5d0362SJack F Vogel static s32 e1000_init_nvm_params_i210(struct e1000_hw *hw) 629ab5d0362SJack F Vogel { 6308cc64f1eSJack F Vogel s32 ret_val; 631ab5d0362SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 632ab5d0362SJack F Vogel 633ab5d0362SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_i210"); 634ab5d0362SJack F Vogel 635ab5d0362SJack F Vogel ret_val = e1000_init_nvm_params_82575(hw); 636ab5d0362SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_i210; 637ab5d0362SJack F Vogel nvm->ops.release = e1000_release_nvm_i210; 6387609433eSJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_i210; 6397609433eSJack F Vogel if (e1000_get_flash_presence_i210(hw)) { 6407609433eSJack F Vogel hw->nvm.type = e1000_nvm_flash_hw; 641ab5d0362SJack F Vogel nvm->ops.read = e1000_read_nvm_srrd_i210; 642ab5d0362SJack F Vogel nvm->ops.write = e1000_write_nvm_srwr_i210; 643ab5d0362SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_i210; 644ab5d0362SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_i210; 6457609433eSJack F Vogel } else { 6467609433eSJack F Vogel hw->nvm.type = e1000_nvm_invm; 6477609433eSJack F Vogel nvm->ops.read = e1000_read_invm_i210; 648ab5d0362SJack F Vogel nvm->ops.write = e1000_null_write_nvm; 649ab5d0362SJack F Vogel nvm->ops.validate = e1000_null_ops_generic; 650ab5d0362SJack F Vogel nvm->ops.update = e1000_null_ops_generic; 6517609433eSJack F Vogel } 6527609433eSJack F Vogel return ret_val; 653ab5d0362SJack F Vogel } 654ab5d0362SJack F Vogel 655ab5d0362SJack F Vogel /** 656ab5d0362SJack F Vogel * e1000_init_function_pointers_i210 - Init func ptrs. 657ab5d0362SJack F Vogel * @hw: pointer to the HW structure 658ab5d0362SJack F Vogel * 659ab5d0362SJack F Vogel * Called to initialize all function pointers and parameters. 660ab5d0362SJack F Vogel **/ 661ab5d0362SJack F Vogel void e1000_init_function_pointers_i210(struct e1000_hw *hw) 662ab5d0362SJack F Vogel { 663ab5d0362SJack F Vogel e1000_init_function_pointers_82575(hw); 664ab5d0362SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_i210; 665ab5d0362SJack F Vogel } 666ab5d0362SJack F Vogel 667ab5d0362SJack F Vogel /** 668ab5d0362SJack F Vogel * e1000_valid_led_default_i210 - Verify a valid default LED config 669ab5d0362SJack F Vogel * @hw: pointer to the HW structure 670ab5d0362SJack F Vogel * @data: pointer to the NVM (EEPROM) 671ab5d0362SJack F Vogel * 672ab5d0362SJack F Vogel * Read the EEPROM for the current default LED configuration. If the 673ab5d0362SJack F Vogel * LED configuration is not valid, set to a valid LED configuration. 674ab5d0362SJack F Vogel **/ 675ab5d0362SJack F Vogel static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data) 676ab5d0362SJack F Vogel { 677ab5d0362SJack F Vogel s32 ret_val; 678ab5d0362SJack F Vogel 679ab5d0362SJack F Vogel DEBUGFUNC("e1000_valid_led_default_i210"); 680ab5d0362SJack F Vogel 681ab5d0362SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 682ab5d0362SJack F Vogel if (ret_val) { 683ab5d0362SJack F Vogel DEBUGOUT("NVM Read Error\n"); 684ab5d0362SJack F Vogel goto out; 685ab5d0362SJack F Vogel } 686ab5d0362SJack F Vogel 687ab5d0362SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { 688ab5d0362SJack F Vogel switch (hw->phy.media_type) { 689ab5d0362SJack F Vogel case e1000_media_type_internal_serdes: 690ab5d0362SJack F Vogel *data = ID_LED_DEFAULT_I210_SERDES; 691ab5d0362SJack F Vogel break; 692ab5d0362SJack F Vogel case e1000_media_type_copper: 693ab5d0362SJack F Vogel default: 694ab5d0362SJack F Vogel *data = ID_LED_DEFAULT_I210; 695ab5d0362SJack F Vogel break; 696ab5d0362SJack F Vogel } 697ab5d0362SJack F Vogel } 698ab5d0362SJack F Vogel out: 699ab5d0362SJack F Vogel return ret_val; 700ab5d0362SJack F Vogel } 7017609433eSJack F Vogel 7027609433eSJack F Vogel /** 7038cc64f1eSJack F Vogel * e1000_pll_workaround_i210 7048cc64f1eSJack F Vogel * @hw: pointer to the HW structure 7058cc64f1eSJack F Vogel * 7068cc64f1eSJack F Vogel * Works around an errata in the PLL circuit where it occasionally 7078cc64f1eSJack F Vogel * provides the wrong clock frequency after power up. 7088cc64f1eSJack F Vogel **/ 7098cc64f1eSJack F Vogel static s32 e1000_pll_workaround_i210(struct e1000_hw *hw) 7108cc64f1eSJack F Vogel { 7118cc64f1eSJack F Vogel s32 ret_val; 7128cc64f1eSJack F Vogel u32 wuc, mdicnfg, ctrl, ctrl_ext, reg_val; 7138cc64f1eSJack F Vogel u16 nvm_word, phy_word, pci_word, tmp_nvm; 7148cc64f1eSJack F Vogel int i; 7158cc64f1eSJack F Vogel 7161883a6ffSGuinan Sun /* Get PHY semaphore */ 7171883a6ffSGuinan Sun hw->phy.ops.acquire(hw); 7188cc64f1eSJack F Vogel /* Get and set needed register values */ 7198cc64f1eSJack F Vogel wuc = E1000_READ_REG(hw, E1000_WUC); 7208cc64f1eSJack F Vogel mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG); 7218cc64f1eSJack F Vogel reg_val = mdicnfg & ~E1000_MDICNFG_EXT_MDIO; 7228cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_MDICNFG, reg_val); 7238cc64f1eSJack F Vogel 7248cc64f1eSJack F Vogel /* Get data from NVM, or set default */ 7258cc64f1eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, E1000_INVM_AUTOLOAD, 7268cc64f1eSJack F Vogel &nvm_word); 7278cc64f1eSJack F Vogel if (ret_val != E1000_SUCCESS) 7288cc64f1eSJack F Vogel nvm_word = E1000_INVM_DEFAULT_AL; 7298cc64f1eSJack F Vogel tmp_nvm = nvm_word | E1000_INVM_PLL_WO_VAL; 730984d1616SKevin Bowling phy_word = E1000_PHY_PLL_UNCONF; 7318cc64f1eSJack F Vogel for (i = 0; i < E1000_MAX_PLL_TRIES; i++) { 7328cc64f1eSJack F Vogel /* check current state directly from internal PHY */ 7331883a6ffSGuinan Sun e1000_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, 0xFC); 7341883a6ffSGuinan Sun usec_delay(20); 7351883a6ffSGuinan Sun e1000_read_phy_reg_mdic(hw, E1000_PHY_PLL_FREQ_REG, &phy_word); 7361883a6ffSGuinan Sun usec_delay(20); 7371883a6ffSGuinan Sun e1000_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, 0); 7388cc64f1eSJack F Vogel if ((phy_word & E1000_PHY_PLL_UNCONF) 7398cc64f1eSJack F Vogel != E1000_PHY_PLL_UNCONF) { 7408cc64f1eSJack F Vogel ret_val = E1000_SUCCESS; 7418cc64f1eSJack F Vogel break; 7428cc64f1eSJack F Vogel } else { 7438cc64f1eSJack F Vogel ret_val = -E1000_ERR_PHY; 7448cc64f1eSJack F Vogel } 7458cc64f1eSJack F Vogel /* directly reset the internal PHY */ 7468cc64f1eSJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 7478cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl|E1000_CTRL_PHY_RST); 7488cc64f1eSJack F Vogel 7498cc64f1eSJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 7508cc64f1eSJack F Vogel ctrl_ext |= (E1000_CTRL_EXT_PHYPDEN | E1000_CTRL_EXT_SDLPE); 7518cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 7528cc64f1eSJack F Vogel 7538cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_WUC, 0); 7548cc64f1eSJack F Vogel reg_val = (E1000_INVM_AUTOLOAD << 4) | (tmp_nvm << 16); 7558cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_EEARBC_I210, reg_val); 7568cc64f1eSJack F Vogel 7578cc64f1eSJack F Vogel e1000_read_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word); 7588cc64f1eSJack F Vogel pci_word |= E1000_PCI_PMCSR_D3; 7598cc64f1eSJack F Vogel e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word); 7608cc64f1eSJack F Vogel msec_delay(1); 7618cc64f1eSJack F Vogel pci_word &= ~E1000_PCI_PMCSR_D3; 7628cc64f1eSJack F Vogel e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word); 7638cc64f1eSJack F Vogel reg_val = (E1000_INVM_AUTOLOAD << 4) | (nvm_word << 16); 7648cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_EEARBC_I210, reg_val); 7658cc64f1eSJack F Vogel 7668cc64f1eSJack F Vogel /* restore WUC register */ 7678cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_WUC, wuc); 7688cc64f1eSJack F Vogel } 7698cc64f1eSJack F Vogel /* restore MDICNFG setting */ 7708cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg); 7711883a6ffSGuinan Sun /* Release PHY semaphore */ 7721883a6ffSGuinan Sun hw->phy.ops.release(hw); 7738cc64f1eSJack F Vogel return ret_val; 7748cc64f1eSJack F Vogel } 7758cc64f1eSJack F Vogel 7768cc64f1eSJack F Vogel /** 777c80429ceSEric Joyner * e1000_get_cfg_done_i210 - Read config done bit 778c80429ceSEric Joyner * @hw: pointer to the HW structure 779c80429ceSEric Joyner * 780c80429ceSEric Joyner * Read the management control register for the config done bit for 781c80429ceSEric Joyner * completion status. NOTE: silicon which is EEPROM-less will fail trying 782c80429ceSEric Joyner * to read the config done bit, so an error is *ONLY* logged and returns 783c80429ceSEric Joyner * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon 784c80429ceSEric Joyner * would not be able to be reset or change link. 785c80429ceSEric Joyner **/ 786c80429ceSEric Joyner static s32 e1000_get_cfg_done_i210(struct e1000_hw *hw) 787c80429ceSEric Joyner { 788c80429ceSEric Joyner s32 timeout = PHY_CFG_TIMEOUT; 789c80429ceSEric Joyner u32 mask = E1000_NVM_CFG_DONE_PORT_0; 790c80429ceSEric Joyner 791c80429ceSEric Joyner DEBUGFUNC("e1000_get_cfg_done_i210"); 792c80429ceSEric Joyner 793c80429ceSEric Joyner while (timeout) { 794c80429ceSEric Joyner if (E1000_READ_REG(hw, E1000_EEMNGCTL_I210) & mask) 795c80429ceSEric Joyner break; 796c80429ceSEric Joyner msec_delay(1); 797c80429ceSEric Joyner timeout--; 798c80429ceSEric Joyner } 799c80429ceSEric Joyner if (!timeout) 800c80429ceSEric Joyner DEBUGOUT("MNG configuration cycle has not completed.\n"); 801c80429ceSEric Joyner 802c80429ceSEric Joyner return E1000_SUCCESS; 803c80429ceSEric Joyner } 804c80429ceSEric Joyner 805c80429ceSEric Joyner /** 8068cc64f1eSJack F Vogel * e1000_init_hw_i210 - Init hw for I210/I211 8078cc64f1eSJack F Vogel * @hw: pointer to the HW structure 8088cc64f1eSJack F Vogel * 8098cc64f1eSJack F Vogel * Called to initialize hw for i210 hw family. 8108cc64f1eSJack F Vogel **/ 8118cc64f1eSJack F Vogel s32 e1000_init_hw_i210(struct e1000_hw *hw) 8128cc64f1eSJack F Vogel { 81351569bd7SEric Joyner struct e1000_mac_info *mac = &hw->mac; 8148cc64f1eSJack F Vogel s32 ret_val; 8158cc64f1eSJack F Vogel 8168cc64f1eSJack F Vogel DEBUGFUNC("e1000_init_hw_i210"); 8178cc64f1eSJack F Vogel if ((hw->mac.type >= e1000_i210) && 8188cc64f1eSJack F Vogel !(e1000_get_flash_presence_i210(hw))) { 8198cc64f1eSJack F Vogel ret_val = e1000_pll_workaround_i210(hw); 8208cc64f1eSJack F Vogel if (ret_val != E1000_SUCCESS) 8218cc64f1eSJack F Vogel return ret_val; 8228cc64f1eSJack F Vogel } 823c80429ceSEric Joyner hw->phy.ops.get_cfg_done = e1000_get_cfg_done_i210; 82451569bd7SEric Joyner 82551569bd7SEric Joyner /* Initialize identification LED */ 82651569bd7SEric Joyner mac->ops.id_led_init(hw); 82751569bd7SEric Joyner 8286b9d35faSGuinan Sun ret_val = e1000_init_hw_base(hw); 8298cc64f1eSJack F Vogel return ret_val; 8308cc64f1eSJack F Vogel } 831