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
35ab5d0362SJack F Vogel #include "e1000_api.h"
36ab5d0362SJack F Vogel
37ab5d0362SJack F Vogel
38ab5d0362SJack F Vogel static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw);
39ab5d0362SJack F Vogel static void e1000_release_nvm_i210(struct e1000_hw *hw);
40ab5d0362SJack F Vogel static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
41ab5d0362SJack F Vogel u16 *data);
42ab5d0362SJack F Vogel static s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw);
43ab5d0362SJack F Vogel static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
44ab5d0362SJack F Vogel
45ab5d0362SJack F Vogel /**
46ab5d0362SJack F Vogel * e1000_acquire_nvm_i210 - Request for access to EEPROM
47ab5d0362SJack F Vogel * @hw: pointer to the HW structure
48ab5d0362SJack F Vogel *
49ab5d0362SJack F Vogel * Acquire the necessary semaphores for exclusive access to the EEPROM.
50ab5d0362SJack F Vogel * Set the EEPROM access request bit and wait for EEPROM access grant bit.
51ab5d0362SJack F Vogel * Return successful if access grant bit set, else clear the request for
52ab5d0362SJack F Vogel * EEPROM access and return -E1000_ERR_NVM (-1).
53ab5d0362SJack F Vogel **/
e1000_acquire_nvm_i210(struct e1000_hw * hw)54ab5d0362SJack F Vogel static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw)
55ab5d0362SJack F Vogel {
56ab5d0362SJack F Vogel s32 ret_val;
57ab5d0362SJack F Vogel
58ab5d0362SJack F Vogel DEBUGFUNC("e1000_acquire_nvm_i210");
59ab5d0362SJack F Vogel
60d5210708SMatt Macy ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM);
61ab5d0362SJack F Vogel
62ab5d0362SJack F Vogel return ret_val;
63ab5d0362SJack F Vogel }
64ab5d0362SJack F Vogel
65ab5d0362SJack F Vogel /**
66ab5d0362SJack F Vogel * e1000_release_nvm_i210 - Release exclusive access to EEPROM
67ab5d0362SJack F Vogel * @hw: pointer to the HW structure
68ab5d0362SJack F Vogel *
69ab5d0362SJack F Vogel * Stop any current commands to the EEPROM and clear the EEPROM request bit,
70ab5d0362SJack F Vogel * then release the semaphores acquired.
71ab5d0362SJack F Vogel **/
e1000_release_nvm_i210(struct e1000_hw * hw)72ab5d0362SJack F Vogel static void e1000_release_nvm_i210(struct e1000_hw *hw)
73ab5d0362SJack F Vogel {
74ab5d0362SJack F Vogel DEBUGFUNC("e1000_release_nvm_i210");
75ab5d0362SJack F Vogel
76d5210708SMatt Macy e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM);
77ab5d0362SJack F Vogel }
78ab5d0362SJack F Vogel
79ab5d0362SJack F Vogel /**
80ab5d0362SJack F Vogel * e1000_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register
81ab5d0362SJack F Vogel * @hw: pointer to the HW structure
82ab5d0362SJack F Vogel * @offset: offset of word in the Shadow Ram to read
83ab5d0362SJack F Vogel * @words: number of words to read
84ab5d0362SJack F Vogel * @data: word read from the Shadow Ram
85ab5d0362SJack F Vogel *
86ab5d0362SJack F Vogel * Reads a 16 bit word from the Shadow Ram using the EERD register.
87ab5d0362SJack F Vogel * Uses necessary synchronization semaphores.
88ab5d0362SJack F Vogel **/
e1000_read_nvm_srrd_i210(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)89ab5d0362SJack F Vogel s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
90ab5d0362SJack F Vogel u16 *data)
91ab5d0362SJack F Vogel {
92ab5d0362SJack F Vogel s32 status = E1000_SUCCESS;
93ab5d0362SJack F Vogel u16 i, count;
94ab5d0362SJack F Vogel
95ab5d0362SJack F Vogel DEBUGFUNC("e1000_read_nvm_srrd_i210");
96ab5d0362SJack F Vogel
97ab5d0362SJack F Vogel /* We cannot hold synchronization semaphores for too long,
98ab5d0362SJack F Vogel * because of forceful takeover procedure. However it is more efficient
99ab5d0362SJack F Vogel * to read in bursts than synchronizing access for each word. */
100ab5d0362SJack F Vogel for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
101ab5d0362SJack F Vogel count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
102ab5d0362SJack F Vogel E1000_EERD_EEWR_MAX_COUNT : (words - i);
103ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
104ab5d0362SJack F Vogel status = e1000_read_nvm_eerd(hw, offset, count,
105ab5d0362SJack F Vogel data + i);
106ab5d0362SJack F Vogel hw->nvm.ops.release(hw);
107ab5d0362SJack F Vogel } else {
108ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC;
109ab5d0362SJack F Vogel }
110ab5d0362SJack F Vogel
111ab5d0362SJack F Vogel if (status != E1000_SUCCESS)
112ab5d0362SJack F Vogel break;
113ab5d0362SJack F Vogel }
114ab5d0362SJack F Vogel
115ab5d0362SJack F Vogel return status;
116ab5d0362SJack F Vogel }
117ab5d0362SJack F Vogel
118ab5d0362SJack F Vogel /**
119ab5d0362SJack F Vogel * e1000_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR
120ab5d0362SJack F Vogel * @hw: pointer to the HW structure
121ab5d0362SJack F Vogel * @offset: offset within the Shadow RAM to be written to
122ab5d0362SJack F Vogel * @words: number of words to write
123ab5d0362SJack F Vogel * @data: 16 bit word(s) to be written to the Shadow RAM
124ab5d0362SJack F Vogel *
125ab5d0362SJack F Vogel * Writes data to Shadow RAM at offset using EEWR register.
126ab5d0362SJack F Vogel *
127ab5d0362SJack F Vogel * If e1000_update_nvm_checksum is not called after this function , the
128ab5d0362SJack F Vogel * data will not be committed to FLASH and also Shadow RAM will most likely
129ab5d0362SJack F Vogel * contain an invalid checksum.
130ab5d0362SJack F Vogel *
131ab5d0362SJack F Vogel * If error code is returned, data and Shadow RAM may be inconsistent - buffer
132ab5d0362SJack F Vogel * partially written.
133ab5d0362SJack F Vogel **/
e1000_write_nvm_srwr_i210(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)134ab5d0362SJack F Vogel s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
135ab5d0362SJack F Vogel u16 *data)
136ab5d0362SJack F Vogel {
137ab5d0362SJack F Vogel s32 status = E1000_SUCCESS;
138ab5d0362SJack F Vogel u16 i, count;
139ab5d0362SJack F Vogel
140ab5d0362SJack F Vogel DEBUGFUNC("e1000_write_nvm_srwr_i210");
141ab5d0362SJack F Vogel
142ab5d0362SJack F Vogel /* We cannot hold synchronization semaphores for too long,
143ab5d0362SJack F Vogel * because of forceful takeover procedure. However it is more efficient
144ab5d0362SJack F Vogel * to write in bursts than synchronizing access for each word. */
145ab5d0362SJack F Vogel for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
146ab5d0362SJack F Vogel count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
147ab5d0362SJack F Vogel E1000_EERD_EEWR_MAX_COUNT : (words - i);
148ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
149ab5d0362SJack F Vogel status = e1000_write_nvm_srwr(hw, offset, count,
150ab5d0362SJack F Vogel data + i);
151ab5d0362SJack F Vogel hw->nvm.ops.release(hw);
152ab5d0362SJack F Vogel } else {
153ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC;
154ab5d0362SJack F Vogel }
155ab5d0362SJack F Vogel
156ab5d0362SJack F Vogel if (status != E1000_SUCCESS)
157ab5d0362SJack F Vogel break;
158ab5d0362SJack F Vogel }
159ab5d0362SJack F Vogel
160ab5d0362SJack F Vogel return status;
161ab5d0362SJack F Vogel }
162ab5d0362SJack F Vogel
163ab5d0362SJack F Vogel /**
164ab5d0362SJack F Vogel * e1000_write_nvm_srwr - Write to Shadow Ram using EEWR
165ab5d0362SJack F Vogel * @hw: pointer to the HW structure
166ab5d0362SJack F Vogel * @offset: offset within the Shadow Ram to be written to
167ab5d0362SJack F Vogel * @words: number of words to write
168ab5d0362SJack F Vogel * @data: 16 bit word(s) to be written to the Shadow Ram
169ab5d0362SJack F Vogel *
170ab5d0362SJack F Vogel * Writes data to Shadow Ram at offset using EEWR register.
171ab5d0362SJack F Vogel *
172ab5d0362SJack F Vogel * If e1000_update_nvm_checksum is not called after this function , the
173ab5d0362SJack F Vogel * Shadow Ram will most likely contain an invalid checksum.
174ab5d0362SJack F Vogel **/
e1000_write_nvm_srwr(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)175ab5d0362SJack F Vogel static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
176ab5d0362SJack F Vogel u16 *data)
177ab5d0362SJack F Vogel {
178ab5d0362SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
179ab5d0362SJack F Vogel u32 i, k, eewr = 0;
180ab5d0362SJack F Vogel u32 attempts = 100000;
181ab5d0362SJack F Vogel s32 ret_val = E1000_SUCCESS;
182ab5d0362SJack F Vogel
183ab5d0362SJack F Vogel DEBUGFUNC("e1000_write_nvm_srwr");
184ab5d0362SJack F Vogel
185ab5d0362SJack F Vogel /*
186ab5d0362SJack F Vogel * A check for invalid values: offset too large, too many words,
187ab5d0362SJack F Vogel * too many words for the offset, and not enough words.
188ab5d0362SJack F Vogel */
189ab5d0362SJack F Vogel if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
190ab5d0362SJack F Vogel (words == 0)) {
191ab5d0362SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n");
192ab5d0362SJack F Vogel ret_val = -E1000_ERR_NVM;
193ab5d0362SJack F Vogel goto out;
194ab5d0362SJack F Vogel }
195ab5d0362SJack F Vogel
196ab5d0362SJack F Vogel for (i = 0; i < words; i++) {
197f6517a7eSChengwen Feng ret_val = -E1000_ERR_NVM;
198f6517a7eSChengwen Feng
199ab5d0362SJack F Vogel eewr = ((offset + i) << E1000_NVM_RW_ADDR_SHIFT) |
200ab5d0362SJack F Vogel (data[i] << E1000_NVM_RW_REG_DATA) |
201ab5d0362SJack F Vogel E1000_NVM_RW_REG_START;
202ab5d0362SJack F Vogel
203ab5d0362SJack F Vogel E1000_WRITE_REG(hw, E1000_SRWR, eewr);
204ab5d0362SJack F Vogel
205ab5d0362SJack F Vogel for (k = 0; k < attempts; k++) {
206ab5d0362SJack F Vogel if (E1000_NVM_RW_REG_DONE &
207ab5d0362SJack F Vogel E1000_READ_REG(hw, E1000_SRWR)) {
208ab5d0362SJack F Vogel ret_val = E1000_SUCCESS;
209ab5d0362SJack F Vogel break;
210ab5d0362SJack F Vogel }
211ab5d0362SJack F Vogel usec_delay(5);
212ab5d0362SJack F Vogel }
213ab5d0362SJack F Vogel
214ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) {
215ab5d0362SJack F Vogel DEBUGOUT("Shadow RAM write EEWR timed out\n");
216ab5d0362SJack F Vogel break;
217ab5d0362SJack F Vogel }
218ab5d0362SJack F Vogel }
219ab5d0362SJack F Vogel
220ab5d0362SJack F Vogel out:
221ab5d0362SJack F Vogel return ret_val;
222ab5d0362SJack F Vogel }
223ab5d0362SJack F Vogel
2247609433eSJack F Vogel /** e1000_read_invm_word_i210 - Reads OTP
225ab5d0362SJack F Vogel * @hw: pointer to the HW structure
226ab5d0362SJack F Vogel * @address: the word address (aka eeprom offset) to read
227ab5d0362SJack F Vogel * @data: pointer to the data read
228ab5d0362SJack F Vogel *
229ab5d0362SJack F Vogel * Reads 16-bit words from the OTP. Return error when the word is not
230ab5d0362SJack F Vogel * stored in OTP.
231ab5d0362SJack F Vogel **/
e1000_read_invm_word_i210(struct e1000_hw * hw,u8 address,u16 * data)2327609433eSJack F Vogel static s32 e1000_read_invm_word_i210(struct e1000_hw *hw, u8 address, u16 *data)
233ab5d0362SJack F Vogel {
234ab5d0362SJack F Vogel s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
235ab5d0362SJack F Vogel u32 invm_dword;
236ab5d0362SJack F Vogel u16 i;
237ab5d0362SJack F Vogel u8 record_type, word_address;
238ab5d0362SJack F Vogel
2397609433eSJack F Vogel DEBUGFUNC("e1000_read_invm_word_i210");
240ab5d0362SJack F Vogel
241ab5d0362SJack F Vogel for (i = 0; i < E1000_INVM_SIZE; i++) {
242ab5d0362SJack F Vogel invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i));
243ab5d0362SJack F Vogel /* Get record type */
244ab5d0362SJack F Vogel record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
245ab5d0362SJack F Vogel if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE)
246ab5d0362SJack F Vogel break;
247ab5d0362SJack F Vogel if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE)
248ab5d0362SJack F Vogel i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
249ab5d0362SJack F Vogel if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE)
250ab5d0362SJack F Vogel i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
251ab5d0362SJack F Vogel if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) {
252ab5d0362SJack F Vogel word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
253ab5d0362SJack F Vogel if (word_address == address) {
254ab5d0362SJack F Vogel *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
255ab5d0362SJack F Vogel DEBUGOUT2("Read INVM Word 0x%02x = %x",
256ab5d0362SJack F Vogel address, *data);
257ab5d0362SJack F Vogel status = E1000_SUCCESS;
258ab5d0362SJack F Vogel break;
259ab5d0362SJack F Vogel }
260ab5d0362SJack F Vogel }
261ab5d0362SJack F Vogel }
262ab5d0362SJack F Vogel if (status != E1000_SUCCESS)
263ab5d0362SJack F Vogel DEBUGOUT1("Requested word 0x%02x not found in OTP\n", address);
264ab5d0362SJack F Vogel return status;
265ab5d0362SJack F Vogel }
266ab5d0362SJack F Vogel
2677609433eSJack F Vogel /** e1000_read_invm_i210 - Read invm wrapper function for I210/I211
2687609433eSJack F Vogel * @hw: pointer to the HW structure
2697609433eSJack F Vogel * @address: the word address (aka eeprom offset) to read
2707609433eSJack F Vogel * @data: pointer to the data read
2717609433eSJack F Vogel *
2727609433eSJack F Vogel * Wrapper function to return data formerly found in the NVM.
2737609433eSJack F Vogel **/
e1000_read_invm_i210(struct e1000_hw * hw,u16 offset,u16 E1000_UNUSEDARG words,u16 * data)2747609433eSJack F Vogel static s32 e1000_read_invm_i210(struct e1000_hw *hw, u16 offset,
2757609433eSJack F Vogel u16 E1000_UNUSEDARG words, u16 *data)
2767609433eSJack F Vogel {
2777609433eSJack F Vogel s32 ret_val = E1000_SUCCESS;
2787609433eSJack F Vogel
2797609433eSJack F Vogel DEBUGFUNC("e1000_read_invm_i210");
2807609433eSJack F Vogel
2817609433eSJack F Vogel /* Only the MAC addr is required to be present in the iNVM */
2827609433eSJack F Vogel switch (offset) {
2837609433eSJack F Vogel case NVM_MAC_ADDR:
2847609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, &data[0]);
2857609433eSJack F Vogel ret_val |= e1000_read_invm_word_i210(hw, (u8)offset + 1,
2867609433eSJack F Vogel &data[1]);
2877609433eSJack F Vogel ret_val |= e1000_read_invm_word_i210(hw, (u8)offset + 2,
2887609433eSJack F Vogel &data[2]);
2897609433eSJack F Vogel if (ret_val != E1000_SUCCESS)
2907609433eSJack F Vogel DEBUGOUT("MAC Addr not found in iNVM\n");
2917609433eSJack F Vogel break;
2927609433eSJack F Vogel case NVM_INIT_CTRL_2:
2937609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
2947609433eSJack F Vogel if (ret_val != E1000_SUCCESS) {
2957609433eSJack F Vogel *data = NVM_INIT_CTRL_2_DEFAULT_I211;
2967609433eSJack F Vogel ret_val = E1000_SUCCESS;
2977609433eSJack F Vogel }
2987609433eSJack F Vogel break;
2997609433eSJack F Vogel case NVM_INIT_CTRL_4:
3007609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
3017609433eSJack F Vogel if (ret_val != E1000_SUCCESS) {
3027609433eSJack F Vogel *data = NVM_INIT_CTRL_4_DEFAULT_I211;
3037609433eSJack F Vogel ret_val = E1000_SUCCESS;
3047609433eSJack F Vogel }
3057609433eSJack F Vogel break;
3067609433eSJack F Vogel case NVM_LED_1_CFG:
3077609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
3087609433eSJack F Vogel if (ret_val != E1000_SUCCESS) {
3097609433eSJack F Vogel *data = NVM_LED_1_CFG_DEFAULT_I211;
3107609433eSJack F Vogel ret_val = E1000_SUCCESS;
3117609433eSJack F Vogel }
3127609433eSJack F Vogel break;
3137609433eSJack F Vogel case NVM_LED_0_2_CFG:
3147609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
3157609433eSJack F Vogel if (ret_val != E1000_SUCCESS) {
3167609433eSJack F Vogel *data = NVM_LED_0_2_CFG_DEFAULT_I211;
3177609433eSJack F Vogel ret_val = E1000_SUCCESS;
3187609433eSJack F Vogel }
3197609433eSJack F Vogel break;
3207609433eSJack F Vogel case NVM_ID_LED_SETTINGS:
3217609433eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
3227609433eSJack F Vogel if (ret_val != E1000_SUCCESS) {
3237609433eSJack F Vogel *data = ID_LED_RESERVED_FFFF;
3247609433eSJack F Vogel ret_val = E1000_SUCCESS;
3257609433eSJack F Vogel }
3267609433eSJack F Vogel break;
3277609433eSJack F Vogel case NVM_SUB_DEV_ID:
3287609433eSJack F Vogel *data = hw->subsystem_device_id;
3297609433eSJack F Vogel break;
3307609433eSJack F Vogel case NVM_SUB_VEN_ID:
3317609433eSJack F Vogel *data = hw->subsystem_vendor_id;
3327609433eSJack F Vogel break;
3337609433eSJack F Vogel case NVM_DEV_ID:
3347609433eSJack F Vogel *data = hw->device_id;
3357609433eSJack F Vogel break;
3367609433eSJack F Vogel case NVM_VEN_ID:
3377609433eSJack F Vogel *data = hw->vendor_id;
3387609433eSJack F Vogel break;
3397609433eSJack F Vogel default:
3407609433eSJack F Vogel DEBUGOUT1("NVM word 0x%02x is not mapped.\n", offset);
3417609433eSJack F Vogel *data = NVM_RESERVED_WORD;
3427609433eSJack F Vogel break;
3437609433eSJack F Vogel }
3447609433eSJack F Vogel return ret_val;
3457609433eSJack F Vogel }
3467609433eSJack F Vogel
347ab5d0362SJack F Vogel /**
348984d1616SKevin Bowling * e1000_read_invm_version - Reads iNVM version and image type
349984d1616SKevin Bowling * @hw: pointer to the HW structure
350984d1616SKevin Bowling * @invm_ver: version structure for the version read
351984d1616SKevin Bowling *
352984d1616SKevin Bowling * Reads iNVM version and image type.
353984d1616SKevin Bowling **/
e1000_read_invm_version(struct e1000_hw * hw,struct e1000_fw_version * invm_ver)354984d1616SKevin Bowling s32 e1000_read_invm_version(struct e1000_hw *hw,
355984d1616SKevin Bowling struct e1000_fw_version *invm_ver)
356984d1616SKevin Bowling {
357984d1616SKevin Bowling u32 *record = NULL;
358984d1616SKevin Bowling u32 *next_record = NULL;
359984d1616SKevin Bowling u32 i = 0;
360984d1616SKevin Bowling u32 invm_dword = 0;
361984d1616SKevin Bowling u32 invm_blocks = E1000_INVM_SIZE - (E1000_INVM_ULT_BYTES_SIZE /
362984d1616SKevin Bowling E1000_INVM_RECORD_SIZE_IN_BYTES);
363984d1616SKevin Bowling u32 buffer[E1000_INVM_SIZE];
364984d1616SKevin Bowling s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
365*ddfec1fbSKevin Bowling u16 nvm_version = 0;
366984d1616SKevin Bowling
367984d1616SKevin Bowling DEBUGFUNC("e1000_read_invm_version");
368984d1616SKevin Bowling
369984d1616SKevin Bowling /* Read iNVM memory */
370984d1616SKevin Bowling for (i = 0; i < E1000_INVM_SIZE; i++) {
371984d1616SKevin Bowling invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i));
372984d1616SKevin Bowling buffer[i] = invm_dword;
373984d1616SKevin Bowling }
374984d1616SKevin Bowling
375984d1616SKevin Bowling /* Read version number */
376984d1616SKevin Bowling for (i = 1; i < invm_blocks; i++) {
377984d1616SKevin Bowling record = &buffer[invm_blocks - i];
378984d1616SKevin Bowling next_record = &buffer[invm_blocks - i + 1];
379984d1616SKevin Bowling
380984d1616SKevin Bowling /* Check if we have first version location used */
381984d1616SKevin Bowling if ((i == 1) && ((*record & E1000_INVM_VER_FIELD_ONE) == 0)) {
382*ddfec1fbSKevin Bowling nvm_version = 0;
383984d1616SKevin Bowling status = E1000_SUCCESS;
384984d1616SKevin Bowling break;
385984d1616SKevin Bowling }
386984d1616SKevin Bowling /* Check if we have second version location used */
387984d1616SKevin Bowling else if ((i == 1) &&
388984d1616SKevin Bowling ((*record & E1000_INVM_VER_FIELD_TWO) == 0)) {
389*ddfec1fbSKevin Bowling nvm_version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
390984d1616SKevin Bowling status = E1000_SUCCESS;
391984d1616SKevin Bowling break;
392984d1616SKevin Bowling }
393984d1616SKevin Bowling /*
394984d1616SKevin Bowling * Check if we have odd version location
395984d1616SKevin Bowling * used and it is the last one used
396984d1616SKevin Bowling */
397984d1616SKevin Bowling else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) &&
398984d1616SKevin Bowling ((*record & 0x3) == 0)) || (((*record & 0x3) != 0) &&
399984d1616SKevin Bowling (i != 1))) {
400*ddfec1fbSKevin Bowling nvm_version = (*next_record & E1000_INVM_VER_FIELD_TWO)
401984d1616SKevin Bowling >> 13;
402984d1616SKevin Bowling status = E1000_SUCCESS;
403984d1616SKevin Bowling break;
404984d1616SKevin Bowling }
405984d1616SKevin Bowling /*
406984d1616SKevin Bowling * Check if we have even version location
407984d1616SKevin Bowling * used and it is the last one used
408984d1616SKevin Bowling */
409984d1616SKevin Bowling else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) &&
410984d1616SKevin Bowling ((*record & 0x3) == 0)) {
411*ddfec1fbSKevin Bowling nvm_version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
412984d1616SKevin Bowling status = E1000_SUCCESS;
413984d1616SKevin Bowling break;
414984d1616SKevin Bowling }
415984d1616SKevin Bowling }
416984d1616SKevin Bowling
417984d1616SKevin Bowling if (status == E1000_SUCCESS) {
418*ddfec1fbSKevin Bowling invm_ver->invm_major = (nvm_version & E1000_INVM_MAJOR_MASK)
419984d1616SKevin Bowling >> E1000_INVM_MAJOR_SHIFT;
420*ddfec1fbSKevin Bowling invm_ver->invm_minor = nvm_version & E1000_INVM_MINOR_MASK;
421984d1616SKevin Bowling }
422984d1616SKevin Bowling /* Read Image Type */
423984d1616SKevin Bowling for (i = 1; i < invm_blocks; i++) {
424984d1616SKevin Bowling record = &buffer[invm_blocks - i];
425984d1616SKevin Bowling next_record = &buffer[invm_blocks - i + 1];
426984d1616SKevin Bowling
427984d1616SKevin Bowling /* Check if we have image type in first location used */
428984d1616SKevin Bowling if ((i == 1) && ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) {
429984d1616SKevin Bowling invm_ver->invm_img_type = 0;
430984d1616SKevin Bowling status = E1000_SUCCESS;
431984d1616SKevin Bowling break;
432984d1616SKevin Bowling }
433984d1616SKevin Bowling /* Check if we have image type in first location used */
434984d1616SKevin Bowling else if ((((*record & 0x3) == 0) &&
435984d1616SKevin Bowling ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) ||
436984d1616SKevin Bowling ((((*record & 0x3) != 0) && (i != 1)))) {
437984d1616SKevin Bowling invm_ver->invm_img_type =
438984d1616SKevin Bowling (*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23;
439984d1616SKevin Bowling status = E1000_SUCCESS;
440984d1616SKevin Bowling break;
441984d1616SKevin Bowling }
442984d1616SKevin Bowling }
443984d1616SKevin Bowling return status;
444984d1616SKevin Bowling }
445984d1616SKevin Bowling
446984d1616SKevin Bowling /**
447ab5d0362SJack F Vogel * e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum
448ab5d0362SJack F Vogel * @hw: pointer to the HW structure
449ab5d0362SJack F Vogel *
450ab5d0362SJack F Vogel * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
451ab5d0362SJack F Vogel * and then verifies that the sum of the EEPROM is equal to 0xBABA.
452ab5d0362SJack F Vogel **/
e1000_validate_nvm_checksum_i210(struct e1000_hw * hw)453ab5d0362SJack F Vogel s32 e1000_validate_nvm_checksum_i210(struct e1000_hw *hw)
454ab5d0362SJack F Vogel {
455ab5d0362SJack F Vogel s32 status = E1000_SUCCESS;
456ab5d0362SJack F Vogel s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *);
457ab5d0362SJack F Vogel
458ab5d0362SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_i210");
459ab5d0362SJack F Vogel
460ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
461ab5d0362SJack F Vogel
462ab5d0362SJack F Vogel /*
463ab5d0362SJack F Vogel * Replace the read function with semaphore grabbing with
464ab5d0362SJack F Vogel * the one that skips this for a while.
465ab5d0362SJack F Vogel * We have semaphore taken already here.
466ab5d0362SJack F Vogel */
467ab5d0362SJack F Vogel read_op_ptr = hw->nvm.ops.read;
468ab5d0362SJack F Vogel hw->nvm.ops.read = e1000_read_nvm_eerd;
469ab5d0362SJack F Vogel
470ab5d0362SJack F Vogel status = e1000_validate_nvm_checksum_generic(hw);
471ab5d0362SJack F Vogel
472ab5d0362SJack F Vogel /* Revert original read operation. */
473ab5d0362SJack F Vogel hw->nvm.ops.read = read_op_ptr;
474ab5d0362SJack F Vogel
475ab5d0362SJack F Vogel hw->nvm.ops.release(hw);
476ab5d0362SJack F Vogel } else {
477ab5d0362SJack F Vogel status = E1000_ERR_SWFW_SYNC;
478ab5d0362SJack F Vogel }
479ab5d0362SJack F Vogel
480ab5d0362SJack F Vogel return status;
481ab5d0362SJack F Vogel }
482ab5d0362SJack F Vogel
483ab5d0362SJack F Vogel
484ab5d0362SJack F Vogel /**
485ab5d0362SJack F Vogel * e1000_update_nvm_checksum_i210 - Update EEPROM checksum
486ab5d0362SJack F Vogel * @hw: pointer to the HW structure
487ab5d0362SJack F Vogel *
488ab5d0362SJack F Vogel * Updates the EEPROM checksum by reading/adding each word of the EEPROM
489ab5d0362SJack F Vogel * up to the checksum. Then calculates the EEPROM checksum and writes the
490ab5d0362SJack F Vogel * value to the EEPROM. Next commit EEPROM data onto the Flash.
491ab5d0362SJack F Vogel **/
e1000_update_nvm_checksum_i210(struct e1000_hw * hw)492ab5d0362SJack F Vogel s32 e1000_update_nvm_checksum_i210(struct e1000_hw *hw)
493ab5d0362SJack F Vogel {
4948cc64f1eSJack F Vogel s32 ret_val;
495ab5d0362SJack F Vogel u16 checksum = 0;
496ab5d0362SJack F Vogel u16 i, nvm_data;
497ab5d0362SJack F Vogel
498ab5d0362SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_i210");
499ab5d0362SJack F Vogel
500ab5d0362SJack F Vogel /*
501ab5d0362SJack F Vogel * Read the first word from the EEPROM. If this times out or fails, do
502ab5d0362SJack F Vogel * not continue or we could be in for a very long wait while every
503ab5d0362SJack F Vogel * EEPROM read fails
504ab5d0362SJack F Vogel */
505ab5d0362SJack F Vogel ret_val = e1000_read_nvm_eerd(hw, 0, 1, &nvm_data);
506ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) {
507ab5d0362SJack F Vogel DEBUGOUT("EEPROM read failed\n");
508ab5d0362SJack F Vogel goto out;
509ab5d0362SJack F Vogel }
510ab5d0362SJack F Vogel
511ab5d0362SJack F Vogel if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
512ab5d0362SJack F Vogel /*
513ab5d0362SJack F Vogel * Do not use hw->nvm.ops.write, hw->nvm.ops.read
514ab5d0362SJack F Vogel * because we do not want to take the synchronization
515ab5d0362SJack F Vogel * semaphores twice here.
516ab5d0362SJack F Vogel */
517ab5d0362SJack F Vogel
518ab5d0362SJack F Vogel for (i = 0; i < NVM_CHECKSUM_REG; i++) {
519ab5d0362SJack F Vogel ret_val = e1000_read_nvm_eerd(hw, i, 1, &nvm_data);
520ab5d0362SJack F Vogel if (ret_val) {
521ab5d0362SJack F Vogel hw->nvm.ops.release(hw);
522ab5d0362SJack F Vogel DEBUGOUT("NVM Read Error while updating checksum.\n");
523ab5d0362SJack F Vogel goto out;
524ab5d0362SJack F Vogel }
525ab5d0362SJack F Vogel checksum += nvm_data;
526ab5d0362SJack F Vogel }
527ab5d0362SJack F Vogel checksum = (u16) NVM_SUM - checksum;
528ab5d0362SJack F Vogel ret_val = e1000_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
529ab5d0362SJack F Vogel &checksum);
530ab5d0362SJack F Vogel if (ret_val != E1000_SUCCESS) {
531ab5d0362SJack F Vogel hw->nvm.ops.release(hw);
532ab5d0362SJack F Vogel DEBUGOUT("NVM Write Error while updating checksum.\n");
533ab5d0362SJack F Vogel goto out;
534ab5d0362SJack F Vogel }
535ab5d0362SJack F Vogel
536ab5d0362SJack F Vogel hw->nvm.ops.release(hw);
537ab5d0362SJack F Vogel
538ab5d0362SJack F Vogel ret_val = e1000_update_flash_i210(hw);
539ab5d0362SJack F Vogel } else {
540ab5d0362SJack F Vogel ret_val = E1000_ERR_SWFW_SYNC;
541ab5d0362SJack F Vogel }
542ab5d0362SJack F Vogel out:
543ab5d0362SJack F Vogel return ret_val;
544ab5d0362SJack F Vogel }
545ab5d0362SJack F Vogel
546ab5d0362SJack F Vogel /**
5477609433eSJack F Vogel * e1000_get_flash_presence_i210 - Check if flash device is detected.
5487609433eSJack F Vogel * @hw: pointer to the HW structure
5497609433eSJack F Vogel *
5507609433eSJack F Vogel **/
e1000_get_flash_presence_i210(struct e1000_hw * hw)5517609433eSJack F Vogel bool e1000_get_flash_presence_i210(struct e1000_hw *hw)
5527609433eSJack F Vogel {
5537609433eSJack F Vogel u32 eec = 0;
5541bbdc25fSKevin Bowling bool ret_val = false;
5557609433eSJack F Vogel
5567609433eSJack F Vogel DEBUGFUNC("e1000_get_flash_presence_i210");
5577609433eSJack F Vogel
5587609433eSJack F Vogel eec = E1000_READ_REG(hw, E1000_EECD);
5597609433eSJack F Vogel
5607609433eSJack F Vogel if (eec & E1000_EECD_FLASH_DETECTED_I210)
5611bbdc25fSKevin Bowling ret_val = true;
5627609433eSJack F Vogel
5637609433eSJack F Vogel return ret_val;
5647609433eSJack F Vogel }
5657609433eSJack F Vogel
5667609433eSJack F Vogel /**
567ab5d0362SJack F Vogel * e1000_update_flash_i210 - Commit EEPROM to the flash
568ab5d0362SJack F Vogel * @hw: pointer to the HW structure
569ab5d0362SJack F Vogel *
570ab5d0362SJack F Vogel **/
e1000_update_flash_i210(struct e1000_hw * hw)571ab5d0362SJack F Vogel s32 e1000_update_flash_i210(struct e1000_hw *hw)
572ab5d0362SJack F Vogel {
5738cc64f1eSJack F Vogel s32 ret_val;
574ab5d0362SJack F Vogel u32 flup;
575ab5d0362SJack F Vogel
576ab5d0362SJack F Vogel DEBUGFUNC("e1000_update_flash_i210");
577ab5d0362SJack F Vogel
578ab5d0362SJack F Vogel ret_val = e1000_pool_flash_update_done_i210(hw);
579ab5d0362SJack F Vogel if (ret_val == -E1000_ERR_NVM) {
580ab5d0362SJack F Vogel DEBUGOUT("Flash update time out\n");
581ab5d0362SJack F Vogel goto out;
582ab5d0362SJack F Vogel }
583ab5d0362SJack F Vogel
584ab5d0362SJack F Vogel flup = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD_I210;
585ab5d0362SJack F Vogel E1000_WRITE_REG(hw, E1000_EECD, flup);
586ab5d0362SJack F Vogel
587ab5d0362SJack F Vogel ret_val = e1000_pool_flash_update_done_i210(hw);
588ab5d0362SJack F Vogel if (ret_val == E1000_SUCCESS)
589ab5d0362SJack F Vogel DEBUGOUT("Flash update complete\n");
590ab5d0362SJack F Vogel else
591ab5d0362SJack F Vogel DEBUGOUT("Flash update time out\n");
592ab5d0362SJack F Vogel
593ab5d0362SJack F Vogel out:
594ab5d0362SJack F Vogel return ret_val;
595ab5d0362SJack F Vogel }
596ab5d0362SJack F Vogel
597ab5d0362SJack F Vogel /**
598ab5d0362SJack F Vogel * e1000_pool_flash_update_done_i210 - Pool FLUDONE status.
599ab5d0362SJack F Vogel * @hw: pointer to the HW structure
600ab5d0362SJack F Vogel *
601ab5d0362SJack F Vogel **/
e1000_pool_flash_update_done_i210(struct e1000_hw * hw)602ab5d0362SJack F Vogel s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw)
603ab5d0362SJack F Vogel {
604ab5d0362SJack F Vogel s32 ret_val = -E1000_ERR_NVM;
605ab5d0362SJack F Vogel u32 i, reg;
606ab5d0362SJack F Vogel
607ab5d0362SJack F Vogel DEBUGFUNC("e1000_pool_flash_update_done_i210");
608ab5d0362SJack F Vogel
609ab5d0362SJack F Vogel for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) {
610ab5d0362SJack F Vogel reg = E1000_READ_REG(hw, E1000_EECD);
611ab5d0362SJack F Vogel if (reg & E1000_EECD_FLUDONE_I210) {
612ab5d0362SJack F Vogel ret_val = E1000_SUCCESS;
613ab5d0362SJack F Vogel break;
614ab5d0362SJack F Vogel }
615ab5d0362SJack F Vogel usec_delay(5);
616ab5d0362SJack F Vogel }
617ab5d0362SJack F Vogel
618ab5d0362SJack F Vogel return ret_val;
619ab5d0362SJack F Vogel }
620ab5d0362SJack F Vogel
621ab5d0362SJack F Vogel /**
622ab5d0362SJack F Vogel * e1000_init_nvm_params_i210 - Initialize i210 NVM function pointers
623ab5d0362SJack F Vogel * @hw: pointer to the HW structure
624ab5d0362SJack F Vogel *
6257609433eSJack F Vogel * Initialize the i210/i211 NVM parameters and function pointers.
626ab5d0362SJack F Vogel **/
e1000_init_nvm_params_i210(struct e1000_hw * hw)627ab5d0362SJack F Vogel static s32 e1000_init_nvm_params_i210(struct e1000_hw *hw)
628ab5d0362SJack F Vogel {
6298cc64f1eSJack F Vogel s32 ret_val;
630ab5d0362SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
631ab5d0362SJack F Vogel
632ab5d0362SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_i210");
633ab5d0362SJack F Vogel
634ab5d0362SJack F Vogel ret_val = e1000_init_nvm_params_82575(hw);
635ab5d0362SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_i210;
636ab5d0362SJack F Vogel nvm->ops.release = e1000_release_nvm_i210;
6377609433eSJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_i210;
6387609433eSJack F Vogel if (e1000_get_flash_presence_i210(hw)) {
6397609433eSJack F Vogel hw->nvm.type = e1000_nvm_flash_hw;
640ab5d0362SJack F Vogel nvm->ops.read = e1000_read_nvm_srrd_i210;
641ab5d0362SJack F Vogel nvm->ops.write = e1000_write_nvm_srwr_i210;
642ab5d0362SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_i210;
643ab5d0362SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_i210;
6447609433eSJack F Vogel } else {
6457609433eSJack F Vogel hw->nvm.type = e1000_nvm_invm;
6467609433eSJack F Vogel nvm->ops.read = e1000_read_invm_i210;
647ab5d0362SJack F Vogel nvm->ops.write = e1000_null_write_nvm;
648ab5d0362SJack F Vogel nvm->ops.validate = e1000_null_ops_generic;
649ab5d0362SJack F Vogel nvm->ops.update = e1000_null_ops_generic;
6507609433eSJack F Vogel }
6517609433eSJack F Vogel return ret_val;
652ab5d0362SJack F Vogel }
653ab5d0362SJack F Vogel
654ab5d0362SJack F Vogel /**
655ab5d0362SJack F Vogel * e1000_init_function_pointers_i210 - Init func ptrs.
656ab5d0362SJack F Vogel * @hw: pointer to the HW structure
657ab5d0362SJack F Vogel *
658ab5d0362SJack F Vogel * Called to initialize all function pointers and parameters.
659ab5d0362SJack F Vogel **/
e1000_init_function_pointers_i210(struct e1000_hw * hw)660ab5d0362SJack F Vogel void e1000_init_function_pointers_i210(struct e1000_hw *hw)
661ab5d0362SJack F Vogel {
662ab5d0362SJack F Vogel e1000_init_function_pointers_82575(hw);
663ab5d0362SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_i210;
664ab5d0362SJack F Vogel }
665ab5d0362SJack F Vogel
666ab5d0362SJack F Vogel /**
667ab5d0362SJack F Vogel * e1000_valid_led_default_i210 - Verify a valid default LED config
668ab5d0362SJack F Vogel * @hw: pointer to the HW structure
669ab5d0362SJack F Vogel * @data: pointer to the NVM (EEPROM)
670ab5d0362SJack F Vogel *
671ab5d0362SJack F Vogel * Read the EEPROM for the current default LED configuration. If the
672ab5d0362SJack F Vogel * LED configuration is not valid, set to a valid LED configuration.
673ab5d0362SJack F Vogel **/
e1000_valid_led_default_i210(struct e1000_hw * hw,u16 * data)674ab5d0362SJack F Vogel static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
675ab5d0362SJack F Vogel {
676ab5d0362SJack F Vogel s32 ret_val;
677ab5d0362SJack F Vogel
678ab5d0362SJack F Vogel DEBUGFUNC("e1000_valid_led_default_i210");
679ab5d0362SJack F Vogel
680ab5d0362SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
681ab5d0362SJack F Vogel if (ret_val) {
682ab5d0362SJack F Vogel DEBUGOUT("NVM Read Error\n");
683ab5d0362SJack F Vogel goto out;
684ab5d0362SJack F Vogel }
685ab5d0362SJack F Vogel
686ab5d0362SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
687ab5d0362SJack F Vogel switch (hw->phy.media_type) {
688ab5d0362SJack F Vogel case e1000_media_type_internal_serdes:
689ab5d0362SJack F Vogel *data = ID_LED_DEFAULT_I210_SERDES;
690ab5d0362SJack F Vogel break;
691ab5d0362SJack F Vogel case e1000_media_type_copper:
692ab5d0362SJack F Vogel default:
693ab5d0362SJack F Vogel *data = ID_LED_DEFAULT_I210;
694ab5d0362SJack F Vogel break;
695ab5d0362SJack F Vogel }
696ab5d0362SJack F Vogel }
697ab5d0362SJack F Vogel out:
698ab5d0362SJack F Vogel return ret_val;
699ab5d0362SJack F Vogel }
7007609433eSJack F Vogel
7017609433eSJack F Vogel /**
7028cc64f1eSJack F Vogel * e1000_pll_workaround_i210
7038cc64f1eSJack F Vogel * @hw: pointer to the HW structure
7048cc64f1eSJack F Vogel *
7058cc64f1eSJack F Vogel * Works around an errata in the PLL circuit where it occasionally
7068cc64f1eSJack F Vogel * provides the wrong clock frequency after power up.
7078cc64f1eSJack F Vogel **/
e1000_pll_workaround_i210(struct e1000_hw * hw)7088cc64f1eSJack F Vogel static s32 e1000_pll_workaround_i210(struct e1000_hw *hw)
7098cc64f1eSJack F Vogel {
7108cc64f1eSJack F Vogel s32 ret_val;
7118cc64f1eSJack F Vogel u32 wuc, mdicnfg, ctrl, ctrl_ext, reg_val;
7128cc64f1eSJack F Vogel u16 nvm_word, phy_word, pci_word, tmp_nvm;
7138cc64f1eSJack F Vogel int i;
7148cc64f1eSJack F Vogel
7151883a6ffSGuinan Sun /* Get PHY semaphore */
7161883a6ffSGuinan Sun hw->phy.ops.acquire(hw);
7178cc64f1eSJack F Vogel /* Get and set needed register values */
7188cc64f1eSJack F Vogel wuc = E1000_READ_REG(hw, E1000_WUC);
7198cc64f1eSJack F Vogel mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG);
7208cc64f1eSJack F Vogel reg_val = mdicnfg & ~E1000_MDICNFG_EXT_MDIO;
7218cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_MDICNFG, reg_val);
7228cc64f1eSJack F Vogel
7238cc64f1eSJack F Vogel /* Get data from NVM, or set default */
7248cc64f1eSJack F Vogel ret_val = e1000_read_invm_word_i210(hw, E1000_INVM_AUTOLOAD,
7258cc64f1eSJack F Vogel &nvm_word);
7268cc64f1eSJack F Vogel if (ret_val != E1000_SUCCESS)
7278cc64f1eSJack F Vogel nvm_word = E1000_INVM_DEFAULT_AL;
7288cc64f1eSJack F Vogel tmp_nvm = nvm_word | E1000_INVM_PLL_WO_VAL;
729984d1616SKevin Bowling phy_word = E1000_PHY_PLL_UNCONF;
7308cc64f1eSJack F Vogel for (i = 0; i < E1000_MAX_PLL_TRIES; i++) {
7318cc64f1eSJack F Vogel /* check current state directly from internal PHY */
7321883a6ffSGuinan Sun e1000_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, 0xFC);
7331883a6ffSGuinan Sun usec_delay(20);
7341883a6ffSGuinan Sun e1000_read_phy_reg_mdic(hw, E1000_PHY_PLL_FREQ_REG, &phy_word);
7351883a6ffSGuinan Sun usec_delay(20);
7361883a6ffSGuinan Sun e1000_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, 0);
7378cc64f1eSJack F Vogel if ((phy_word & E1000_PHY_PLL_UNCONF)
7388cc64f1eSJack F Vogel != E1000_PHY_PLL_UNCONF) {
7398cc64f1eSJack F Vogel ret_val = E1000_SUCCESS;
7408cc64f1eSJack F Vogel break;
7418cc64f1eSJack F Vogel } else {
7428cc64f1eSJack F Vogel ret_val = -E1000_ERR_PHY;
7438cc64f1eSJack F Vogel }
7448cc64f1eSJack F Vogel /* directly reset the internal PHY */
7458cc64f1eSJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL);
7468cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl|E1000_CTRL_PHY_RST);
7478cc64f1eSJack F Vogel
7488cc64f1eSJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
7498cc64f1eSJack F Vogel ctrl_ext |= (E1000_CTRL_EXT_PHYPDEN | E1000_CTRL_EXT_SDLPE);
7508cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
7518cc64f1eSJack F Vogel
7528cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_WUC, 0);
7538cc64f1eSJack F Vogel reg_val = (E1000_INVM_AUTOLOAD << 4) | (tmp_nvm << 16);
7548cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_EEARBC_I210, reg_val);
7558cc64f1eSJack F Vogel
7568cc64f1eSJack F Vogel e1000_read_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
7578cc64f1eSJack F Vogel pci_word |= E1000_PCI_PMCSR_D3;
7588cc64f1eSJack F Vogel e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
7598cc64f1eSJack F Vogel msec_delay(1);
7608cc64f1eSJack F Vogel pci_word &= ~E1000_PCI_PMCSR_D3;
7618cc64f1eSJack F Vogel e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
7628cc64f1eSJack F Vogel reg_val = (E1000_INVM_AUTOLOAD << 4) | (nvm_word << 16);
7638cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_EEARBC_I210, reg_val);
7648cc64f1eSJack F Vogel
7658cc64f1eSJack F Vogel /* restore WUC register */
7668cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_WUC, wuc);
7678cc64f1eSJack F Vogel }
7688cc64f1eSJack F Vogel /* restore MDICNFG setting */
7698cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
7701883a6ffSGuinan Sun /* Release PHY semaphore */
7711883a6ffSGuinan Sun hw->phy.ops.release(hw);
7728cc64f1eSJack F Vogel return ret_val;
7738cc64f1eSJack F Vogel }
7748cc64f1eSJack F Vogel
7758cc64f1eSJack F Vogel /**
776c80429ceSEric Joyner * e1000_get_cfg_done_i210 - Read config done bit
777c80429ceSEric Joyner * @hw: pointer to the HW structure
778c80429ceSEric Joyner *
779c80429ceSEric Joyner * Read the management control register for the config done bit for
780c80429ceSEric Joyner * completion status. NOTE: silicon which is EEPROM-less will fail trying
781c80429ceSEric Joyner * to read the config done bit, so an error is *ONLY* logged and returns
782c80429ceSEric Joyner * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
783c80429ceSEric Joyner * would not be able to be reset or change link.
784c80429ceSEric Joyner **/
e1000_get_cfg_done_i210(struct e1000_hw * hw)785c80429ceSEric Joyner static s32 e1000_get_cfg_done_i210(struct e1000_hw *hw)
786c80429ceSEric Joyner {
787c80429ceSEric Joyner s32 timeout = PHY_CFG_TIMEOUT;
788c80429ceSEric Joyner u32 mask = E1000_NVM_CFG_DONE_PORT_0;
789c80429ceSEric Joyner
790c80429ceSEric Joyner DEBUGFUNC("e1000_get_cfg_done_i210");
791c80429ceSEric Joyner
792c80429ceSEric Joyner while (timeout) {
793c80429ceSEric Joyner if (E1000_READ_REG(hw, E1000_EEMNGCTL_I210) & mask)
794c80429ceSEric Joyner break;
795c80429ceSEric Joyner msec_delay(1);
796c80429ceSEric Joyner timeout--;
797c80429ceSEric Joyner }
798c80429ceSEric Joyner if (!timeout)
799c80429ceSEric Joyner DEBUGOUT("MNG configuration cycle has not completed.\n");
800c80429ceSEric Joyner
801c80429ceSEric Joyner return E1000_SUCCESS;
802c80429ceSEric Joyner }
803c80429ceSEric Joyner
804c80429ceSEric Joyner /**
8058cc64f1eSJack F Vogel * e1000_init_hw_i210 - Init hw for I210/I211
8068cc64f1eSJack F Vogel * @hw: pointer to the HW structure
8078cc64f1eSJack F Vogel *
8088cc64f1eSJack F Vogel * Called to initialize hw for i210 hw family.
8098cc64f1eSJack F Vogel **/
e1000_init_hw_i210(struct e1000_hw * hw)8108cc64f1eSJack F Vogel s32 e1000_init_hw_i210(struct e1000_hw *hw)
8118cc64f1eSJack F Vogel {
81251569bd7SEric Joyner struct e1000_mac_info *mac = &hw->mac;
8138cc64f1eSJack F Vogel s32 ret_val;
8148cc64f1eSJack F Vogel
8158cc64f1eSJack F Vogel DEBUGFUNC("e1000_init_hw_i210");
8168cc64f1eSJack F Vogel if ((hw->mac.type >= e1000_i210) &&
8178cc64f1eSJack F Vogel !(e1000_get_flash_presence_i210(hw))) {
8188cc64f1eSJack F Vogel ret_val = e1000_pll_workaround_i210(hw);
8198cc64f1eSJack F Vogel if (ret_val != E1000_SUCCESS)
8208cc64f1eSJack F Vogel return ret_val;
8218cc64f1eSJack F Vogel }
822c80429ceSEric Joyner hw->phy.ops.get_cfg_done = e1000_get_cfg_done_i210;
82351569bd7SEric Joyner
82451569bd7SEric Joyner /* Initialize identification LED */
82551569bd7SEric Joyner mac->ops.id_led_init(hw);
82651569bd7SEric Joyner
8276b9d35faSGuinan Sun ret_val = e1000_init_hw_base(hw);
8288cc64f1eSJack F Vogel return ret_val;
8298cc64f1eSJack F Vogel }
830