xref: /freebsd/sys/dev/e1000/e1000_i210.c (revision ddfec1fb6814088abc5805f45c4a18c5731d51b9)
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