1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 2009-2012 Realtek Corporation.*/ |
3 | |
4 | #include "wifi.h" |
5 | #include "efuse.h" |
6 | #include "pci.h" |
7 | #include <linux/export.h> |
8 | |
9 | static const u8 PGPKT_DATA_SIZE = 8; |
10 | static const int EFUSE_MAX_SIZE = 512; |
11 | |
12 | #define START_ADDRESS 0x1000 |
13 | #define REG_MCUFWDL 0x0080 |
14 | |
15 | static const struct rtl_efuse_ops efuse_ops = { |
16 | .efuse_onebyte_read = efuse_one_byte_read, |
17 | .efuse_logical_map_read = efuse_shadow_read, |
18 | }; |
19 | |
20 | static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, |
21 | u8 *value); |
22 | static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, |
23 | u16 *value); |
24 | static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, |
25 | u32 *value); |
26 | static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, |
27 | u8 value); |
28 | static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, |
29 | u16 value); |
30 | static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, |
31 | u32 value); |
32 | static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, |
33 | u8 data); |
34 | static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse); |
35 | static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, |
36 | u8 *data); |
37 | static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset, |
38 | u8 word_en, u8 *data); |
39 | static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, |
40 | u8 *targetdata); |
41 | static u8 enable_efuse_data_write(struct ieee80211_hw *hw, |
42 | u16 efuse_addr, u8 word_en, u8 *data); |
43 | static u16 efuse_get_current_size(struct ieee80211_hw *hw); |
44 | static u8 efuse_calculate_word_cnts(u8 word_en); |
45 | |
46 | void efuse_initialize(struct ieee80211_hw *hw) |
47 | { |
48 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
49 | u8 bytetemp; |
50 | u8 temp; |
51 | |
52 | bytetemp = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[SYS_FUNC_EN] + 1); |
53 | temp = bytetemp | 0x20; |
54 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, val8: temp); |
55 | |
56 | bytetemp = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1); |
57 | temp = bytetemp & 0xFE; |
58 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, val8: temp); |
59 | |
60 | bytetemp = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_TEST] + 3); |
61 | temp = bytetemp | 0x80; |
62 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_TEST] + 3, val8: temp); |
63 | |
64 | rtl_write_byte(rtlpriv, addr: 0x2F8, val8: 0x3); |
65 | |
66 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3, val8: 0x72); |
67 | |
68 | } |
69 | |
70 | u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) |
71 | { |
72 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
73 | u8 data; |
74 | u8 bytetemp; |
75 | u8 temp; |
76 | u32 k = 0; |
77 | const u32 efuse_len = |
78 | rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; |
79 | |
80 | if (address < efuse_len) { |
81 | temp = address & 0xFF; |
82 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 1, |
83 | val8: temp); |
84 | bytetemp = rtl_read_byte(rtlpriv, |
85 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2); |
86 | temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); |
87 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2, |
88 | val8: temp); |
89 | |
90 | bytetemp = rtl_read_byte(rtlpriv, |
91 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3); |
92 | temp = bytetemp & 0x7F; |
93 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3, |
94 | val8: temp); |
95 | |
96 | bytetemp = rtl_read_byte(rtlpriv, |
97 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3); |
98 | while (!(bytetemp & 0x80)) { |
99 | bytetemp = rtl_read_byte(rtlpriv, |
100 | addr: rtlpriv->cfg-> |
101 | maps[EFUSE_CTRL] + 3); |
102 | k++; |
103 | if (k == 1000) |
104 | break; |
105 | } |
106 | data = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL]); |
107 | return data; |
108 | } else |
109 | return 0xFF; |
110 | |
111 | } |
112 | EXPORT_SYMBOL(efuse_read_1byte); |
113 | |
114 | void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) |
115 | { |
116 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
117 | u8 bytetemp; |
118 | u8 temp; |
119 | u32 k = 0; |
120 | const u32 efuse_len = |
121 | rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; |
122 | |
123 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "Addr=%x Data =%x\n" , |
124 | address, value); |
125 | |
126 | if (address < efuse_len) { |
127 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL], val8: value); |
128 | |
129 | temp = address & 0xFF; |
130 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 1, |
131 | val8: temp); |
132 | bytetemp = rtl_read_byte(rtlpriv, |
133 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2); |
134 | |
135 | temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); |
136 | rtl_write_byte(rtlpriv, |
137 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2, val8: temp); |
138 | |
139 | bytetemp = rtl_read_byte(rtlpriv, |
140 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3); |
141 | temp = bytetemp | 0x80; |
142 | rtl_write_byte(rtlpriv, |
143 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3, val8: temp); |
144 | |
145 | bytetemp = rtl_read_byte(rtlpriv, |
146 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3); |
147 | |
148 | while (bytetemp & 0x80) { |
149 | bytetemp = rtl_read_byte(rtlpriv, |
150 | addr: rtlpriv->cfg-> |
151 | maps[EFUSE_CTRL] + 3); |
152 | k++; |
153 | if (k == 100) { |
154 | k = 0; |
155 | break; |
156 | } |
157 | } |
158 | } |
159 | |
160 | } |
161 | |
162 | void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) |
163 | { |
164 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
165 | u32 value32; |
166 | u8 readbyte; |
167 | u16 retry; |
168 | |
169 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 1, |
170 | val8: (_offset & 0xff)); |
171 | readbyte = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2); |
172 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2, |
173 | val8: ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); |
174 | |
175 | readbyte = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3); |
176 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3, |
177 | val8: (readbyte & 0x7f)); |
178 | |
179 | retry = 0; |
180 | value32 = rtl_read_dword(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL]); |
181 | while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { |
182 | value32 = rtl_read_dword(rtlpriv, |
183 | addr: rtlpriv->cfg->maps[EFUSE_CTRL]); |
184 | retry++; |
185 | } |
186 | |
187 | udelay(50); |
188 | value32 = rtl_read_dword(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL]); |
189 | |
190 | *pbuf = (u8) (value32 & 0xff); |
191 | } |
192 | EXPORT_SYMBOL_GPL(read_efuse_byte); |
193 | |
194 | void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) |
195 | { |
196 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
197 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
198 | u8 *efuse_tbl; |
199 | u8 rtemp8[1]; |
200 | u16 efuse_addr = 0; |
201 | u8 offset, wren; |
202 | u8 u1temp = 0; |
203 | u16 i; |
204 | u16 j; |
205 | const u16 efuse_max_section = |
206 | rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; |
207 | const u32 efuse_len = |
208 | rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; |
209 | u16 **efuse_word; |
210 | u16 efuse_utilized = 0; |
211 | u8 efuse_usage; |
212 | |
213 | if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { |
214 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, |
215 | "%s: Invalid offset(%#x) with read bytes(%#x)!!\n" , |
216 | __func__, _offset, _size_byte); |
217 | return; |
218 | } |
219 | |
220 | /* allocate memory for efuse_tbl and efuse_word */ |
221 | efuse_tbl = kzalloc(size: rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], |
222 | GFP_ATOMIC); |
223 | if (!efuse_tbl) |
224 | return; |
225 | efuse_word = kcalloc(EFUSE_MAX_WORD_UNIT, size: sizeof(u16 *), GFP_ATOMIC); |
226 | if (!efuse_word) |
227 | goto out; |
228 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
229 | efuse_word[i] = kcalloc(n: efuse_max_section, size: sizeof(u16), |
230 | GFP_ATOMIC); |
231 | if (!efuse_word[i]) |
232 | goto done; |
233 | } |
234 | |
235 | for (i = 0; i < efuse_max_section; i++) |
236 | for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) |
237 | efuse_word[j][i] = 0xFFFF; |
238 | |
239 | read_efuse_byte(hw, efuse_addr, rtemp8); |
240 | if (*rtemp8 != 0xFF) { |
241 | efuse_utilized++; |
242 | RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, |
243 | "Addr=%d\n" , efuse_addr); |
244 | efuse_addr++; |
245 | } |
246 | |
247 | while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { |
248 | /* Check PG header for section num. */ |
249 | if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */ |
250 | u1temp = ((*rtemp8 & 0xE0) >> 5); |
251 | read_efuse_byte(hw, efuse_addr, rtemp8); |
252 | |
253 | if ((*rtemp8 & 0x0F) == 0x0F) { |
254 | efuse_addr++; |
255 | read_efuse_byte(hw, efuse_addr, rtemp8); |
256 | |
257 | if (*rtemp8 != 0xFF && |
258 | (efuse_addr < efuse_len)) { |
259 | efuse_addr++; |
260 | } |
261 | continue; |
262 | } else { |
263 | offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; |
264 | wren = (*rtemp8 & 0x0F); |
265 | efuse_addr++; |
266 | } |
267 | } else { |
268 | offset = ((*rtemp8 >> 4) & 0x0f); |
269 | wren = (*rtemp8 & 0x0f); |
270 | } |
271 | |
272 | if (offset < efuse_max_section) { |
273 | RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, |
274 | "offset-%d Worden=%x\n" , offset, wren); |
275 | |
276 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
277 | if (!(wren & 0x01)) { |
278 | RTPRINT(rtlpriv, FEEPROM, |
279 | EFUSE_READ_ALL, |
280 | "Addr=%d\n" , efuse_addr); |
281 | |
282 | read_efuse_byte(hw, efuse_addr, rtemp8); |
283 | efuse_addr++; |
284 | efuse_utilized++; |
285 | efuse_word[i][offset] = |
286 | (*rtemp8 & 0xff); |
287 | |
288 | if (efuse_addr >= efuse_len) |
289 | break; |
290 | |
291 | RTPRINT(rtlpriv, FEEPROM, |
292 | EFUSE_READ_ALL, |
293 | "Addr=%d\n" , efuse_addr); |
294 | |
295 | read_efuse_byte(hw, efuse_addr, rtemp8); |
296 | efuse_addr++; |
297 | efuse_utilized++; |
298 | efuse_word[i][offset] |= |
299 | (((u16)*rtemp8 << 8) & 0xff00); |
300 | |
301 | if (efuse_addr >= efuse_len) |
302 | break; |
303 | } |
304 | |
305 | wren >>= 1; |
306 | } |
307 | } |
308 | |
309 | RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, |
310 | "Addr=%d\n" , efuse_addr); |
311 | read_efuse_byte(hw, efuse_addr, rtemp8); |
312 | if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { |
313 | efuse_utilized++; |
314 | efuse_addr++; |
315 | } |
316 | } |
317 | |
318 | for (i = 0; i < efuse_max_section; i++) { |
319 | for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { |
320 | efuse_tbl[(i * 8) + (j * 2)] = |
321 | (efuse_word[j][i] & 0xff); |
322 | efuse_tbl[(i * 8) + ((j * 2) + 1)] = |
323 | ((efuse_word[j][i] >> 8) & 0xff); |
324 | } |
325 | } |
326 | |
327 | for (i = 0; i < _size_byte; i++) |
328 | pbuf[i] = efuse_tbl[_offset + i]; |
329 | |
330 | rtlefuse->efuse_usedbytes = efuse_utilized; |
331 | efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len); |
332 | rtlefuse->efuse_usedpercentage = efuse_usage; |
333 | rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, |
334 | (u8 *)&efuse_utilized); |
335 | rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, |
336 | &efuse_usage); |
337 | done: |
338 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) |
339 | kfree(objp: efuse_word[i]); |
340 | kfree(objp: efuse_word); |
341 | out: |
342 | kfree(objp: efuse_tbl); |
343 | } |
344 | |
345 | bool efuse_shadow_update_chk(struct ieee80211_hw *hw) |
346 | { |
347 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
348 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
349 | u8 section_idx, i, base; |
350 | u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; |
351 | bool wordchanged, result = true; |
352 | |
353 | for (section_idx = 0; section_idx < 16; section_idx++) { |
354 | base = section_idx * 8; |
355 | wordchanged = false; |
356 | |
357 | for (i = 0; i < 8; i = i + 2) { |
358 | if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != |
359 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i] || |
360 | rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i + 1] != |
361 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i + |
362 | 1]) { |
363 | words_need++; |
364 | wordchanged = true; |
365 | } |
366 | } |
367 | |
368 | if (wordchanged) |
369 | hdr_num++; |
370 | } |
371 | |
372 | totalbytes = hdr_num + words_need * 2; |
373 | efuse_used = rtlefuse->efuse_usedbytes; |
374 | |
375 | if ((totalbytes + efuse_used) >= |
376 | (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) |
377 | result = false; |
378 | |
379 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, |
380 | "%s: totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n" , |
381 | __func__, totalbytes, hdr_num, words_need, efuse_used); |
382 | |
383 | return result; |
384 | } |
385 | |
386 | void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, |
387 | u16 offset, u32 *value) |
388 | { |
389 | if (type == 1) |
390 | efuse_shadow_read_1byte(hw, offset, value: (u8 *)value); |
391 | else if (type == 2) |
392 | efuse_shadow_read_2byte(hw, offset, value: (u16 *)value); |
393 | else if (type == 4) |
394 | efuse_shadow_read_4byte(hw, offset, value); |
395 | |
396 | } |
397 | EXPORT_SYMBOL(efuse_shadow_read); |
398 | |
399 | void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, |
400 | u32 value) |
401 | { |
402 | if (type == 1) |
403 | efuse_shadow_write_1byte(hw, offset, value: (u8) value); |
404 | else if (type == 2) |
405 | efuse_shadow_write_2byte(hw, offset, value: (u16) value); |
406 | else if (type == 4) |
407 | efuse_shadow_write_4byte(hw, offset, value); |
408 | |
409 | } |
410 | |
411 | bool efuse_shadow_update(struct ieee80211_hw *hw) |
412 | { |
413 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
414 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
415 | u16 i, offset, base; |
416 | u8 word_en = 0x0F; |
417 | u8 first_pg = false; |
418 | |
419 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n" ); |
420 | |
421 | if (!efuse_shadow_update_chk(hw)) { |
422 | efuse_read_all_map(hw, efuse: &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); |
423 | memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], |
424 | &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], |
425 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
426 | |
427 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, |
428 | "efuse out of capacity!!\n" ); |
429 | return false; |
430 | } |
431 | efuse_power_switch(hw, write: true, pwrstate: true); |
432 | |
433 | for (offset = 0; offset < 16; offset++) { |
434 | |
435 | word_en = 0x0F; |
436 | base = offset * 8; |
437 | |
438 | for (i = 0; i < 8; i++) { |
439 | if (first_pg) { |
440 | word_en &= ~(BIT(i / 2)); |
441 | |
442 | rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = |
443 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; |
444 | } else { |
445 | |
446 | if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != |
447 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) { |
448 | word_en &= ~(BIT(i / 2)); |
449 | |
450 | rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = |
451 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; |
452 | } |
453 | } |
454 | } |
455 | |
456 | if (word_en != 0x0F) { |
457 | u8 tmpdata[8]; |
458 | |
459 | memcpy(tmpdata, |
460 | &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base], |
461 | 8); |
462 | RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, |
463 | "U-efuse\n" , tmpdata, 8); |
464 | |
465 | if (!efuse_pg_packet_write(hw, offset: (u8) offset, word_en, |
466 | data: tmpdata)) { |
467 | rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, |
468 | "PG section(%#x) fail!!\n" , offset); |
469 | break; |
470 | } |
471 | } |
472 | } |
473 | |
474 | efuse_power_switch(hw, write: true, pwrstate: false); |
475 | efuse_read_all_map(hw, efuse: &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); |
476 | |
477 | memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], |
478 | &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], |
479 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
480 | |
481 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n" ); |
482 | return true; |
483 | } |
484 | |
485 | void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) |
486 | { |
487 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
488 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
489 | |
490 | if (rtlefuse->autoload_failflag) |
491 | memset((&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), |
492 | 0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
493 | else |
494 | efuse_read_all_map(hw, efuse: &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); |
495 | |
496 | memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], |
497 | &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], |
498 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
499 | |
500 | } |
501 | EXPORT_SYMBOL(rtl_efuse_shadow_map_update); |
502 | |
503 | void efuse_force_write_vendor_id(struct ieee80211_hw *hw) |
504 | { |
505 | u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF }; |
506 | |
507 | efuse_power_switch(hw, write: true, pwrstate: true); |
508 | |
509 | efuse_pg_packet_write(hw, offset: 1, word_en: 0xD, data: tmpdata); |
510 | |
511 | efuse_power_switch(hw, write: true, pwrstate: false); |
512 | |
513 | } |
514 | |
515 | void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) |
516 | { |
517 | } |
518 | |
519 | static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, |
520 | u16 offset, u8 *value) |
521 | { |
522 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
523 | *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; |
524 | } |
525 | |
526 | static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, |
527 | u16 offset, u16 *value) |
528 | { |
529 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
530 | |
531 | *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; |
532 | *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; |
533 | |
534 | } |
535 | |
536 | static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, |
537 | u16 offset, u32 *value) |
538 | { |
539 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
540 | |
541 | *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; |
542 | *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; |
543 | *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16; |
544 | *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24; |
545 | } |
546 | |
547 | static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, |
548 | u16 offset, u8 value) |
549 | { |
550 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
551 | |
552 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value; |
553 | } |
554 | |
555 | static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, |
556 | u16 offset, u16 value) |
557 | { |
558 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
559 | |
560 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF; |
561 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8; |
562 | |
563 | } |
564 | |
565 | static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, |
566 | u16 offset, u32 value) |
567 | { |
568 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
569 | |
570 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = |
571 | (u8) (value & 0x000000FF); |
572 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = |
573 | (u8) ((value >> 8) & 0x0000FF); |
574 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] = |
575 | (u8) ((value >> 16) & 0x00FF); |
576 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] = |
577 | (u8) ((value >> 24) & 0xFF); |
578 | |
579 | } |
580 | |
581 | int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) |
582 | { |
583 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
584 | u8 tmpidx = 0; |
585 | int result; |
586 | |
587 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 1, |
588 | val8: (u8) (addr & 0xff)); |
589 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2, |
590 | val8: ((u8) ((addr >> 8) & 0x03)) | |
591 | (rtl_read_byte(rtlpriv, |
592 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2) & |
593 | 0xFC)); |
594 | |
595 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3, val8: 0x72); |
596 | |
597 | while (!(0x80 & rtl_read_byte(rtlpriv, |
598 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) |
599 | && (tmpidx < 100)) { |
600 | tmpidx++; |
601 | } |
602 | |
603 | if (tmpidx < 100) { |
604 | *data = rtl_read_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL]); |
605 | result = true; |
606 | } else { |
607 | *data = 0xff; |
608 | result = false; |
609 | } |
610 | return result; |
611 | } |
612 | EXPORT_SYMBOL(efuse_one_byte_read); |
613 | |
614 | static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) |
615 | { |
616 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
617 | u8 tmpidx = 0; |
618 | |
619 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, |
620 | "Addr = %x Data=%x\n" , addr, data); |
621 | |
622 | rtl_write_byte(rtlpriv, |
623 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 1, val8: (u8) (addr & 0xff)); |
624 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 2, |
625 | val8: (rtl_read_byte(rtlpriv, |
626 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + |
627 | 2) & 0xFC) | (u8) ((addr >> 8) & 0x03)); |
628 | |
629 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL], val8: data); |
630 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3, val8: 0xF2); |
631 | |
632 | while ((0x80 & rtl_read_byte(rtlpriv, |
633 | addr: rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) |
634 | && (tmpidx < 100)) { |
635 | tmpidx++; |
636 | } |
637 | |
638 | if (tmpidx < 100) |
639 | return true; |
640 | return false; |
641 | } |
642 | |
643 | static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse) |
644 | { |
645 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
646 | |
647 | efuse_power_switch(hw, write: false, pwrstate: true); |
648 | read_efuse(hw, offset: 0, size_byte: rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], pbuf: efuse); |
649 | efuse_power_switch(hw, write: false, pwrstate: false); |
650 | } |
651 | |
652 | static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, |
653 | u8 efuse_data, u8 offset, u8 *tmpdata, |
654 | u8 *readstate) |
655 | { |
656 | bool dataempty = true; |
657 | u8 hoffset; |
658 | u8 tmpidx; |
659 | u8 hworden; |
660 | u8 word_cnts; |
661 | |
662 | hoffset = (efuse_data >> 4) & 0x0F; |
663 | hworden = efuse_data & 0x0F; |
664 | word_cnts = efuse_calculate_word_cnts(word_en: hworden); |
665 | |
666 | if (hoffset == offset) { |
667 | for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) { |
668 | if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, |
669 | &efuse_data)) { |
670 | tmpdata[tmpidx] = efuse_data; |
671 | if (efuse_data != 0xff) |
672 | dataempty = false; |
673 | } |
674 | } |
675 | |
676 | if (!dataempty) { |
677 | *readstate = PG_STATE_DATA; |
678 | } else { |
679 | *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; |
680 | *readstate = PG_STATE_HEADER; |
681 | } |
682 | |
683 | } else { |
684 | *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; |
685 | *readstate = PG_STATE_HEADER; |
686 | } |
687 | } |
688 | |
689 | static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) |
690 | { |
691 | u8 readstate = PG_STATE_HEADER; |
692 | |
693 | bool continual = true; |
694 | |
695 | u8 efuse_data, word_cnts = 0; |
696 | u16 efuse_addr = 0; |
697 | u8 tmpdata[8]; |
698 | |
699 | if (data == NULL) |
700 | return false; |
701 | if (offset > 15) |
702 | return false; |
703 | |
704 | memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); |
705 | memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); |
706 | |
707 | while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { |
708 | if (readstate & PG_STATE_HEADER) { |
709 | if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) |
710 | && (efuse_data != 0xFF)) |
711 | efuse_read_data_case1(hw, efuse_addr: &efuse_addr, |
712 | efuse_data, offset, |
713 | tmpdata, readstate: &readstate); |
714 | else |
715 | continual = false; |
716 | } else if (readstate & PG_STATE_DATA) { |
717 | efuse_word_enable_data_read(word_en: 0, sourdata: tmpdata, targetdata: data); |
718 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; |
719 | readstate = PG_STATE_HEADER; |
720 | } |
721 | |
722 | } |
723 | |
724 | if ((data[0] == 0xff) && (data[1] == 0xff) && |
725 | (data[2] == 0xff) && (data[3] == 0xff) && |
726 | (data[4] == 0xff) && (data[5] == 0xff) && |
727 | (data[6] == 0xff) && (data[7] == 0xff)) |
728 | return false; |
729 | else |
730 | return true; |
731 | |
732 | } |
733 | |
734 | static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, |
735 | u8 efuse_data, u8 offset, |
736 | int *continual, u8 *write_state, |
737 | struct pgpkt_struct *target_pkt, |
738 | int *repeat_times, int *result, u8 word_en) |
739 | { |
740 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
741 | struct pgpkt_struct tmp_pkt; |
742 | int dataempty = true; |
743 | u8 originaldata[8 * sizeof(u8)]; |
744 | u8 badworden = 0x0F; |
745 | u8 match_word_en, tmp_word_en; |
746 | u8 tmpindex; |
747 | u8 = efuse_data; |
748 | u8 tmp_word_cnts; |
749 | |
750 | tmp_pkt.offset = (tmp_header >> 4) & 0x0F; |
751 | tmp_pkt.word_en = tmp_header & 0x0F; |
752 | tmp_word_cnts = efuse_calculate_word_cnts(word_en: tmp_pkt.word_en); |
753 | |
754 | if (tmp_pkt.offset != target_pkt->offset) { |
755 | *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; |
756 | *write_state = PG_STATE_HEADER; |
757 | } else { |
758 | for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) { |
759 | if (efuse_one_byte_read(hw, |
760 | (*efuse_addr + 1 + tmpindex), |
761 | &efuse_data) && |
762 | (efuse_data != 0xFF)) |
763 | dataempty = false; |
764 | } |
765 | |
766 | if (!dataempty) { |
767 | *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; |
768 | *write_state = PG_STATE_HEADER; |
769 | } else { |
770 | match_word_en = 0x0F; |
771 | if (!((target_pkt->word_en & BIT(0)) | |
772 | (tmp_pkt.word_en & BIT(0)))) |
773 | match_word_en &= (~BIT(0)); |
774 | |
775 | if (!((target_pkt->word_en & BIT(1)) | |
776 | (tmp_pkt.word_en & BIT(1)))) |
777 | match_word_en &= (~BIT(1)); |
778 | |
779 | if (!((target_pkt->word_en & BIT(2)) | |
780 | (tmp_pkt.word_en & BIT(2)))) |
781 | match_word_en &= (~BIT(2)); |
782 | |
783 | if (!((target_pkt->word_en & BIT(3)) | |
784 | (tmp_pkt.word_en & BIT(3)))) |
785 | match_word_en &= (~BIT(3)); |
786 | |
787 | if ((match_word_en & 0x0F) != 0x0F) { |
788 | badworden = |
789 | enable_efuse_data_write(hw, |
790 | efuse_addr: *efuse_addr + 1, |
791 | word_en: tmp_pkt.word_en, |
792 | data: target_pkt->data); |
793 | |
794 | if (0x0F != (badworden & 0x0F)) { |
795 | u8 reorg_offset = offset; |
796 | u8 reorg_worden = badworden; |
797 | |
798 | efuse_pg_packet_write(hw, offset: reorg_offset, |
799 | word_en: reorg_worden, |
800 | data: originaldata); |
801 | } |
802 | |
803 | tmp_word_en = 0x0F; |
804 | if ((target_pkt->word_en & BIT(0)) ^ |
805 | (match_word_en & BIT(0))) |
806 | tmp_word_en &= (~BIT(0)); |
807 | |
808 | if ((target_pkt->word_en & BIT(1)) ^ |
809 | (match_word_en & BIT(1))) |
810 | tmp_word_en &= (~BIT(1)); |
811 | |
812 | if ((target_pkt->word_en & BIT(2)) ^ |
813 | (match_word_en & BIT(2))) |
814 | tmp_word_en &= (~BIT(2)); |
815 | |
816 | if ((target_pkt->word_en & BIT(3)) ^ |
817 | (match_word_en & BIT(3))) |
818 | tmp_word_en &= (~BIT(3)); |
819 | |
820 | if ((tmp_word_en & 0x0F) != 0x0F) { |
821 | *efuse_addr = efuse_get_current_size(hw); |
822 | target_pkt->offset = offset; |
823 | target_pkt->word_en = tmp_word_en; |
824 | } else { |
825 | *continual = false; |
826 | } |
827 | *write_state = PG_STATE_HEADER; |
828 | *repeat_times += 1; |
829 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
830 | *continual = false; |
831 | *result = false; |
832 | } |
833 | } else { |
834 | *efuse_addr += (2 * tmp_word_cnts) + 1; |
835 | target_pkt->offset = offset; |
836 | target_pkt->word_en = word_en; |
837 | *write_state = PG_STATE_HEADER; |
838 | } |
839 | } |
840 | } |
841 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n" ); |
842 | } |
843 | |
844 | static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, |
845 | int *continual, u8 *write_state, |
846 | struct pgpkt_struct target_pkt, |
847 | int *repeat_times, int *result) |
848 | { |
849 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
850 | struct pgpkt_struct tmp_pkt; |
851 | u8 ; |
852 | u8 ; |
853 | u8 originaldata[8 * sizeof(u8)]; |
854 | u8 tmp_word_cnts; |
855 | u8 badworden = 0x0F; |
856 | |
857 | pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en; |
858 | efuse_one_byte_write(hw, addr: *efuse_addr, data: pg_header); |
859 | efuse_one_byte_read(hw, *efuse_addr, &tmp_header); |
860 | |
861 | if (tmp_header == pg_header) { |
862 | *write_state = PG_STATE_DATA; |
863 | } else if (tmp_header == 0xFF) { |
864 | *write_state = PG_STATE_HEADER; |
865 | *repeat_times += 1; |
866 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
867 | *continual = false; |
868 | *result = false; |
869 | } |
870 | } else { |
871 | tmp_pkt.offset = (tmp_header >> 4) & 0x0F; |
872 | tmp_pkt.word_en = tmp_header & 0x0F; |
873 | |
874 | tmp_word_cnts = efuse_calculate_word_cnts(word_en: tmp_pkt.word_en); |
875 | |
876 | memset(originaldata, 0xff, 8 * sizeof(u8)); |
877 | |
878 | if (efuse_pg_packet_read(hw, offset: tmp_pkt.offset, data: originaldata)) { |
879 | badworden = enable_efuse_data_write(hw, |
880 | efuse_addr: *efuse_addr + 1, |
881 | word_en: tmp_pkt.word_en, |
882 | data: originaldata); |
883 | |
884 | if (0x0F != (badworden & 0x0F)) { |
885 | u8 reorg_offset = tmp_pkt.offset; |
886 | u8 reorg_worden = badworden; |
887 | |
888 | efuse_pg_packet_write(hw, offset: reorg_offset, |
889 | word_en: reorg_worden, |
890 | data: originaldata); |
891 | *efuse_addr = efuse_get_current_size(hw); |
892 | } else { |
893 | *efuse_addr = *efuse_addr + |
894 | (tmp_word_cnts * 2) + 1; |
895 | } |
896 | } else { |
897 | *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; |
898 | } |
899 | |
900 | *write_state = PG_STATE_HEADER; |
901 | *repeat_times += 1; |
902 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
903 | *continual = false; |
904 | *result = false; |
905 | } |
906 | |
907 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
908 | "efuse PG_STATE_HEADER-2\n" ); |
909 | } |
910 | } |
911 | |
912 | static int efuse_pg_packet_write(struct ieee80211_hw *hw, |
913 | u8 offset, u8 word_en, u8 *data) |
914 | { |
915 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
916 | struct pgpkt_struct target_pkt; |
917 | u8 write_state = PG_STATE_HEADER; |
918 | int continual = true, result = true; |
919 | u16 efuse_addr = 0; |
920 | u8 efuse_data; |
921 | u8 target_word_cnts = 0; |
922 | u8 badworden = 0x0F; |
923 | static int repeat_times; |
924 | |
925 | if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE - |
926 | rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { |
927 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
928 | "efuse_pg_packet_write error\n" ); |
929 | return false; |
930 | } |
931 | |
932 | target_pkt.offset = offset; |
933 | target_pkt.word_en = word_en; |
934 | |
935 | memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); |
936 | |
937 | efuse_word_enable_data_read(word_en, sourdata: data, targetdata: target_pkt.data); |
938 | target_word_cnts = efuse_calculate_word_cnts(word_en: target_pkt.word_en); |
939 | |
940 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n" ); |
941 | |
942 | while (continual && (efuse_addr < (EFUSE_MAX_SIZE - |
943 | rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { |
944 | if (write_state == PG_STATE_HEADER) { |
945 | badworden = 0x0F; |
946 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
947 | "efuse PG_STATE_HEADER\n" ); |
948 | |
949 | if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && |
950 | (efuse_data != 0xFF)) |
951 | efuse_write_data_case1(hw, efuse_addr: &efuse_addr, |
952 | efuse_data, offset, |
953 | continual: &continual, |
954 | write_state: &write_state, |
955 | target_pkt: &target_pkt, |
956 | repeat_times: &repeat_times, result: &result, |
957 | word_en); |
958 | else |
959 | efuse_write_data_case2(hw, efuse_addr: &efuse_addr, |
960 | continual: &continual, |
961 | write_state: &write_state, |
962 | target_pkt, |
963 | repeat_times: &repeat_times, |
964 | result: &result); |
965 | |
966 | } else if (write_state == PG_STATE_DATA) { |
967 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
968 | "efuse PG_STATE_DATA\n" ); |
969 | badworden = |
970 | enable_efuse_data_write(hw, efuse_addr: efuse_addr + 1, |
971 | word_en: target_pkt.word_en, |
972 | data: target_pkt.data); |
973 | |
974 | if ((badworden & 0x0F) == 0x0F) { |
975 | continual = false; |
976 | } else { |
977 | efuse_addr = |
978 | efuse_addr + (2 * target_word_cnts) + 1; |
979 | |
980 | target_pkt.offset = offset; |
981 | target_pkt.word_en = badworden; |
982 | target_word_cnts = |
983 | efuse_calculate_word_cnts(word_en: target_pkt. |
984 | word_en); |
985 | write_state = PG_STATE_HEADER; |
986 | repeat_times++; |
987 | if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
988 | continual = false; |
989 | result = false; |
990 | } |
991 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
992 | "efuse PG_STATE_HEADER-3\n" ); |
993 | } |
994 | } |
995 | } |
996 | |
997 | if (efuse_addr >= (EFUSE_MAX_SIZE - |
998 | rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { |
999 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, |
1000 | "efuse_addr(%#x) Out of size!!\n" , efuse_addr); |
1001 | } |
1002 | |
1003 | return true; |
1004 | } |
1005 | |
1006 | static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, |
1007 | u8 *targetdata) |
1008 | { |
1009 | if (!(word_en & BIT(0))) { |
1010 | targetdata[0] = sourdata[0]; |
1011 | targetdata[1] = sourdata[1]; |
1012 | } |
1013 | |
1014 | if (!(word_en & BIT(1))) { |
1015 | targetdata[2] = sourdata[2]; |
1016 | targetdata[3] = sourdata[3]; |
1017 | } |
1018 | |
1019 | if (!(word_en & BIT(2))) { |
1020 | targetdata[4] = sourdata[4]; |
1021 | targetdata[5] = sourdata[5]; |
1022 | } |
1023 | |
1024 | if (!(word_en & BIT(3))) { |
1025 | targetdata[6] = sourdata[6]; |
1026 | targetdata[7] = sourdata[7]; |
1027 | } |
1028 | } |
1029 | |
1030 | static u8 enable_efuse_data_write(struct ieee80211_hw *hw, |
1031 | u16 efuse_addr, u8 word_en, u8 *data) |
1032 | { |
1033 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1034 | u16 tmpaddr; |
1035 | u16 start_addr = efuse_addr; |
1036 | u8 badworden = 0x0F; |
1037 | u8 tmpdata[8]; |
1038 | |
1039 | memset(tmpdata, 0xff, PGPKT_DATA_SIZE); |
1040 | rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, |
1041 | "word_en = %x efuse_addr=%x\n" , word_en, efuse_addr); |
1042 | |
1043 | if (!(word_en & BIT(0))) { |
1044 | tmpaddr = start_addr; |
1045 | efuse_one_byte_write(hw, addr: start_addr++, data: data[0]); |
1046 | efuse_one_byte_write(hw, addr: start_addr++, data: data[1]); |
1047 | |
1048 | efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); |
1049 | efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]); |
1050 | if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) |
1051 | badworden &= (~BIT(0)); |
1052 | } |
1053 | |
1054 | if (!(word_en & BIT(1))) { |
1055 | tmpaddr = start_addr; |
1056 | efuse_one_byte_write(hw, addr: start_addr++, data: data[2]); |
1057 | efuse_one_byte_write(hw, addr: start_addr++, data: data[3]); |
1058 | |
1059 | efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); |
1060 | efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]); |
1061 | if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) |
1062 | badworden &= (~BIT(1)); |
1063 | } |
1064 | |
1065 | if (!(word_en & BIT(2))) { |
1066 | tmpaddr = start_addr; |
1067 | efuse_one_byte_write(hw, addr: start_addr++, data: data[4]); |
1068 | efuse_one_byte_write(hw, addr: start_addr++, data: data[5]); |
1069 | |
1070 | efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); |
1071 | efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]); |
1072 | if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) |
1073 | badworden &= (~BIT(2)); |
1074 | } |
1075 | |
1076 | if (!(word_en & BIT(3))) { |
1077 | tmpaddr = start_addr; |
1078 | efuse_one_byte_write(hw, addr: start_addr++, data: data[6]); |
1079 | efuse_one_byte_write(hw, addr: start_addr++, data: data[7]); |
1080 | |
1081 | efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); |
1082 | efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]); |
1083 | if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) |
1084 | badworden &= (~BIT(3)); |
1085 | } |
1086 | |
1087 | return badworden; |
1088 | } |
1089 | |
1090 | void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) |
1091 | { |
1092 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1093 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); |
1094 | u8 tempval; |
1095 | u16 tmpv16; |
1096 | |
1097 | if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) { |
1098 | if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && |
1099 | rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) { |
1100 | rtl_write_byte(rtlpriv, |
1101 | addr: rtlpriv->cfg->maps[EFUSE_ACCESS], val8: 0x69); |
1102 | } else { |
1103 | tmpv16 = |
1104 | rtl_read_word(rtlpriv, |
1105 | addr: rtlpriv->cfg->maps[SYS_ISO_CTRL]); |
1106 | if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { |
1107 | tmpv16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V]; |
1108 | rtl_write_word(rtlpriv, |
1109 | addr: rtlpriv->cfg->maps[SYS_ISO_CTRL], |
1110 | val16: tmpv16); |
1111 | } |
1112 | } |
1113 | tmpv16 = rtl_read_word(rtlpriv, |
1114 | addr: rtlpriv->cfg->maps[SYS_FUNC_EN]); |
1115 | if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) { |
1116 | tmpv16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR]; |
1117 | rtl_write_word(rtlpriv, |
1118 | addr: rtlpriv->cfg->maps[SYS_FUNC_EN], val16: tmpv16); |
1119 | } |
1120 | |
1121 | tmpv16 = rtl_read_word(rtlpriv, addr: rtlpriv->cfg->maps[SYS_CLK]); |
1122 | if ((!(tmpv16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) || |
1123 | (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) { |
1124 | tmpv16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] | |
1125 | rtlpriv->cfg->maps[EFUSE_ANA8M]); |
1126 | rtl_write_word(rtlpriv, |
1127 | addr: rtlpriv->cfg->maps[SYS_CLK], val16: tmpv16); |
1128 | } |
1129 | } |
1130 | |
1131 | if (pwrstate) { |
1132 | if (write) { |
1133 | tempval = rtl_read_byte(rtlpriv, |
1134 | addr: rtlpriv->cfg->maps[EFUSE_TEST] + |
1135 | 3); |
1136 | |
1137 | if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { |
1138 | tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6)); |
1139 | tempval |= (VOLTAGE_V25 << 3); |
1140 | } else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { |
1141 | tempval &= 0x0F; |
1142 | tempval |= (VOLTAGE_V25 << 4); |
1143 | } |
1144 | |
1145 | rtl_write_byte(rtlpriv, |
1146 | addr: rtlpriv->cfg->maps[EFUSE_TEST] + 3, |
1147 | val8: (tempval | 0x80)); |
1148 | } |
1149 | |
1150 | if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { |
1151 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CLK], |
1152 | val8: 0x03); |
1153 | } |
1154 | } else { |
1155 | if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && |
1156 | rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) |
1157 | rtl_write_byte(rtlpriv, |
1158 | addr: rtlpriv->cfg->maps[EFUSE_ACCESS], val8: 0); |
1159 | |
1160 | if (write) { |
1161 | tempval = rtl_read_byte(rtlpriv, |
1162 | addr: rtlpriv->cfg->maps[EFUSE_TEST] + |
1163 | 3); |
1164 | rtl_write_byte(rtlpriv, |
1165 | addr: rtlpriv->cfg->maps[EFUSE_TEST] + 3, |
1166 | val8: (tempval & 0x7F)); |
1167 | } |
1168 | |
1169 | if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { |
1170 | rtl_write_byte(rtlpriv, addr: rtlpriv->cfg->maps[EFUSE_CLK], |
1171 | val8: 0x02); |
1172 | } |
1173 | } |
1174 | } |
1175 | EXPORT_SYMBOL(efuse_power_switch); |
1176 | |
1177 | static u16 efuse_get_current_size(struct ieee80211_hw *hw) |
1178 | { |
1179 | int continual = true; |
1180 | u16 efuse_addr = 0; |
1181 | u8 hworden; |
1182 | u8 efuse_data, word_cnts; |
1183 | |
1184 | while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && |
1185 | (efuse_addr < EFUSE_MAX_SIZE)) { |
1186 | if (efuse_data != 0xFF) { |
1187 | hworden = efuse_data & 0x0F; |
1188 | word_cnts = efuse_calculate_word_cnts(word_en: hworden); |
1189 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; |
1190 | } else { |
1191 | continual = false; |
1192 | } |
1193 | } |
1194 | |
1195 | return efuse_addr; |
1196 | } |
1197 | |
1198 | static u8 efuse_calculate_word_cnts(u8 word_en) |
1199 | { |
1200 | u8 word_cnts = 0; |
1201 | |
1202 | if (!(word_en & BIT(0))) |
1203 | word_cnts++; |
1204 | if (!(word_en & BIT(1))) |
1205 | word_cnts++; |
1206 | if (!(word_en & BIT(2))) |
1207 | word_cnts++; |
1208 | if (!(word_en & BIT(3))) |
1209 | word_cnts++; |
1210 | return word_cnts; |
1211 | } |
1212 | |
1213 | int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, |
1214 | int max_size, u8 *hwinfo, int *params) |
1215 | { |
1216 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
1217 | struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); |
1218 | struct device *dev = &rtlpcipriv->dev.pdev->dev; |
1219 | u16 eeprom_id; |
1220 | u16 i, usvalue; |
1221 | |
1222 | switch (rtlefuse->epromtype) { |
1223 | case EEPROM_BOOT_EFUSE: |
1224 | rtl_efuse_shadow_map_update(hw); |
1225 | break; |
1226 | |
1227 | case EEPROM_93C46: |
1228 | pr_err("RTL8XXX did not boot from eeprom, check it !!\n" ); |
1229 | return 1; |
1230 | |
1231 | default: |
1232 | dev_warn(dev, "no efuse data\n" ); |
1233 | return 1; |
1234 | } |
1235 | |
1236 | memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], max_size); |
1237 | |
1238 | RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP" , |
1239 | hwinfo, max_size); |
1240 | |
1241 | eeprom_id = *((u16 *)&hwinfo[0]); |
1242 | if (eeprom_id != params[0]) { |
1243 | rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, |
1244 | "EEPROM ID(%#x) is invalid!!\n" , eeprom_id); |
1245 | rtlefuse->autoload_failflag = true; |
1246 | } else { |
1247 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n" ); |
1248 | rtlefuse->autoload_failflag = false; |
1249 | } |
1250 | |
1251 | if (rtlefuse->autoload_failflag) |
1252 | return 1; |
1253 | |
1254 | rtlefuse->eeprom_vid = *(u16 *)&hwinfo[params[1]]; |
1255 | rtlefuse->eeprom_did = *(u16 *)&hwinfo[params[2]]; |
1256 | rtlefuse->eeprom_svid = *(u16 *)&hwinfo[params[3]]; |
1257 | rtlefuse->eeprom_smid = *(u16 *)&hwinfo[params[4]]; |
1258 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, |
1259 | "EEPROMId = 0x%4x\n" , eeprom_id); |
1260 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, |
1261 | "EEPROM VID = 0x%4x\n" , rtlefuse->eeprom_vid); |
1262 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, |
1263 | "EEPROM DID = 0x%4x\n" , rtlefuse->eeprom_did); |
1264 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, |
1265 | "EEPROM SVID = 0x%4x\n" , rtlefuse->eeprom_svid); |
1266 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, |
1267 | "EEPROM SMID = 0x%4x\n" , rtlefuse->eeprom_smid); |
1268 | |
1269 | for (i = 0; i < 6; i += 2) { |
1270 | usvalue = *(u16 *)&hwinfo[params[5] + i]; |
1271 | *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; |
1272 | } |
1273 | rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n" , rtlefuse->dev_addr); |
1274 | |
1275 | rtlefuse->eeprom_channelplan = *&hwinfo[params[6]]; |
1276 | rtlefuse->eeprom_version = *(u16 *)&hwinfo[params[7]]; |
1277 | rtlefuse->txpwr_fromeprom = true; |
1278 | rtlefuse->eeprom_oemid = *&hwinfo[params[8]]; |
1279 | |
1280 | rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, |
1281 | "EEPROM Customer ID: 0x%2x\n" , rtlefuse->eeprom_oemid); |
1282 | |
1283 | /* set channel plan to world wide 13 */ |
1284 | rtlefuse->channel_plan = params[9]; |
1285 | |
1286 | return 0; |
1287 | } |
1288 | EXPORT_SYMBOL_GPL(rtl_get_hwinfo); |
1289 | |
1290 | static void _rtl_fw_block_write_usb(struct ieee80211_hw *hw, u8 *buffer, u32 size) |
1291 | { |
1292 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1293 | u32 start = START_ADDRESS; |
1294 | u32 n; |
1295 | |
1296 | while (size > 0) { |
1297 | if (size >= 64) |
1298 | n = 64; |
1299 | else if (size >= 8) |
1300 | n = 8; |
1301 | else |
1302 | n = 1; |
1303 | |
1304 | rtl_write_chunk(rtlpriv, addr: start, length: n, data: buffer); |
1305 | |
1306 | start += n; |
1307 | buffer += n; |
1308 | size -= n; |
1309 | } |
1310 | } |
1311 | |
1312 | void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size) |
1313 | { |
1314 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1315 | u32 i; |
1316 | |
1317 | if (rtlpriv->rtlhal.interface == INTF_PCI) { |
1318 | for (i = 0; i < size; i++) |
1319 | rtl_write_byte(rtlpriv, addr: (START_ADDRESS + i), |
1320 | val8: *(buffer + i)); |
1321 | } else if (rtlpriv->rtlhal.interface == INTF_USB) { |
1322 | _rtl_fw_block_write_usb(hw, buffer, size); |
1323 | } |
1324 | } |
1325 | EXPORT_SYMBOL_GPL(rtl_fw_block_write); |
1326 | |
1327 | void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer, |
1328 | u32 size) |
1329 | { |
1330 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1331 | u8 value8; |
1332 | u8 u8page = (u8)(page & 0x07); |
1333 | |
1334 | value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; |
1335 | |
1336 | rtl_write_byte(rtlpriv, addr: (REG_MCUFWDL + 2), val8: value8); |
1337 | rtl_fw_block_write(hw, buffer, size); |
1338 | } |
1339 | EXPORT_SYMBOL_GPL(rtl_fw_page_write); |
1340 | |
1341 | void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen) |
1342 | { |
1343 | u32 fwlen = *pfwlen; |
1344 | u8 remain = (u8)(fwlen % 4); |
1345 | |
1346 | remain = (remain == 0) ? 0 : (4 - remain); |
1347 | |
1348 | while (remain > 0) { |
1349 | pfwbuf[fwlen] = 0; |
1350 | fwlen++; |
1351 | remain--; |
1352 | } |
1353 | |
1354 | *pfwlen = fwlen; |
1355 | } |
1356 | EXPORT_SYMBOL_GPL(rtl_fill_dummy); |
1357 | |
1358 | void rtl_efuse_ops_init(struct ieee80211_hw *hw) |
1359 | { |
1360 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1361 | |
1362 | rtlpriv->efuse.efuse_ops = &efuse_ops; |
1363 | } |
1364 | EXPORT_SYMBOL_GPL(rtl_efuse_ops_init); |
1365 | |