xref: /illumos-gate/usr/src/uts/common/io/igc/core/igc_nvm.c (revision 6bbbd442)
1*6bbbd442SRobert Mustacchi /*-
2*6bbbd442SRobert Mustacchi  * Copyright 2021 Intel Corp
3*6bbbd442SRobert Mustacchi  * Copyright 2021 Rubicon Communications, LLC (Netgate)
4*6bbbd442SRobert Mustacchi  * SPDX-License-Identifier: BSD-3-Clause
5*6bbbd442SRobert Mustacchi  */
6*6bbbd442SRobert Mustacchi 
7*6bbbd442SRobert Mustacchi #include "igc_api.h"
8*6bbbd442SRobert Mustacchi 
9*6bbbd442SRobert Mustacchi static void igc_reload_nvm_generic(struct igc_hw *hw);
10*6bbbd442SRobert Mustacchi 
11*6bbbd442SRobert Mustacchi /**
12*6bbbd442SRobert Mustacchi  *  igc_init_nvm_ops_generic - Initialize NVM function pointers
13*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
14*6bbbd442SRobert Mustacchi  *
15*6bbbd442SRobert Mustacchi  *  Setups up the function pointers to no-op functions
16*6bbbd442SRobert Mustacchi  **/
igc_init_nvm_ops_generic(struct igc_hw * hw)17*6bbbd442SRobert Mustacchi void igc_init_nvm_ops_generic(struct igc_hw *hw)
18*6bbbd442SRobert Mustacchi {
19*6bbbd442SRobert Mustacchi 	struct igc_nvm_info *nvm = &hw->nvm;
20*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_init_nvm_ops_generic");
21*6bbbd442SRobert Mustacchi 
22*6bbbd442SRobert Mustacchi 	/* Initialize function pointers */
23*6bbbd442SRobert Mustacchi 	nvm->ops.init_params = igc_null_ops_generic;
24*6bbbd442SRobert Mustacchi 	nvm->ops.acquire = igc_null_ops_generic;
25*6bbbd442SRobert Mustacchi 	nvm->ops.read = igc_null_read_nvm;
26*6bbbd442SRobert Mustacchi 	nvm->ops.release = igc_null_nvm_generic;
27*6bbbd442SRobert Mustacchi 	nvm->ops.reload = igc_reload_nvm_generic;
28*6bbbd442SRobert Mustacchi 	nvm->ops.update = igc_null_ops_generic;
29*6bbbd442SRobert Mustacchi 	nvm->ops.validate = igc_null_ops_generic;
30*6bbbd442SRobert Mustacchi 	nvm->ops.write = igc_null_write_nvm;
31*6bbbd442SRobert Mustacchi }
32*6bbbd442SRobert Mustacchi 
33*6bbbd442SRobert Mustacchi /**
34*6bbbd442SRobert Mustacchi  *  igc_null_nvm_read - No-op function, return 0
35*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
36*6bbbd442SRobert Mustacchi  *  @a: dummy variable
37*6bbbd442SRobert Mustacchi  *  @b: dummy variable
38*6bbbd442SRobert Mustacchi  *  @c: dummy variable
39*6bbbd442SRobert Mustacchi  **/
igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG * hw,u16 IGC_UNUSEDARG a,u16 IGC_UNUSEDARG b,u16 IGC_UNUSEDARG * c)40*6bbbd442SRobert Mustacchi s32 igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG *hw,
41*6bbbd442SRobert Mustacchi 			u16 IGC_UNUSEDARG a, u16 IGC_UNUSEDARG b,
42*6bbbd442SRobert Mustacchi 			u16 IGC_UNUSEDARG *c)
43*6bbbd442SRobert Mustacchi {
44*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_null_read_nvm");
45*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
46*6bbbd442SRobert Mustacchi }
47*6bbbd442SRobert Mustacchi 
48*6bbbd442SRobert Mustacchi /**
49*6bbbd442SRobert Mustacchi  *  igc_null_nvm_generic - No-op function, return void
50*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
51*6bbbd442SRobert Mustacchi  **/
igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG * hw)52*6bbbd442SRobert Mustacchi void igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG *hw)
53*6bbbd442SRobert Mustacchi {
54*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_null_nvm_generic");
55*6bbbd442SRobert Mustacchi 	return;
56*6bbbd442SRobert Mustacchi }
57*6bbbd442SRobert Mustacchi 
58*6bbbd442SRobert Mustacchi /**
59*6bbbd442SRobert Mustacchi  *  igc_null_write_nvm - No-op function, return 0
60*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
61*6bbbd442SRobert Mustacchi  *  @a: dummy variable
62*6bbbd442SRobert Mustacchi  *  @b: dummy variable
63*6bbbd442SRobert Mustacchi  *  @c: dummy variable
64*6bbbd442SRobert Mustacchi  **/
igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG * hw,u16 IGC_UNUSEDARG a,u16 IGC_UNUSEDARG b,u16 IGC_UNUSEDARG * c)65*6bbbd442SRobert Mustacchi s32 igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG *hw,
66*6bbbd442SRobert Mustacchi 			 u16 IGC_UNUSEDARG a, u16 IGC_UNUSEDARG b,
67*6bbbd442SRobert Mustacchi 			 u16 IGC_UNUSEDARG *c)
68*6bbbd442SRobert Mustacchi {
69*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_null_write_nvm");
70*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
71*6bbbd442SRobert Mustacchi }
72*6bbbd442SRobert Mustacchi 
73*6bbbd442SRobert Mustacchi /**
74*6bbbd442SRobert Mustacchi  *  igc_raise_eec_clk - Raise EEPROM clock
75*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
76*6bbbd442SRobert Mustacchi  *  @eecd: pointer to the EEPROM
77*6bbbd442SRobert Mustacchi  *
78*6bbbd442SRobert Mustacchi  *  Enable/Raise the EEPROM clock bit.
79*6bbbd442SRobert Mustacchi  **/
igc_raise_eec_clk(struct igc_hw * hw,u32 * eecd)80*6bbbd442SRobert Mustacchi static void igc_raise_eec_clk(struct igc_hw *hw, u32 *eecd)
81*6bbbd442SRobert Mustacchi {
82*6bbbd442SRobert Mustacchi 	*eecd = *eecd | IGC_EECD_SK;
83*6bbbd442SRobert Mustacchi 	IGC_WRITE_REG(hw, IGC_EECD, *eecd);
84*6bbbd442SRobert Mustacchi 	IGC_WRITE_FLUSH(hw);
85*6bbbd442SRobert Mustacchi 	usec_delay(hw->nvm.delay_usec);
86*6bbbd442SRobert Mustacchi }
87*6bbbd442SRobert Mustacchi 
88*6bbbd442SRobert Mustacchi /**
89*6bbbd442SRobert Mustacchi  *  igc_lower_eec_clk - Lower EEPROM clock
90*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
91*6bbbd442SRobert Mustacchi  *  @eecd: pointer to the EEPROM
92*6bbbd442SRobert Mustacchi  *
93*6bbbd442SRobert Mustacchi  *  Clear/Lower the EEPROM clock bit.
94*6bbbd442SRobert Mustacchi  **/
igc_lower_eec_clk(struct igc_hw * hw,u32 * eecd)95*6bbbd442SRobert Mustacchi static void igc_lower_eec_clk(struct igc_hw *hw, u32 *eecd)
96*6bbbd442SRobert Mustacchi {
97*6bbbd442SRobert Mustacchi 	*eecd = *eecd & ~IGC_EECD_SK;
98*6bbbd442SRobert Mustacchi 	IGC_WRITE_REG(hw, IGC_EECD, *eecd);
99*6bbbd442SRobert Mustacchi 	IGC_WRITE_FLUSH(hw);
100*6bbbd442SRobert Mustacchi 	usec_delay(hw->nvm.delay_usec);
101*6bbbd442SRobert Mustacchi }
102*6bbbd442SRobert Mustacchi 
103*6bbbd442SRobert Mustacchi /**
104*6bbbd442SRobert Mustacchi  *  igc_shift_out_eec_bits - Shift data bits our to the EEPROM
105*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
106*6bbbd442SRobert Mustacchi  *  @data: data to send to the EEPROM
107*6bbbd442SRobert Mustacchi  *  @count: number of bits to shift out
108*6bbbd442SRobert Mustacchi  *
109*6bbbd442SRobert Mustacchi  *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
110*6bbbd442SRobert Mustacchi  *  "data" parameter will be shifted out to the EEPROM one bit at a time.
111*6bbbd442SRobert Mustacchi  *  In order to do this, "data" must be broken down into bits.
112*6bbbd442SRobert Mustacchi  **/
igc_shift_out_eec_bits(struct igc_hw * hw,u16 data,u16 count)113*6bbbd442SRobert Mustacchi static void igc_shift_out_eec_bits(struct igc_hw *hw, u16 data, u16 count)
114*6bbbd442SRobert Mustacchi {
115*6bbbd442SRobert Mustacchi 	struct igc_nvm_info *nvm = &hw->nvm;
116*6bbbd442SRobert Mustacchi 	u32 eecd = IGC_READ_REG(hw, IGC_EECD);
117*6bbbd442SRobert Mustacchi 	u32 mask;
118*6bbbd442SRobert Mustacchi 
119*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_shift_out_eec_bits");
120*6bbbd442SRobert Mustacchi 
121*6bbbd442SRobert Mustacchi 	mask = 0x01 << (count - 1);
122*6bbbd442SRobert Mustacchi 	if (nvm->type == igc_nvm_eeprom_spi)
123*6bbbd442SRobert Mustacchi 		eecd |= IGC_EECD_DO;
124*6bbbd442SRobert Mustacchi 
125*6bbbd442SRobert Mustacchi 	do {
126*6bbbd442SRobert Mustacchi 		eecd &= ~IGC_EECD_DI;
127*6bbbd442SRobert Mustacchi 
128*6bbbd442SRobert Mustacchi 		if (data & mask)
129*6bbbd442SRobert Mustacchi 			eecd |= IGC_EECD_DI;
130*6bbbd442SRobert Mustacchi 
131*6bbbd442SRobert Mustacchi 		IGC_WRITE_REG(hw, IGC_EECD, eecd);
132*6bbbd442SRobert Mustacchi 		IGC_WRITE_FLUSH(hw);
133*6bbbd442SRobert Mustacchi 
134*6bbbd442SRobert Mustacchi 		usec_delay(nvm->delay_usec);
135*6bbbd442SRobert Mustacchi 
136*6bbbd442SRobert Mustacchi 		igc_raise_eec_clk(hw, &eecd);
137*6bbbd442SRobert Mustacchi 		igc_lower_eec_clk(hw, &eecd);
138*6bbbd442SRobert Mustacchi 
139*6bbbd442SRobert Mustacchi 		mask >>= 1;
140*6bbbd442SRobert Mustacchi 	} while (mask);
141*6bbbd442SRobert Mustacchi 
142*6bbbd442SRobert Mustacchi 	eecd &= ~IGC_EECD_DI;
143*6bbbd442SRobert Mustacchi 	IGC_WRITE_REG(hw, IGC_EECD, eecd);
144*6bbbd442SRobert Mustacchi }
145*6bbbd442SRobert Mustacchi 
146*6bbbd442SRobert Mustacchi /**
147*6bbbd442SRobert Mustacchi  *  igc_shift_in_eec_bits - Shift data bits in from the EEPROM
148*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
149*6bbbd442SRobert Mustacchi  *  @count: number of bits to shift in
150*6bbbd442SRobert Mustacchi  *
151*6bbbd442SRobert Mustacchi  *  In order to read a register from the EEPROM, we need to shift 'count' bits
152*6bbbd442SRobert Mustacchi  *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
153*6bbbd442SRobert Mustacchi  *  the EEPROM (setting the SK bit), and then reading the value of the data out
154*6bbbd442SRobert Mustacchi  *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
155*6bbbd442SRobert Mustacchi  *  always be clear.
156*6bbbd442SRobert Mustacchi  **/
igc_shift_in_eec_bits(struct igc_hw * hw,u16 count)157*6bbbd442SRobert Mustacchi static u16 igc_shift_in_eec_bits(struct igc_hw *hw, u16 count)
158*6bbbd442SRobert Mustacchi {
159*6bbbd442SRobert Mustacchi 	u32 eecd;
160*6bbbd442SRobert Mustacchi 	u32 i;
161*6bbbd442SRobert Mustacchi 	u16 data;
162*6bbbd442SRobert Mustacchi 
163*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_shift_in_eec_bits");
164*6bbbd442SRobert Mustacchi 
165*6bbbd442SRobert Mustacchi 	eecd = IGC_READ_REG(hw, IGC_EECD);
166*6bbbd442SRobert Mustacchi 
167*6bbbd442SRobert Mustacchi 	eecd &= ~(IGC_EECD_DO | IGC_EECD_DI);
168*6bbbd442SRobert Mustacchi 	data = 0;
169*6bbbd442SRobert Mustacchi 
170*6bbbd442SRobert Mustacchi 	for (i = 0; i < count; i++) {
171*6bbbd442SRobert Mustacchi 		data <<= 1;
172*6bbbd442SRobert Mustacchi 		igc_raise_eec_clk(hw, &eecd);
173*6bbbd442SRobert Mustacchi 
174*6bbbd442SRobert Mustacchi 		eecd = IGC_READ_REG(hw, IGC_EECD);
175*6bbbd442SRobert Mustacchi 
176*6bbbd442SRobert Mustacchi 		eecd &= ~IGC_EECD_DI;
177*6bbbd442SRobert Mustacchi 		if (eecd & IGC_EECD_DO)
178*6bbbd442SRobert Mustacchi 			data |= 1;
179*6bbbd442SRobert Mustacchi 
180*6bbbd442SRobert Mustacchi 		igc_lower_eec_clk(hw, &eecd);
181*6bbbd442SRobert Mustacchi 	}
182*6bbbd442SRobert Mustacchi 
183*6bbbd442SRobert Mustacchi 	return data;
184*6bbbd442SRobert Mustacchi }
185*6bbbd442SRobert Mustacchi 
186*6bbbd442SRobert Mustacchi /**
187*6bbbd442SRobert Mustacchi  *  igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion
188*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
189*6bbbd442SRobert Mustacchi  *  @ee_reg: EEPROM flag for polling
190*6bbbd442SRobert Mustacchi  *
191*6bbbd442SRobert Mustacchi  *  Polls the EEPROM status bit for either read or write completion based
192*6bbbd442SRobert Mustacchi  *  upon the value of 'ee_reg'.
193*6bbbd442SRobert Mustacchi  **/
igc_poll_eerd_eewr_done(struct igc_hw * hw,int ee_reg)194*6bbbd442SRobert Mustacchi s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
195*6bbbd442SRobert Mustacchi {
196*6bbbd442SRobert Mustacchi 	u32 attempts = 100000;
197*6bbbd442SRobert Mustacchi 	u32 i, reg = 0;
198*6bbbd442SRobert Mustacchi 
199*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_poll_eerd_eewr_done");
200*6bbbd442SRobert Mustacchi 
201*6bbbd442SRobert Mustacchi 	for (i = 0; i < attempts; i++) {
202*6bbbd442SRobert Mustacchi 		if (ee_reg == IGC_NVM_POLL_READ)
203*6bbbd442SRobert Mustacchi 			reg = IGC_READ_REG(hw, IGC_EERD);
204*6bbbd442SRobert Mustacchi 		else
205*6bbbd442SRobert Mustacchi 			reg = IGC_READ_REG(hw, IGC_EEWR);
206*6bbbd442SRobert Mustacchi 
207*6bbbd442SRobert Mustacchi 		if (reg & IGC_NVM_RW_REG_DONE)
208*6bbbd442SRobert Mustacchi 			return IGC_SUCCESS;
209*6bbbd442SRobert Mustacchi 
210*6bbbd442SRobert Mustacchi 		usec_delay(5);
211*6bbbd442SRobert Mustacchi 	}
212*6bbbd442SRobert Mustacchi 
213*6bbbd442SRobert Mustacchi 	return -IGC_ERR_NVM;
214*6bbbd442SRobert Mustacchi }
215*6bbbd442SRobert Mustacchi 
216*6bbbd442SRobert Mustacchi /**
217*6bbbd442SRobert Mustacchi  *  igc_acquire_nvm_generic - Generic request for access to EEPROM
218*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
219*6bbbd442SRobert Mustacchi  *
220*6bbbd442SRobert Mustacchi  *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
221*6bbbd442SRobert Mustacchi  *  Return successful if access grant bit set, else clear the request for
222*6bbbd442SRobert Mustacchi  *  EEPROM access and return -IGC_ERR_NVM (-1).
223*6bbbd442SRobert Mustacchi  **/
igc_acquire_nvm_generic(struct igc_hw * hw)224*6bbbd442SRobert Mustacchi s32 igc_acquire_nvm_generic(struct igc_hw *hw)
225*6bbbd442SRobert Mustacchi {
226*6bbbd442SRobert Mustacchi 	u32 eecd = IGC_READ_REG(hw, IGC_EECD);
227*6bbbd442SRobert Mustacchi 	s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
228*6bbbd442SRobert Mustacchi 
229*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_acquire_nvm_generic");
230*6bbbd442SRobert Mustacchi 
231*6bbbd442SRobert Mustacchi 	IGC_WRITE_REG(hw, IGC_EECD, eecd | IGC_EECD_REQ);
232*6bbbd442SRobert Mustacchi 	eecd = IGC_READ_REG(hw, IGC_EECD);
233*6bbbd442SRobert Mustacchi 
234*6bbbd442SRobert Mustacchi 	while (timeout) {
235*6bbbd442SRobert Mustacchi 		if (eecd & IGC_EECD_GNT)
236*6bbbd442SRobert Mustacchi 			break;
237*6bbbd442SRobert Mustacchi 		usec_delay(5);
238*6bbbd442SRobert Mustacchi 		eecd = IGC_READ_REG(hw, IGC_EECD);
239*6bbbd442SRobert Mustacchi 		timeout--;
240*6bbbd442SRobert Mustacchi 	}
241*6bbbd442SRobert Mustacchi 
242*6bbbd442SRobert Mustacchi 	if (!timeout) {
243*6bbbd442SRobert Mustacchi 		eecd &= ~IGC_EECD_REQ;
244*6bbbd442SRobert Mustacchi 		IGC_WRITE_REG(hw, IGC_EECD, eecd);
245*6bbbd442SRobert Mustacchi 		DEBUGOUT("Could not acquire NVM grant\n");
246*6bbbd442SRobert Mustacchi 		return -IGC_ERR_NVM;
247*6bbbd442SRobert Mustacchi 	}
248*6bbbd442SRobert Mustacchi 
249*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
250*6bbbd442SRobert Mustacchi }
251*6bbbd442SRobert Mustacchi 
252*6bbbd442SRobert Mustacchi /**
253*6bbbd442SRobert Mustacchi  *  igc_standby_nvm - Return EEPROM to standby state
254*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
255*6bbbd442SRobert Mustacchi  *
256*6bbbd442SRobert Mustacchi  *  Return the EEPROM to a standby state.
257*6bbbd442SRobert Mustacchi  **/
igc_standby_nvm(struct igc_hw * hw)258*6bbbd442SRobert Mustacchi static void igc_standby_nvm(struct igc_hw *hw)
259*6bbbd442SRobert Mustacchi {
260*6bbbd442SRobert Mustacchi 	struct igc_nvm_info *nvm = &hw->nvm;
261*6bbbd442SRobert Mustacchi 	u32 eecd = IGC_READ_REG(hw, IGC_EECD);
262*6bbbd442SRobert Mustacchi 
263*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_standby_nvm");
264*6bbbd442SRobert Mustacchi 
265*6bbbd442SRobert Mustacchi 	if (nvm->type == igc_nvm_eeprom_spi) {
266*6bbbd442SRobert Mustacchi 		/* Toggle CS to flush commands */
267*6bbbd442SRobert Mustacchi 		eecd |= IGC_EECD_CS;
268*6bbbd442SRobert Mustacchi 		IGC_WRITE_REG(hw, IGC_EECD, eecd);
269*6bbbd442SRobert Mustacchi 		IGC_WRITE_FLUSH(hw);
270*6bbbd442SRobert Mustacchi 		usec_delay(nvm->delay_usec);
271*6bbbd442SRobert Mustacchi 		eecd &= ~IGC_EECD_CS;
272*6bbbd442SRobert Mustacchi 		IGC_WRITE_REG(hw, IGC_EECD, eecd);
273*6bbbd442SRobert Mustacchi 		IGC_WRITE_FLUSH(hw);
274*6bbbd442SRobert Mustacchi 		usec_delay(nvm->delay_usec);
275*6bbbd442SRobert Mustacchi 	}
276*6bbbd442SRobert Mustacchi }
277*6bbbd442SRobert Mustacchi 
278*6bbbd442SRobert Mustacchi /**
279*6bbbd442SRobert Mustacchi  *  igc_stop_nvm - Terminate EEPROM command
280*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
281*6bbbd442SRobert Mustacchi  *
282*6bbbd442SRobert Mustacchi  *  Terminates the current command by inverting the EEPROM's chip select pin.
283*6bbbd442SRobert Mustacchi  **/
igc_stop_nvm(struct igc_hw * hw)284*6bbbd442SRobert Mustacchi static void igc_stop_nvm(struct igc_hw *hw)
285*6bbbd442SRobert Mustacchi {
286*6bbbd442SRobert Mustacchi 	u32 eecd;
287*6bbbd442SRobert Mustacchi 
288*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_stop_nvm");
289*6bbbd442SRobert Mustacchi 
290*6bbbd442SRobert Mustacchi 	eecd = IGC_READ_REG(hw, IGC_EECD);
291*6bbbd442SRobert Mustacchi 	if (hw->nvm.type == igc_nvm_eeprom_spi) {
292*6bbbd442SRobert Mustacchi 		/* Pull CS high */
293*6bbbd442SRobert Mustacchi 		eecd |= IGC_EECD_CS;
294*6bbbd442SRobert Mustacchi 		igc_lower_eec_clk(hw, &eecd);
295*6bbbd442SRobert Mustacchi 	}
296*6bbbd442SRobert Mustacchi }
297*6bbbd442SRobert Mustacchi 
298*6bbbd442SRobert Mustacchi /**
299*6bbbd442SRobert Mustacchi  *  igc_release_nvm_generic - Release exclusive access to EEPROM
300*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
301*6bbbd442SRobert Mustacchi  *
302*6bbbd442SRobert Mustacchi  *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
303*6bbbd442SRobert Mustacchi  **/
igc_release_nvm_generic(struct igc_hw * hw)304*6bbbd442SRobert Mustacchi void igc_release_nvm_generic(struct igc_hw *hw)
305*6bbbd442SRobert Mustacchi {
306*6bbbd442SRobert Mustacchi 	u32 eecd;
307*6bbbd442SRobert Mustacchi 
308*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_release_nvm_generic");
309*6bbbd442SRobert Mustacchi 
310*6bbbd442SRobert Mustacchi 	igc_stop_nvm(hw);
311*6bbbd442SRobert Mustacchi 
312*6bbbd442SRobert Mustacchi 	eecd = IGC_READ_REG(hw, IGC_EECD);
313*6bbbd442SRobert Mustacchi 	eecd &= ~IGC_EECD_REQ;
314*6bbbd442SRobert Mustacchi 	IGC_WRITE_REG(hw, IGC_EECD, eecd);
315*6bbbd442SRobert Mustacchi }
316*6bbbd442SRobert Mustacchi 
317*6bbbd442SRobert Mustacchi /**
318*6bbbd442SRobert Mustacchi  *  igc_ready_nvm_eeprom - Prepares EEPROM for read/write
319*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
320*6bbbd442SRobert Mustacchi  *
321*6bbbd442SRobert Mustacchi  *  Setups the EEPROM for reading and writing.
322*6bbbd442SRobert Mustacchi  **/
igc_ready_nvm_eeprom(struct igc_hw * hw)323*6bbbd442SRobert Mustacchi static s32 igc_ready_nvm_eeprom(struct igc_hw *hw)
324*6bbbd442SRobert Mustacchi {
325*6bbbd442SRobert Mustacchi 	struct igc_nvm_info *nvm = &hw->nvm;
326*6bbbd442SRobert Mustacchi 	u32 eecd = IGC_READ_REG(hw, IGC_EECD);
327*6bbbd442SRobert Mustacchi 	u8 spi_stat_reg;
328*6bbbd442SRobert Mustacchi 
329*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_ready_nvm_eeprom");
330*6bbbd442SRobert Mustacchi 
331*6bbbd442SRobert Mustacchi 	if (nvm->type == igc_nvm_eeprom_spi) {
332*6bbbd442SRobert Mustacchi 		u16 timeout = NVM_MAX_RETRY_SPI;
333*6bbbd442SRobert Mustacchi 
334*6bbbd442SRobert Mustacchi 		/* Clear SK and CS */
335*6bbbd442SRobert Mustacchi 		eecd &= ~(IGC_EECD_CS | IGC_EECD_SK);
336*6bbbd442SRobert Mustacchi 		IGC_WRITE_REG(hw, IGC_EECD, eecd);
337*6bbbd442SRobert Mustacchi 		IGC_WRITE_FLUSH(hw);
338*6bbbd442SRobert Mustacchi 		usec_delay(1);
339*6bbbd442SRobert Mustacchi 
340*6bbbd442SRobert Mustacchi 		/* Read "Status Register" repeatedly until the LSB is cleared.
341*6bbbd442SRobert Mustacchi 		 * The EEPROM will signal that the command has been completed
342*6bbbd442SRobert Mustacchi 		 * by clearing bit 0 of the internal status register.  If it's
343*6bbbd442SRobert Mustacchi 		 * not cleared within 'timeout', then error out.
344*6bbbd442SRobert Mustacchi 		 */
345*6bbbd442SRobert Mustacchi 		while (timeout) {
346*6bbbd442SRobert Mustacchi 			igc_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
347*6bbbd442SRobert Mustacchi 						 hw->nvm.opcode_bits);
348*6bbbd442SRobert Mustacchi 			spi_stat_reg = (u8)igc_shift_in_eec_bits(hw, 8);
349*6bbbd442SRobert Mustacchi 			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
350*6bbbd442SRobert Mustacchi 				break;
351*6bbbd442SRobert Mustacchi 
352*6bbbd442SRobert Mustacchi 			usec_delay(5);
353*6bbbd442SRobert Mustacchi 			igc_standby_nvm(hw);
354*6bbbd442SRobert Mustacchi 			timeout--;
355*6bbbd442SRobert Mustacchi 		}
356*6bbbd442SRobert Mustacchi 
357*6bbbd442SRobert Mustacchi 		if (!timeout) {
358*6bbbd442SRobert Mustacchi 			DEBUGOUT("SPI NVM Status error\n");
359*6bbbd442SRobert Mustacchi 			return -IGC_ERR_NVM;
360*6bbbd442SRobert Mustacchi 		}
361*6bbbd442SRobert Mustacchi 	}
362*6bbbd442SRobert Mustacchi 
363*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
364*6bbbd442SRobert Mustacchi }
365*6bbbd442SRobert Mustacchi 
366*6bbbd442SRobert Mustacchi /**
367*6bbbd442SRobert Mustacchi  *  igc_read_nvm_eerd - Reads EEPROM using EERD register
368*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
369*6bbbd442SRobert Mustacchi  *  @offset: offset of word in the EEPROM to read
370*6bbbd442SRobert Mustacchi  *  @words: number of words to read
371*6bbbd442SRobert Mustacchi  *  @data: word read from the EEPROM
372*6bbbd442SRobert Mustacchi  *
373*6bbbd442SRobert Mustacchi  *  Reads a 16 bit word from the EEPROM using the EERD register.
374*6bbbd442SRobert Mustacchi  **/
igc_read_nvm_eerd(struct igc_hw * hw,u16 offset,u16 words,u16 * data)375*6bbbd442SRobert Mustacchi s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
376*6bbbd442SRobert Mustacchi {
377*6bbbd442SRobert Mustacchi 	struct igc_nvm_info *nvm = &hw->nvm;
378*6bbbd442SRobert Mustacchi 	u32 i, eerd = 0;
379*6bbbd442SRobert Mustacchi 	s32 ret_val = IGC_SUCCESS;
380*6bbbd442SRobert Mustacchi 
381*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_read_nvm_eerd");
382*6bbbd442SRobert Mustacchi 
383*6bbbd442SRobert Mustacchi 	/* A check for invalid values:  offset too large, too many words,
384*6bbbd442SRobert Mustacchi 	 * too many words for the offset, and not enough words.
385*6bbbd442SRobert Mustacchi 	 */
386*6bbbd442SRobert Mustacchi 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
387*6bbbd442SRobert Mustacchi 	    (words == 0)) {
388*6bbbd442SRobert Mustacchi 		DEBUGOUT("nvm parameter(s) out of bounds\n");
389*6bbbd442SRobert Mustacchi 		return -IGC_ERR_NVM;
390*6bbbd442SRobert Mustacchi 	}
391*6bbbd442SRobert Mustacchi 
392*6bbbd442SRobert Mustacchi 	for (i = 0; i < words; i++) {
393*6bbbd442SRobert Mustacchi 		eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
394*6bbbd442SRobert Mustacchi 		       IGC_NVM_RW_REG_START;
395*6bbbd442SRobert Mustacchi 
396*6bbbd442SRobert Mustacchi 		IGC_WRITE_REG(hw, IGC_EERD, eerd);
397*6bbbd442SRobert Mustacchi 		ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
398*6bbbd442SRobert Mustacchi 		if (ret_val)
399*6bbbd442SRobert Mustacchi 			break;
400*6bbbd442SRobert Mustacchi 
401*6bbbd442SRobert Mustacchi 		data[i] = (IGC_READ_REG(hw, IGC_EERD) >>
402*6bbbd442SRobert Mustacchi 			   IGC_NVM_RW_REG_DATA);
403*6bbbd442SRobert Mustacchi 	}
404*6bbbd442SRobert Mustacchi 
405*6bbbd442SRobert Mustacchi 	if (ret_val)
406*6bbbd442SRobert Mustacchi 		DEBUGOUT1("NVM read error: %d\n", ret_val);
407*6bbbd442SRobert Mustacchi 
408*6bbbd442SRobert Mustacchi 	return ret_val;
409*6bbbd442SRobert Mustacchi }
410*6bbbd442SRobert Mustacchi 
411*6bbbd442SRobert Mustacchi /**
412*6bbbd442SRobert Mustacchi  *  igc_write_nvm_spi - Write to EEPROM using SPI
413*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
414*6bbbd442SRobert Mustacchi  *  @offset: offset within the EEPROM to be written to
415*6bbbd442SRobert Mustacchi  *  @words: number of words to write
416*6bbbd442SRobert Mustacchi  *  @data: 16 bit word(s) to be written to the EEPROM
417*6bbbd442SRobert Mustacchi  *
418*6bbbd442SRobert Mustacchi  *  Writes data to EEPROM at offset using SPI interface.
419*6bbbd442SRobert Mustacchi  *
420*6bbbd442SRobert Mustacchi  *  If igc_update_nvm_checksum is not called after this function , the
421*6bbbd442SRobert Mustacchi  *  EEPROM will most likely contain an invalid checksum.
422*6bbbd442SRobert Mustacchi  **/
igc_write_nvm_spi(struct igc_hw * hw,u16 offset,u16 words,u16 * data)423*6bbbd442SRobert Mustacchi s32 igc_write_nvm_spi(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
424*6bbbd442SRobert Mustacchi {
425*6bbbd442SRobert Mustacchi 	struct igc_nvm_info *nvm = &hw->nvm;
426*6bbbd442SRobert Mustacchi 	s32 ret_val = -IGC_ERR_NVM;
427*6bbbd442SRobert Mustacchi 	u16 widx = 0;
428*6bbbd442SRobert Mustacchi 
429*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_write_nvm_spi");
430*6bbbd442SRobert Mustacchi 
431*6bbbd442SRobert Mustacchi 	/* A check for invalid values:  offset too large, too many words,
432*6bbbd442SRobert Mustacchi 	 * and not enough words.
433*6bbbd442SRobert Mustacchi 	 */
434*6bbbd442SRobert Mustacchi 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
435*6bbbd442SRobert Mustacchi 	    (words == 0)) {
436*6bbbd442SRobert Mustacchi 		DEBUGOUT("nvm parameter(s) out of bounds\n");
437*6bbbd442SRobert Mustacchi 		return -IGC_ERR_NVM;
438*6bbbd442SRobert Mustacchi 	}
439*6bbbd442SRobert Mustacchi 
440*6bbbd442SRobert Mustacchi 	while (widx < words) {
441*6bbbd442SRobert Mustacchi 		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
442*6bbbd442SRobert Mustacchi 
443*6bbbd442SRobert Mustacchi 		ret_val = nvm->ops.acquire(hw);
444*6bbbd442SRobert Mustacchi 		if (ret_val)
445*6bbbd442SRobert Mustacchi 			return ret_val;
446*6bbbd442SRobert Mustacchi 
447*6bbbd442SRobert Mustacchi 		ret_val = igc_ready_nvm_eeprom(hw);
448*6bbbd442SRobert Mustacchi 		if (ret_val) {
449*6bbbd442SRobert Mustacchi 			nvm->ops.release(hw);
450*6bbbd442SRobert Mustacchi 			return ret_val;
451*6bbbd442SRobert Mustacchi 		}
452*6bbbd442SRobert Mustacchi 
453*6bbbd442SRobert Mustacchi 		igc_standby_nvm(hw);
454*6bbbd442SRobert Mustacchi 
455*6bbbd442SRobert Mustacchi 		/* Send the WRITE ENABLE command (8 bit opcode) */
456*6bbbd442SRobert Mustacchi 		igc_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
457*6bbbd442SRobert Mustacchi 					 nvm->opcode_bits);
458*6bbbd442SRobert Mustacchi 
459*6bbbd442SRobert Mustacchi 		igc_standby_nvm(hw);
460*6bbbd442SRobert Mustacchi 
461*6bbbd442SRobert Mustacchi 		/* Some SPI eeproms use the 8th address bit embedded in the
462*6bbbd442SRobert Mustacchi 		 * opcode
463*6bbbd442SRobert Mustacchi 		 */
464*6bbbd442SRobert Mustacchi 		if ((nvm->address_bits == 8) && (offset >= 128))
465*6bbbd442SRobert Mustacchi 			write_opcode |= NVM_A8_OPCODE_SPI;
466*6bbbd442SRobert Mustacchi 
467*6bbbd442SRobert Mustacchi 		/* Send the Write command (8-bit opcode + addr) */
468*6bbbd442SRobert Mustacchi 		igc_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
469*6bbbd442SRobert Mustacchi 		igc_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
470*6bbbd442SRobert Mustacchi 					 nvm->address_bits);
471*6bbbd442SRobert Mustacchi 
472*6bbbd442SRobert Mustacchi 		/* Loop to allow for up to whole page write of eeprom */
473*6bbbd442SRobert Mustacchi 		while (widx < words) {
474*6bbbd442SRobert Mustacchi 			u16 word_out = data[widx];
475*6bbbd442SRobert Mustacchi 			word_out = (word_out >> 8) | (word_out << 8);
476*6bbbd442SRobert Mustacchi 			igc_shift_out_eec_bits(hw, word_out, 16);
477*6bbbd442SRobert Mustacchi 			widx++;
478*6bbbd442SRobert Mustacchi 
479*6bbbd442SRobert Mustacchi 			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
480*6bbbd442SRobert Mustacchi 				igc_standby_nvm(hw);
481*6bbbd442SRobert Mustacchi 				break;
482*6bbbd442SRobert Mustacchi 			}
483*6bbbd442SRobert Mustacchi 		}
484*6bbbd442SRobert Mustacchi 		msec_delay(10);
485*6bbbd442SRobert Mustacchi 		nvm->ops.release(hw);
486*6bbbd442SRobert Mustacchi 	}
487*6bbbd442SRobert Mustacchi 
488*6bbbd442SRobert Mustacchi 	return ret_val;
489*6bbbd442SRobert Mustacchi }
490*6bbbd442SRobert Mustacchi 
491*6bbbd442SRobert Mustacchi /**
492*6bbbd442SRobert Mustacchi  *  igc_read_pba_string_generic - Read device part number
493*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
494*6bbbd442SRobert Mustacchi  *  @pba_num: pointer to device part number
495*6bbbd442SRobert Mustacchi  *  @pba_num_size: size of part number buffer
496*6bbbd442SRobert Mustacchi  *
497*6bbbd442SRobert Mustacchi  *  Reads the product board assembly (PBA) number from the EEPROM and stores
498*6bbbd442SRobert Mustacchi  *  the value in pba_num.
499*6bbbd442SRobert Mustacchi  **/
igc_read_pba_string_generic(struct igc_hw * hw,u8 * pba_num,u32 pba_num_size)500*6bbbd442SRobert Mustacchi s32 igc_read_pba_string_generic(struct igc_hw *hw, u8 *pba_num,
501*6bbbd442SRobert Mustacchi 				  u32 pba_num_size)
502*6bbbd442SRobert Mustacchi {
503*6bbbd442SRobert Mustacchi 	s32 ret_val;
504*6bbbd442SRobert Mustacchi 	u16 nvm_data;
505*6bbbd442SRobert Mustacchi 	u16 pba_ptr;
506*6bbbd442SRobert Mustacchi 	u16 offset;
507*6bbbd442SRobert Mustacchi 	u16 length;
508*6bbbd442SRobert Mustacchi 
509*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_read_pba_string_generic");
510*6bbbd442SRobert Mustacchi 
511*6bbbd442SRobert Mustacchi 	if (pba_num == NULL) {
512*6bbbd442SRobert Mustacchi 		DEBUGOUT("PBA string buffer was null\n");
513*6bbbd442SRobert Mustacchi 		return -IGC_ERR_INVALID_ARGUMENT;
514*6bbbd442SRobert Mustacchi 	}
515*6bbbd442SRobert Mustacchi 
516*6bbbd442SRobert Mustacchi 	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
517*6bbbd442SRobert Mustacchi 	if (ret_val) {
518*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM Read Error\n");
519*6bbbd442SRobert Mustacchi 		return ret_val;
520*6bbbd442SRobert Mustacchi 	}
521*6bbbd442SRobert Mustacchi 
522*6bbbd442SRobert Mustacchi 	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
523*6bbbd442SRobert Mustacchi 	if (ret_val) {
524*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM Read Error\n");
525*6bbbd442SRobert Mustacchi 		return ret_val;
526*6bbbd442SRobert Mustacchi 	}
527*6bbbd442SRobert Mustacchi 
528*6bbbd442SRobert Mustacchi 	/* if nvm_data is not ptr guard the PBA must be in legacy format which
529*6bbbd442SRobert Mustacchi 	 * means pba_ptr is actually our second data word for the PBA number
530*6bbbd442SRobert Mustacchi 	 * and we can decode it into an ascii string
531*6bbbd442SRobert Mustacchi 	 */
532*6bbbd442SRobert Mustacchi 	if (nvm_data != NVM_PBA_PTR_GUARD) {
533*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM PBA number is not stored as string\n");
534*6bbbd442SRobert Mustacchi 
535*6bbbd442SRobert Mustacchi 		/* make sure callers buffer is big enough to store the PBA */
536*6bbbd442SRobert Mustacchi 		if (pba_num_size < IGC_PBANUM_LENGTH) {
537*6bbbd442SRobert Mustacchi 			DEBUGOUT("PBA string buffer too small\n");
538*6bbbd442SRobert Mustacchi 			return IGC_ERR_NO_SPACE;
539*6bbbd442SRobert Mustacchi 		}
540*6bbbd442SRobert Mustacchi 
541*6bbbd442SRobert Mustacchi 		/* extract hex string from data and pba_ptr */
542*6bbbd442SRobert Mustacchi 		pba_num[0] = (nvm_data >> 12) & 0xF;
543*6bbbd442SRobert Mustacchi 		pba_num[1] = (nvm_data >> 8) & 0xF;
544*6bbbd442SRobert Mustacchi 		pba_num[2] = (nvm_data >> 4) & 0xF;
545*6bbbd442SRobert Mustacchi 		pba_num[3] = nvm_data & 0xF;
546*6bbbd442SRobert Mustacchi 		pba_num[4] = (pba_ptr >> 12) & 0xF;
547*6bbbd442SRobert Mustacchi 		pba_num[5] = (pba_ptr >> 8) & 0xF;
548*6bbbd442SRobert Mustacchi 		pba_num[6] = '-';
549*6bbbd442SRobert Mustacchi 		pba_num[7] = 0;
550*6bbbd442SRobert Mustacchi 		pba_num[8] = (pba_ptr >> 4) & 0xF;
551*6bbbd442SRobert Mustacchi 		pba_num[9] = pba_ptr & 0xF;
552*6bbbd442SRobert Mustacchi 
553*6bbbd442SRobert Mustacchi 		/* put a null character on the end of our string */
554*6bbbd442SRobert Mustacchi 		pba_num[10] = '\0';
555*6bbbd442SRobert Mustacchi 
556*6bbbd442SRobert Mustacchi 		/* switch all the data but the '-' to hex char */
557*6bbbd442SRobert Mustacchi 		for (offset = 0; offset < 10; offset++) {
558*6bbbd442SRobert Mustacchi 			if (pba_num[offset] < 0xA)
559*6bbbd442SRobert Mustacchi 				pba_num[offset] += '0';
560*6bbbd442SRobert Mustacchi 			else if (pba_num[offset] < 0x10)
561*6bbbd442SRobert Mustacchi 				pba_num[offset] += 'A' - 0xA;
562*6bbbd442SRobert Mustacchi 		}
563*6bbbd442SRobert Mustacchi 
564*6bbbd442SRobert Mustacchi 		return IGC_SUCCESS;
565*6bbbd442SRobert Mustacchi 	}
566*6bbbd442SRobert Mustacchi 
567*6bbbd442SRobert Mustacchi 	ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
568*6bbbd442SRobert Mustacchi 	if (ret_val) {
569*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM Read Error\n");
570*6bbbd442SRobert Mustacchi 		return ret_val;
571*6bbbd442SRobert Mustacchi 	}
572*6bbbd442SRobert Mustacchi 
573*6bbbd442SRobert Mustacchi 	if (length == 0xFFFF || length == 0) {
574*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM PBA number section invalid length\n");
575*6bbbd442SRobert Mustacchi 		return -IGC_ERR_NVM_PBA_SECTION;
576*6bbbd442SRobert Mustacchi 	}
577*6bbbd442SRobert Mustacchi 	/* check if pba_num buffer is big enough */
578*6bbbd442SRobert Mustacchi 	if (pba_num_size < (((u32)length * 2) - 1)) {
579*6bbbd442SRobert Mustacchi 		DEBUGOUT("PBA string buffer too small\n");
580*6bbbd442SRobert Mustacchi 		return -IGC_ERR_NO_SPACE;
581*6bbbd442SRobert Mustacchi 	}
582*6bbbd442SRobert Mustacchi 
583*6bbbd442SRobert Mustacchi 	/* trim pba length from start of string */
584*6bbbd442SRobert Mustacchi 	pba_ptr++;
585*6bbbd442SRobert Mustacchi 	length--;
586*6bbbd442SRobert Mustacchi 
587*6bbbd442SRobert Mustacchi 	for (offset = 0; offset < length; offset++) {
588*6bbbd442SRobert Mustacchi 		ret_val = hw->nvm.ops.read(hw, pba_ptr + offset, 1, &nvm_data);
589*6bbbd442SRobert Mustacchi 		if (ret_val) {
590*6bbbd442SRobert Mustacchi 			DEBUGOUT("NVM Read Error\n");
591*6bbbd442SRobert Mustacchi 			return ret_val;
592*6bbbd442SRobert Mustacchi 		}
593*6bbbd442SRobert Mustacchi 		pba_num[offset * 2] = (u8)(nvm_data >> 8);
594*6bbbd442SRobert Mustacchi 		pba_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF);
595*6bbbd442SRobert Mustacchi 	}
596*6bbbd442SRobert Mustacchi 	pba_num[offset * 2] = '\0';
597*6bbbd442SRobert Mustacchi 
598*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
599*6bbbd442SRobert Mustacchi }
600*6bbbd442SRobert Mustacchi 
601*6bbbd442SRobert Mustacchi 
602*6bbbd442SRobert Mustacchi 
603*6bbbd442SRobert Mustacchi 
604*6bbbd442SRobert Mustacchi 
605*6bbbd442SRobert Mustacchi /**
606*6bbbd442SRobert Mustacchi  *  igc_read_mac_addr_generic - Read device MAC address
607*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
608*6bbbd442SRobert Mustacchi  *
609*6bbbd442SRobert Mustacchi  *  Reads the device MAC address from the EEPROM and stores the value.
610*6bbbd442SRobert Mustacchi  *  Since devices with two ports use the same EEPROM, we increment the
611*6bbbd442SRobert Mustacchi  *  last bit in the MAC address for the second port.
612*6bbbd442SRobert Mustacchi  **/
igc_read_mac_addr_generic(struct igc_hw * hw)613*6bbbd442SRobert Mustacchi s32 igc_read_mac_addr_generic(struct igc_hw *hw)
614*6bbbd442SRobert Mustacchi {
615*6bbbd442SRobert Mustacchi 	u32 rar_high;
616*6bbbd442SRobert Mustacchi 	u32 rar_low;
617*6bbbd442SRobert Mustacchi 	u16 i;
618*6bbbd442SRobert Mustacchi 
619*6bbbd442SRobert Mustacchi 	rar_high = IGC_READ_REG(hw, IGC_RAH(0));
620*6bbbd442SRobert Mustacchi 	rar_low = IGC_READ_REG(hw, IGC_RAL(0));
621*6bbbd442SRobert Mustacchi 
622*6bbbd442SRobert Mustacchi 	for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)
623*6bbbd442SRobert Mustacchi 		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
624*6bbbd442SRobert Mustacchi 
625*6bbbd442SRobert Mustacchi 	for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)
626*6bbbd442SRobert Mustacchi 		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
627*6bbbd442SRobert Mustacchi 
628*6bbbd442SRobert Mustacchi 	for (i = 0; i < ETH_ADDR_LEN; i++)
629*6bbbd442SRobert Mustacchi 		hw->mac.addr[i] = hw->mac.perm_addr[i];
630*6bbbd442SRobert Mustacchi 
631*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
632*6bbbd442SRobert Mustacchi }
633*6bbbd442SRobert Mustacchi 
634*6bbbd442SRobert Mustacchi /**
635*6bbbd442SRobert Mustacchi  *  igc_validate_nvm_checksum_generic - Validate EEPROM checksum
636*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
637*6bbbd442SRobert Mustacchi  *
638*6bbbd442SRobert Mustacchi  *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
639*6bbbd442SRobert Mustacchi  *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
640*6bbbd442SRobert Mustacchi  **/
igc_validate_nvm_checksum_generic(struct igc_hw * hw)641*6bbbd442SRobert Mustacchi s32 igc_validate_nvm_checksum_generic(struct igc_hw *hw)
642*6bbbd442SRobert Mustacchi {
643*6bbbd442SRobert Mustacchi 	s32 ret_val;
644*6bbbd442SRobert Mustacchi 	u16 checksum = 0;
645*6bbbd442SRobert Mustacchi 	u16 i, nvm_data;
646*6bbbd442SRobert Mustacchi 
647*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_validate_nvm_checksum_generic");
648*6bbbd442SRobert Mustacchi 
649*6bbbd442SRobert Mustacchi 	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
650*6bbbd442SRobert Mustacchi 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
651*6bbbd442SRobert Mustacchi 		if (ret_val) {
652*6bbbd442SRobert Mustacchi 			DEBUGOUT("NVM Read Error\n");
653*6bbbd442SRobert Mustacchi 			return ret_val;
654*6bbbd442SRobert Mustacchi 		}
655*6bbbd442SRobert Mustacchi 		checksum += nvm_data;
656*6bbbd442SRobert Mustacchi 	}
657*6bbbd442SRobert Mustacchi 
658*6bbbd442SRobert Mustacchi 	if (checksum != (u16) NVM_SUM) {
659*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM Checksum Invalid\n");
660*6bbbd442SRobert Mustacchi 		return -IGC_ERR_NVM;
661*6bbbd442SRobert Mustacchi 	}
662*6bbbd442SRobert Mustacchi 
663*6bbbd442SRobert Mustacchi 	return IGC_SUCCESS;
664*6bbbd442SRobert Mustacchi }
665*6bbbd442SRobert Mustacchi 
666*6bbbd442SRobert Mustacchi /**
667*6bbbd442SRobert Mustacchi  *  igc_update_nvm_checksum_generic - Update EEPROM checksum
668*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
669*6bbbd442SRobert Mustacchi  *
670*6bbbd442SRobert Mustacchi  *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
671*6bbbd442SRobert Mustacchi  *  up to the checksum.  Then calculates the EEPROM checksum and writes the
672*6bbbd442SRobert Mustacchi  *  value to the EEPROM.
673*6bbbd442SRobert Mustacchi  **/
igc_update_nvm_checksum_generic(struct igc_hw * hw)674*6bbbd442SRobert Mustacchi s32 igc_update_nvm_checksum_generic(struct igc_hw *hw)
675*6bbbd442SRobert Mustacchi {
676*6bbbd442SRobert Mustacchi 	s32 ret_val;
677*6bbbd442SRobert Mustacchi 	u16 checksum = 0;
678*6bbbd442SRobert Mustacchi 	u16 i, nvm_data;
679*6bbbd442SRobert Mustacchi 
680*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_update_nvm_checksum");
681*6bbbd442SRobert Mustacchi 
682*6bbbd442SRobert Mustacchi 	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
683*6bbbd442SRobert Mustacchi 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
684*6bbbd442SRobert Mustacchi 		if (ret_val) {
685*6bbbd442SRobert Mustacchi 			DEBUGOUT("NVM Read Error while updating checksum.\n");
686*6bbbd442SRobert Mustacchi 			return ret_val;
687*6bbbd442SRobert Mustacchi 		}
688*6bbbd442SRobert Mustacchi 		checksum += nvm_data;
689*6bbbd442SRobert Mustacchi 	}
690*6bbbd442SRobert Mustacchi 	checksum = (u16) NVM_SUM - checksum;
691*6bbbd442SRobert Mustacchi 	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
692*6bbbd442SRobert Mustacchi 	if (ret_val)
693*6bbbd442SRobert Mustacchi 		DEBUGOUT("NVM Write Error while updating checksum.\n");
694*6bbbd442SRobert Mustacchi 
695*6bbbd442SRobert Mustacchi 	return ret_val;
696*6bbbd442SRobert Mustacchi }
697*6bbbd442SRobert Mustacchi 
698*6bbbd442SRobert Mustacchi /**
699*6bbbd442SRobert Mustacchi  *  igc_reload_nvm_generic - Reloads EEPROM
700*6bbbd442SRobert Mustacchi  *  @hw: pointer to the HW structure
701*6bbbd442SRobert Mustacchi  *
702*6bbbd442SRobert Mustacchi  *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
703*6bbbd442SRobert Mustacchi  *  extended control register.
704*6bbbd442SRobert Mustacchi  **/
igc_reload_nvm_generic(struct igc_hw * hw)705*6bbbd442SRobert Mustacchi static void igc_reload_nvm_generic(struct igc_hw *hw)
706*6bbbd442SRobert Mustacchi {
707*6bbbd442SRobert Mustacchi 	u32 ctrl_ext;
708*6bbbd442SRobert Mustacchi 
709*6bbbd442SRobert Mustacchi 	DEBUGFUNC("igc_reload_nvm_generic");
710*6bbbd442SRobert Mustacchi 
711*6bbbd442SRobert Mustacchi 	usec_delay(10);
712*6bbbd442SRobert Mustacchi 	ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
713*6bbbd442SRobert Mustacchi 	ctrl_ext |= IGC_CTRL_EXT_EE_RST;
714*6bbbd442SRobert Mustacchi 	IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext);
715*6bbbd442SRobert Mustacchi 	IGC_WRITE_FLUSH(hw);
716*6bbbd442SRobert Mustacchi }
717*6bbbd442SRobert Mustacchi 
718*6bbbd442SRobert Mustacchi 
719