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