1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#define _RTL8712_EFUSE_C_
30
31#include "osdep_service.h"
32#include "drv_types.h"
33#include "rtl8712_efuse.h"
34
35
36static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 ;
37
38static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn)
39{
40 u8 tmpu8 = 0;
41
42 if (true == bPowerOn) {
43
44
45
46 tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
47 tmpu8 |= 0x80;
48 r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
49 msleep(20);
50
51 r8712_write8(padapter, EFUSE_CLK_CTRL, 0x03);
52 msleep(20);
53 } else {
54
55
56
57 tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
58 tmpu8 &= 0x7F;
59 r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
60
61 r8712_write8(padapter, EFUSE_CLK_CTRL, 0x02);
62 }
63}
64
65
66
67
68u8 r8712_efuse_reg_init(struct _adapter *padapter)
69{
70 return true;
71}
72
73void r8712_efuse_reg_uninit(struct _adapter *padapter)
74{
75 efuse_reg_ctrl(padapter, false);
76}
77
78static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data)
79{
80 u8 tmpidx = 0, bResult;
81
82
83 r8712_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xFF));
84 r8712_write8(padapter, EFUSE_CTRL+2, ((u8)((addr>>8)&0x03)) |
85 (r8712_read8(padapter, EFUSE_CTRL+2)&0xFC));
86 r8712_write8(padapter, EFUSE_CTRL+3, 0x72);
87
88 while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 100))
89 tmpidx++;
90 if (tmpidx < 100) {
91 *data = r8712_read8(padapter, EFUSE_CTRL);
92 bResult = true;
93 } else {
94 *data = 0xff;
95 bResult = false;
96 }
97 return bResult;
98}
99
100static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data)
101{
102 u8 tmpidx = 0, bResult;
103
104
105 r8712_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xFF));
106 r8712_write8(padapter, EFUSE_CTRL+2, ((u8)((addr>>8)&0x03)) |
107 (r8712_read8(padapter, EFUSE_CTRL+2)&0xFC));
108 r8712_write8(padapter, EFUSE_CTRL, data);
109 r8712_write8(padapter, EFUSE_CTRL+3, 0xF2);
110
111 while ((0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 100))
112 tmpidx++;
113 if (tmpidx < 100)
114 bResult = true;
115 else
116 bResult = false;
117 return bResult;
118}
119
120static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr,
121 u8 *data)
122{
123 u8 tmpidx = 0, tmpv8 = 0, bResult;
124
125
126 r8712_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xFF));
127 tmpv8 = ((u8)((addr >> 8) & 0x03)) |
128 (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC);
129 r8712_write8(padapter, EFUSE_CTRL+2, tmpv8);
130 if (true == bRead) {
131 r8712_write8(padapter, EFUSE_CTRL+3, 0x72);
132 while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) &&
133 (tmpidx < 100))
134 tmpidx++;
135 if (tmpidx < 100) {
136 *data = r8712_read8(padapter, EFUSE_CTRL);
137 bResult = true;
138 } else {
139 *data = 0;
140 bResult = false;
141 }
142 } else {
143 r8712_write8(padapter, EFUSE_CTRL, *data);
144 r8712_write8(padapter, EFUSE_CTRL+3, 0xF2);
145 while ((0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) &&
146 (tmpidx < 100))
147 tmpidx++;
148 if (tmpidx < 100)
149 bResult = true;
150 else
151 bResult = false;
152 }
153 return bResult;
154}
155
156static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty)
157{
158 u8 value, ret = true;
159
160
161 if (efuse_one_byte_rw(padapter, true, 0, &value) == true) {
162 if (0xFF == value)
163 *empty = true;
164 else
165 *empty = false;
166 } else
167 ret = false;
168 return ret;
169}
170
171void r8712_efuse_change_max_size(struct _adapter *padapter)
172{
173 u16 pre_pg_data_saddr = 0x1FB;
174 u16 i;
175 u16 pre_pg_data_size = 5;
176 u8 pre_pg_data[5];
177
178 for (i = 0; i < pre_pg_data_size; i++)
179 efuse_one_byte_read(padapter, pre_pg_data_saddr + i,
180 &pre_pg_data[i]);
181 if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) &&
182 (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) &&
183 (pre_pg_data[4] == 0x0C))
184 efuse_available_max_size -= pre_pg_data_size;
185}
186
187int r8712_efuse_get_max_size(struct _adapter *padapter)
188{
189 return efuse_available_max_size;
190}
191
192static u8 calculate_word_cnts(const u8 word_en)
193{
194 u8 word_cnts = 0;
195 u8 word_idx;
196
197 for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++)
198 if (!(word_en & BIT(word_idx)))
199 word_cnts++;
200 return word_cnts;
201}
202
203static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata,
204 u8 *targetdata)
205{
206 u8 tmpindex = 0;
207 u8 word_idx, byte_idx;
208
209 for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) {
210 if (!(word_en&BIT(word_idx))) {
211 byte_idx = word_idx * 2;
212 targetdata[byte_idx] = sourdata[tmpindex++];
213 targetdata[byte_idx + 1] = sourdata[tmpindex++];
214 }
215 }
216}
217
218u16 r8712_efuse_get_current_size(struct _adapter *padapter)
219{
220 int bContinual = true;
221 u16 efuse_addr = 0;
222 u8 hworden = 0;
223 u8 efuse_data, word_cnts = 0;
224
225 while (bContinual && efuse_one_byte_read(padapter, efuse_addr,
226 &efuse_data) && (efuse_addr < efuse_available_max_size)) {
227 if (efuse_data != 0xFF) {
228 hworden = efuse_data & 0x0F;
229 word_cnts = calculate_word_cnts(hworden);
230
231 efuse_addr = efuse_addr + (word_cnts * 2) + 1;
232 } else
233 bContinual = false;
234 }
235 return efuse_addr;
236}
237
238u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
239{
240 u8 hoffset = 0, hworden = 0, word_cnts = 0;
241 u16 efuse_addr = 0;
242 u8 efuse_data;
243 u8 tmpidx = 0;
244 u8 tmpdata[PGPKT_DATA_SIZE];
245 u8 ret = true;
246
247 if (data == NULL)
248 return false;
249 if (offset > 0x0f)
250 return false;
251 memset(data, 0xFF, sizeof(u8)*PGPKT_DATA_SIZE);
252 while (efuse_addr < efuse_available_max_size) {
253 if (efuse_one_byte_read(padapter, efuse_addr, &efuse_data) ==
254 true) {
255 if (efuse_data == 0xFF)
256 break;
257 hoffset = (efuse_data >> 4) & 0x0F;
258 hworden = efuse_data & 0x0F;
259 word_cnts = calculate_word_cnts(hworden);
260 if (hoffset == offset) {
261 memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
262 for (tmpidx = 0; tmpidx < word_cnts * 2;
263 tmpidx++) {
264 if (efuse_one_byte_read(padapter,
265 efuse_addr+1+tmpidx, &efuse_data) ==
266 true) {
267 tmpdata[tmpidx] = efuse_data;
268 } else
269 ret = false;
270 }
271 pgpacket_copy_data(hworden, tmpdata, data);
272 }
273 efuse_addr += 1 + (word_cnts*2);
274 } else {
275 ret = false;
276 break;
277 }
278 }
279 return ret;
280}
281
282static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
283{
284 struct PGPKT_STRUCT pkt;
285 u8 offset, word_en, value;
286 u16 addr;
287 int i;
288 u8 ret = true;
289
290 pkt.offset = GET_EFUSE_OFFSET(header);
291 pkt.word_en = GET_EFUSE_WORD_EN(header);
292 addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2;
293 if (addr > efuse_available_max_size)
294 return false;
295
296 addr = 0;
297 while (addr < header_addr) {
298 if (efuse_one_byte_read(padapter, addr++, &value) == false) {
299 ret = false;
300 break;
301 }
302 offset = GET_EFUSE_OFFSET(value);
303 word_en = GET_EFUSE_WORD_EN(value);
304 if (pkt.offset != offset) {
305 addr += calculate_word_cnts(word_en)*2;
306 continue;
307 }
308 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
309 if (BIT(i) & word_en) {
310 if (BIT(i) & pkt.word_en) {
311 if (efuse_one_byte_read(
312 padapter, addr,
313 &value) == true)
314 pkt.data[i*2] = value;
315 else
316 return false;
317 if (efuse_one_byte_read(
318 padapter,
319 addr + 1,
320 &value) == true)
321 pkt.data[i*2 + 1] =
322 value;
323 else
324 return false;
325 }
326 addr += 2;
327 }
328 }
329 }
330 if (addr != header_addr)
331 return false;
332 addr++;
333
334 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
335 if (BIT(i) & pkt.word_en) {
336 efuse_one_byte_write(padapter, addr, pkt.data[i*2]);
337 efuse_one_byte_write(padapter, addr+1,
338 pkt.data[i*2 + 1]);
339
340 if (efuse_one_byte_read(padapter, addr, &value)
341 == false)
342 ret = false;
343 else if (pkt.data[i*2] != value) {
344 ret = false;
345 if (0xFF == value)
346 efuse_one_byte_write(padapter, addr,
347 pkt.data[i * 2]);
348 }
349 if (efuse_one_byte_read(padapter, addr+1, &value) ==
350 false)
351 ret = false;
352 else if (pkt.data[i*2 + 1] != value) {
353 ret = false;
354 if (0xFF == value)
355 efuse_one_byte_write(padapter, addr+1,
356 pkt.data[i*2 + 1]);
357 }
358 }
359 addr += 2;
360 }
361 return ret;
362}
363
364u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
365 const u8 word_en, const u8 *data)
366{
367 u8 pg_header = 0;
368 u16 efuse_addr = 0, curr_size = 0;
369 u8 efuse_data, target_word_cnts = 0;
370 static int repeat_times;
371 int sub_repeat;
372 u8 bResult = true;
373
374
375 efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL);
376 if (efuse_data != 0x03)
377 return false;
378 pg_header = MAKE_EFUSE_HEADER(offset, word_en);
379 target_word_cnts = calculate_word_cnts(word_en);
380 repeat_times = 0;
381 efuse_addr = 0;
382 while (efuse_addr < efuse_available_max_size) {
383 curr_size = r8712_efuse_get_current_size(padapter);
384 if ((curr_size + 1 + target_word_cnts * 2) >
385 efuse_available_max_size)
386 return false;
387 efuse_addr = curr_size;
388 efuse_one_byte_write(padapter, efuse_addr, pg_header);
389 sub_repeat = 0;
390
391 while (efuse_one_byte_read(padapter, efuse_addr,
392 &efuse_data) == false) {
393 if (++sub_repeat > _REPEAT_THRESHOLD_) {
394 bResult = false;
395 break;
396 }
397 }
398 if ((sub_repeat > _REPEAT_THRESHOLD_) ||
399 (pg_header == efuse_data)) {
400
401 u8 i;
402
403
404 efuse_addr++;
405 for (i = 0; i < target_word_cnts*2; i++) {
406 efuse_one_byte_write(padapter,
407 efuse_addr + i,
408 *(data + i));
409 if (efuse_one_byte_read(padapter,
410 efuse_addr + i, &efuse_data) == false)
411 bResult = false;
412 else if (*(data+i) != efuse_data)
413 bResult = false;
414 }
415 break;
416 }
417
418 bResult = false;
419 if (0xFF == efuse_data)
420 return bResult;
421
422 if (!fix_header(padapter, efuse_data, efuse_addr))
423 return false;
424
425 if (++repeat_times > _REPEAT_THRESHOLD_)
426 break;
427
428 }
429 return bResult;
430}
431
432u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
433 u16 cnts, u8 *data)
434{
435 int i;
436 u8 res = true;
437
438 if (start_addr > EFUSE_MAX_SIZE)
439 return false;
440 if ((bRead == false) && ((start_addr + cnts) >
441 efuse_available_max_size))
442 return false;
443 if ((false == bRead) && (r8712_efuse_reg_init(padapter) == false))
444 return false;
445
446 for (i = 0; i < cnts; i++) {
447 if ((start_addr + i) > EFUSE_MAX_SIZE) {
448 res = false;
449 break;
450 }
451 res = efuse_one_byte_rw(padapter, bRead, start_addr + i,
452 data + i);
453 if ((false == bRead) && (false == res))
454 break;
455 }
456 if (false == bRead)
457 r8712_efuse_reg_uninit(padapter);
458 return res;
459}
460
461u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
462{
463 u8 offset, ret = true;
464 u8 pktdata[PGPKT_DATA_SIZE];
465 int i, idx;
466
467 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
468 return false;
469 if ((efuse_is_empty(padapter, &offset) == true) && (offset ==
470 true)) {
471 for (i = 0; i < cnts; i++)
472 data[i] = 0xFF;
473 return ret;
474 }
475 offset = (addr >> 3) & 0xF;
476 ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata);
477 i = addr & 0x7;
478 idx = 0;
479
480 do {
481 for (; i < PGPKT_DATA_SIZE; i++) {
482 data[idx++] = pktdata[i];
483 if (idx == cnts)
484 return ret;
485 }
486 offset++;
487 if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
488 ret = false;
489 i = 0;
490 } while (1);
491 return ret;
492}
493
494u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
495 u8 *data)
496{
497 u8 offset, word_en, empty;
498 u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE];
499 int i, j, idx;
500
501 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
502 return false;
503
504 empty = r8712_read8(padapter, EFUSE_CLK_CTRL);
505 if (empty != 0x03)
506 return false;
507 if (efuse_is_empty(padapter, &empty) == true) {
508 if (true == empty)
509 memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
510 } else
511 return false;
512 offset = (addr >> 3) & 0xF;
513 if (empty == false)
514 if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
515 return false;
516 word_en = 0xF;
517 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
518 i = addr & 0x7;
519 j = 0;
520 idx = 0;
521
522 if (i & 0x1) {
523
524 if (data[idx] != pktdata[i]) {
525 word_en &= ~BIT(i >> 1);
526 newdata[j++] = pktdata[i - 1];
527 newdata[j++] = data[idx];
528 }
529 i++;
530 idx++;
531 }
532 do {
533 for (; i < PGPKT_DATA_SIZE; i += 2) {
534 if ((cnts - idx) == 1) {
535 if (data[idx] != pktdata[i]) {
536 word_en &= ~BIT(i >> 1);
537 newdata[j++] = data[idx];
538 newdata[j++] = pktdata[1 + 1];
539 }
540 idx++;
541 break;
542 }
543
544 if ((data[idx] != pktdata[i]) || (data[idx+1] !=
545 pktdata[i+1])) {
546 word_en &= ~BIT(i >> 1);
547 newdata[j++] = data[idx];
548 newdata[j++] = data[idx + 1];
549 }
550 idx += 2;
551
552 if (idx == cnts)
553 break;
554 }
555
556 if (word_en != 0xF)
557 if (r8712_efuse_pg_packet_write(padapter, offset,
558 word_en, newdata) == false)
559 return false;
560 if (idx == cnts)
561 break;
562 offset++;
563 if (empty == false)
564 if (!r8712_efuse_pg_packet_read(padapter, offset,
565 pktdata))
566 return false;
567 i = 0;
568 j = 0;
569 word_en = 0xF;
570 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
571 } while (1);
572
573 return true;
574}
575