xref: /linux/drivers/net/ethernet/intel/igc/igc_nvm.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
1*ab405612SSasha Neftin // SPDX-License-Identifier: GPL-2.0
2*ab405612SSasha Neftin /* Copyright (c)  2018 Intel Corporation */
3*ab405612SSasha Neftin 
4*ab405612SSasha Neftin #include "igc_mac.h"
5*ab405612SSasha Neftin #include "igc_nvm.h"
6*ab405612SSasha Neftin 
7*ab405612SSasha Neftin /**
8*ab405612SSasha Neftin  * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion
9*ab405612SSasha Neftin  * @hw: pointer to the HW structure
10*ab405612SSasha Neftin  * @ee_reg: EEPROM flag for polling
11*ab405612SSasha Neftin  *
12*ab405612SSasha Neftin  * Polls the EEPROM status bit for either read or write completion based
13*ab405612SSasha Neftin  * upon the value of 'ee_reg'.
14*ab405612SSasha Neftin  */
igc_poll_eerd_eewr_done(struct igc_hw * hw,int ee_reg)15*ab405612SSasha Neftin static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
16*ab405612SSasha Neftin {
17*ab405612SSasha Neftin 	s32 ret_val = -IGC_ERR_NVM;
18*ab405612SSasha Neftin 	u32 attempts = 100000;
19*ab405612SSasha Neftin 	u32 i, reg = 0;
20*ab405612SSasha Neftin 
21*ab405612SSasha Neftin 	for (i = 0; i < attempts; i++) {
22*ab405612SSasha Neftin 		if (ee_reg == IGC_NVM_POLL_READ)
23*ab405612SSasha Neftin 			reg = rd32(IGC_EERD);
24*ab405612SSasha Neftin 		else
25*ab405612SSasha Neftin 			reg = rd32(IGC_EEWR);
26*ab405612SSasha Neftin 
27*ab405612SSasha Neftin 		if (reg & IGC_NVM_RW_REG_DONE) {
28*ab405612SSasha Neftin 			ret_val = 0;
29*ab405612SSasha Neftin 			break;
30*ab405612SSasha Neftin 		}
31*ab405612SSasha Neftin 
32*ab405612SSasha Neftin 		udelay(5);
33*ab405612SSasha Neftin 	}
34*ab405612SSasha Neftin 
35*ab405612SSasha Neftin 	return ret_val;
36*ab405612SSasha Neftin }
37*ab405612SSasha Neftin 
38*ab405612SSasha Neftin /**
39*ab405612SSasha Neftin  * igc_acquire_nvm - Generic request for access to EEPROM
40*ab405612SSasha Neftin  * @hw: pointer to the HW structure
41*ab405612SSasha Neftin  *
42*ab405612SSasha Neftin  * Set the EEPROM access request bit and wait for EEPROM access grant bit.
43*ab405612SSasha Neftin  * Return successful if access grant bit set, else clear the request for
44*ab405612SSasha Neftin  * EEPROM access and return -IGC_ERR_NVM (-1).
45*ab405612SSasha Neftin  */
igc_acquire_nvm(struct igc_hw * hw)46*ab405612SSasha Neftin s32 igc_acquire_nvm(struct igc_hw *hw)
47*ab405612SSasha Neftin {
48*ab405612SSasha Neftin 	s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
49*ab405612SSasha Neftin 	u32 eecd = rd32(IGC_EECD);
50*ab405612SSasha Neftin 	s32 ret_val = 0;
51*ab405612SSasha Neftin 
52*ab405612SSasha Neftin 	wr32(IGC_EECD, eecd | IGC_EECD_REQ);
53*ab405612SSasha Neftin 	eecd = rd32(IGC_EECD);
54*ab405612SSasha Neftin 
55*ab405612SSasha Neftin 	while (timeout) {
56*ab405612SSasha Neftin 		if (eecd & IGC_EECD_GNT)
57*ab405612SSasha Neftin 			break;
58*ab405612SSasha Neftin 		udelay(5);
59*ab405612SSasha Neftin 		eecd = rd32(IGC_EECD);
60*ab405612SSasha Neftin 		timeout--;
61*ab405612SSasha Neftin 	}
62*ab405612SSasha Neftin 
63*ab405612SSasha Neftin 	if (!timeout) {
64*ab405612SSasha Neftin 		eecd &= ~IGC_EECD_REQ;
65*ab405612SSasha Neftin 		wr32(IGC_EECD, eecd);
66*ab405612SSasha Neftin 		hw_dbg("Could not acquire NVM grant\n");
67*ab405612SSasha Neftin 		ret_val = -IGC_ERR_NVM;
68*ab405612SSasha Neftin 	}
69*ab405612SSasha Neftin 
70*ab405612SSasha Neftin 	return ret_val;
71*ab405612SSasha Neftin }
72*ab405612SSasha Neftin 
73*ab405612SSasha Neftin /**
74*ab405612SSasha Neftin  * igc_release_nvm - Release exclusive access to EEPROM
75*ab405612SSasha Neftin  * @hw: pointer to the HW structure
76*ab405612SSasha Neftin  *
77*ab405612SSasha Neftin  * Stop any current commands to the EEPROM and clear the EEPROM request bit.
78*ab405612SSasha Neftin  */
igc_release_nvm(struct igc_hw * hw)79*ab405612SSasha Neftin void igc_release_nvm(struct igc_hw *hw)
80*ab405612SSasha Neftin {
81*ab405612SSasha Neftin 	u32 eecd;
82*ab405612SSasha Neftin 
83*ab405612SSasha Neftin 	eecd = rd32(IGC_EECD);
84*ab405612SSasha Neftin 	eecd &= ~IGC_EECD_REQ;
85*ab405612SSasha Neftin 	wr32(IGC_EECD, eecd);
86*ab405612SSasha Neftin }
87*ab405612SSasha Neftin 
88*ab405612SSasha Neftin /**
89*ab405612SSasha Neftin  * igc_read_nvm_eerd - Reads EEPROM using EERD register
90*ab405612SSasha Neftin  * @hw: pointer to the HW structure
91*ab405612SSasha Neftin  * @offset: offset of word in the EEPROM to read
92*ab405612SSasha Neftin  * @words: number of words to read
93*ab405612SSasha Neftin  * @data: word read from the EEPROM
94*ab405612SSasha Neftin  *
95*ab405612SSasha Neftin  * Reads a 16 bit word from the EEPROM using the EERD register.
96*ab405612SSasha Neftin  */
igc_read_nvm_eerd(struct igc_hw * hw,u16 offset,u16 words,u16 * data)97*ab405612SSasha Neftin s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
98*ab405612SSasha Neftin {
99*ab405612SSasha Neftin 	struct igc_nvm_info *nvm = &hw->nvm;
100*ab405612SSasha Neftin 	u32 i, eerd = 0;
101*ab405612SSasha Neftin 	s32 ret_val = 0;
102*ab405612SSasha Neftin 
103*ab405612SSasha Neftin 	/* A check for invalid values:  offset too large, too many words,
104*ab405612SSasha Neftin 	 * and not enough words.
105*ab405612SSasha Neftin 	 */
106*ab405612SSasha Neftin 	if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
107*ab405612SSasha Neftin 	    words == 0) {
108*ab405612SSasha Neftin 		hw_dbg("nvm parameter(s) out of bounds\n");
109*ab405612SSasha Neftin 		ret_val = -IGC_ERR_NVM;
110*ab405612SSasha Neftin 		goto out;
111*ab405612SSasha Neftin 	}
112*ab405612SSasha Neftin 
113*ab405612SSasha Neftin 	for (i = 0; i < words; i++) {
114*ab405612SSasha Neftin 		eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
115*ab405612SSasha Neftin 			IGC_NVM_RW_REG_START;
116*ab405612SSasha Neftin 
117*ab405612SSasha Neftin 		wr32(IGC_EERD, eerd);
118*ab405612SSasha Neftin 		ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
119*ab405612SSasha Neftin 		if (ret_val)
120*ab405612SSasha Neftin 			break;
121*ab405612SSasha Neftin 
122*ab405612SSasha Neftin 		data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
123*ab405612SSasha Neftin 	}
124*ab405612SSasha Neftin 
125*ab405612SSasha Neftin out:
126*ab405612SSasha Neftin 	return ret_val;
127*ab405612SSasha Neftin }
128*ab405612SSasha Neftin 
129*ab405612SSasha Neftin /**
130*ab405612SSasha Neftin  * igc_read_mac_addr - Read device MAC address
131*ab405612SSasha Neftin  * @hw: pointer to the HW structure
132*ab405612SSasha Neftin  */
igc_read_mac_addr(struct igc_hw * hw)133*ab405612SSasha Neftin s32 igc_read_mac_addr(struct igc_hw *hw)
134*ab405612SSasha Neftin {
135*ab405612SSasha Neftin 	u32 rar_high;
136*ab405612SSasha Neftin 	u32 rar_low;
137*ab405612SSasha Neftin 	u16 i;
138*ab405612SSasha Neftin 
139*ab405612SSasha Neftin 	rar_high = rd32(IGC_RAH(0));
140*ab405612SSasha Neftin 	rar_low = rd32(IGC_RAL(0));
141*ab405612SSasha Neftin 
142*ab405612SSasha Neftin 	for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)
143*ab405612SSasha Neftin 		hw->mac.perm_addr[i] = (u8)(rar_low >> (i * 8));
144*ab405612SSasha Neftin 
145*ab405612SSasha Neftin 	for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)
146*ab405612SSasha Neftin 		hw->mac.perm_addr[i + 4] = (u8)(rar_high >> (i * 8));
147*ab405612SSasha Neftin 
148*ab405612SSasha Neftin 	for (i = 0; i < ETH_ALEN; i++)
149*ab405612SSasha Neftin 		hw->mac.addr[i] = hw->mac.perm_addr[i];
150*ab405612SSasha Neftin 
151*ab405612SSasha Neftin 	return 0;
152*ab405612SSasha Neftin }
153*ab405612SSasha Neftin 
154*ab405612SSasha Neftin /**
155*ab405612SSasha Neftin  * igc_validate_nvm_checksum - Validate EEPROM checksum
156*ab405612SSasha Neftin  * @hw: pointer to the HW structure
157*ab405612SSasha Neftin  *
158*ab405612SSasha Neftin  * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
159*ab405612SSasha Neftin  * and then verifies that the sum of the EEPROM is equal to 0xBABA.
160*ab405612SSasha Neftin  */
igc_validate_nvm_checksum(struct igc_hw * hw)161*ab405612SSasha Neftin s32 igc_validate_nvm_checksum(struct igc_hw *hw)
162*ab405612SSasha Neftin {
163*ab405612SSasha Neftin 	u16 checksum = 0;
164*ab405612SSasha Neftin 	u16 i, nvm_data;
165*ab405612SSasha Neftin 	s32 ret_val = 0;
166*ab405612SSasha Neftin 
167*ab405612SSasha Neftin 	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
168*ab405612SSasha Neftin 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
169*ab405612SSasha Neftin 		if (ret_val) {
170*ab405612SSasha Neftin 			hw_dbg("NVM Read Error\n");
171*ab405612SSasha Neftin 			goto out;
172*ab405612SSasha Neftin 		}
173*ab405612SSasha Neftin 		checksum += nvm_data;
174*ab405612SSasha Neftin 	}
175*ab405612SSasha Neftin 
176*ab405612SSasha Neftin 	if (checksum != (u16)NVM_SUM) {
177*ab405612SSasha Neftin 		hw_dbg("NVM Checksum Invalid\n");
178*ab405612SSasha Neftin 		ret_val = -IGC_ERR_NVM;
179*ab405612SSasha Neftin 		goto out;
180*ab405612SSasha Neftin 	}
181*ab405612SSasha Neftin 
182*ab405612SSasha Neftin out:
183*ab405612SSasha Neftin 	return ret_val;
184*ab405612SSasha Neftin }
185*ab405612SSasha Neftin 
186*ab405612SSasha Neftin /**
187*ab405612SSasha Neftin  * igc_update_nvm_checksum - Update EEPROM checksum
188*ab405612SSasha Neftin  * @hw: pointer to the HW structure
189*ab405612SSasha Neftin  *
190*ab405612SSasha Neftin  * Updates the EEPROM checksum by reading/adding each word of the EEPROM
191*ab405612SSasha Neftin  * up to the checksum.  Then calculates the EEPROM checksum and writes the
192*ab405612SSasha Neftin  * value to the EEPROM.
193*ab405612SSasha Neftin  */
igc_update_nvm_checksum(struct igc_hw * hw)194*ab405612SSasha Neftin s32 igc_update_nvm_checksum(struct igc_hw *hw)
195*ab405612SSasha Neftin {
196*ab405612SSasha Neftin 	u16 checksum = 0;
197*ab405612SSasha Neftin 	u16 i, nvm_data;
198*ab405612SSasha Neftin 	s32  ret_val;
199*ab405612SSasha Neftin 
200*ab405612SSasha Neftin 	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
201*ab405612SSasha Neftin 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
202*ab405612SSasha Neftin 		if (ret_val) {
203*ab405612SSasha Neftin 			hw_dbg("NVM Read Error while updating checksum.\n");
204*ab405612SSasha Neftin 			goto out;
205*ab405612SSasha Neftin 		}
206*ab405612SSasha Neftin 		checksum += nvm_data;
207*ab405612SSasha Neftin 	}
208*ab405612SSasha Neftin 	checksum = (u16)NVM_SUM - checksum;
209*ab405612SSasha Neftin 	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
210*ab405612SSasha Neftin 	if (ret_val)
211*ab405612SSasha Neftin 		hw_dbg("NVM Write Error while updating checksum.\n");
212*ab405612SSasha Neftin 
213*ab405612SSasha Neftin out:
214*ab405612SSasha Neftin 	return ret_val;
215*ab405612SSasha Neftin }
216