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