]>
Commit | Line | Data |
---|---|---|
2865d42c LF |
1 | /* |
2 | * rtl8712_efuse.c | |
3 | * | |
4 | * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. | |
5 | * Linux device driver for RTL8192SU | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of version 2 of the GNU General Public License as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program; if not, write to the Free Software Foundation, Inc., | |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
19 | * | |
20 | * Modifications for inclusion into the Linux staging tree are | |
21 | * Copyright(c) 2010 Larry Finger. All rights reserved. | |
22 | * | |
23 | * Contact information: | |
24 | * WLAN FAE <wlanfae@realtek.com>. | |
25 | * Larry Finger <Larry.Finger@lwfinger.net> | |
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 | /* reserve 3 bytes for HW stop read */ | |
36 | static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/; | |
37 | ||
38 | static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn) | |
39 | { | |
40 | u8 tmpu8 = 0; | |
41 | ||
1ca96884 | 42 | if (bPowerOn) { |
2865d42c LF |
43 | /* -----------------e-fuse pwr & clk reg ctrl --------------- |
44 | * Enable LDOE25 Macro Block | |
45 | */ | |
46 | tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3); | |
47 | tmpu8 |= 0x80; | |
48 | r8712_write8(padapter, EFUSE_TEST + 3, tmpu8); | |
49 | msleep(20); /* for some platform , need some delay time */ | |
50 | /* Change Efuse Clock for write action to 40MHZ */ | |
51 | r8712_write8(padapter, EFUSE_CLK_CTRL, 0x03); | |
52 | msleep(20); /* for some platform , need some delay time */ | |
53 | } else { | |
54 | /* -----------------e-fuse pwr & clk reg ctrl ----------------- | |
55 | * Disable LDOE25 Macro Block | |
56 | */ | |
57 | tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3); | |
58 | tmpu8 &= 0x7F; | |
59 | r8712_write8(padapter, EFUSE_TEST + 3, tmpu8); | |
60 | /* Change Efuse Clock for write action to 500K */ | |
61 | r8712_write8(padapter, EFUSE_CLK_CTRL, 0x02); | |
62 | } | |
63 | } | |
64 | ||
65 | /* | |
66 | * Before write E-Fuse, this function must be called. | |
67 | */ | |
68 | u8 r8712_efuse_reg_init(struct _adapter *padapter) | |
69 | { | |
70 | return true; | |
71 | } | |
72 | ||
73 | void r8712_efuse_reg_uninit(struct _adapter *padapter) | |
74 | { | |
75 | efuse_reg_ctrl(padapter, false); | |
76 | } | |
77 | ||
78 | static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data) | |
79 | { | |
80 | u8 tmpidx = 0, bResult; | |
81 | ||
82 | /* -----------------e-fuse reg ctrl --------------------------------- */ | |
4ef2de5a LB |
83 | r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */ |
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); /* read cmd */ | |
2865d42c | 87 | /* wait for complete */ |
4ef2de5a LB |
88 | while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) && |
89 | (tmpidx < 100)) | |
2865d42c LF |
90 | tmpidx++; |
91 | if (tmpidx < 100) { | |
92 | *data = r8712_read8(padapter, EFUSE_CTRL); | |
93 | bResult = true; | |
94 | } else { | |
95 | *data = 0xff; | |
96 | bResult = false; | |
97 | } | |
98 | return bResult; | |
99 | } | |
100 | ||
101 | static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data) | |
102 | { | |
103 | u8 tmpidx = 0, bResult; | |
104 | ||
105 | /* -----------------e-fuse reg ctrl -------------------------------- */ | |
4ef2de5a LB |
106 | r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */ |
107 | r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | | |
108 | (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC)); | |
2865d42c | 109 | r8712_write8(padapter, EFUSE_CTRL, data); /* data */ |
4ef2de5a | 110 | r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */ |
2865d42c | 111 | /* wait for complete */ |
4ef2de5a LB |
112 | while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) && |
113 | (tmpidx < 100)) | |
2865d42c LF |
114 | tmpidx++; |
115 | if (tmpidx < 100) | |
116 | bResult = true; | |
117 | else | |
118 | bResult = false; | |
119 | return bResult; | |
120 | } | |
121 | ||
122 | static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr, | |
123 | u8 *data) | |
124 | { | |
125 | u8 tmpidx = 0, tmpv8 = 0, bResult; | |
126 | ||
127 | /* -----------------e-fuse reg ctrl --------------------------------- */ | |
4ef2de5a | 128 | r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */ |
2865d42c LF |
129 | tmpv8 = ((u8)((addr >> 8) & 0x03)) | |
130 | (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC); | |
4ef2de5a | 131 | r8712_write8(padapter, EFUSE_CTRL + 2, tmpv8); |
1ca96884 | 132 | if (bRead) { |
4ef2de5a LB |
133 | r8712_write8(padapter, EFUSE_CTRL + 3, 0x72); /* read cmd */ |
134 | while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) && | |
2865d42c LF |
135 | (tmpidx < 100)) |
136 | tmpidx++; | |
137 | if (tmpidx < 100) { | |
138 | *data = r8712_read8(padapter, EFUSE_CTRL); | |
139 | bResult = true; | |
140 | } else { | |
141 | *data = 0; | |
142 | bResult = false; | |
143 | } | |
144 | } else { | |
145 | r8712_write8(padapter, EFUSE_CTRL, *data); /* data */ | |
4ef2de5a LB |
146 | r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */ |
147 | while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) && | |
2865d42c LF |
148 | (tmpidx < 100)) |
149 | tmpidx++; | |
150 | if (tmpidx < 100) | |
151 | bResult = true; | |
152 | else | |
153 | bResult = false; | |
154 | } | |
155 | return bResult; | |
156 | } | |
157 | ||
158 | static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty) | |
159 | { | |
160 | u8 value, ret = true; | |
161 | ||
162 | /* read one byte to check if E-Fuse is empty */ | |
1ca96884 | 163 | if (efuse_one_byte_rw(padapter, true, 0, &value)) { |
2865d42c LF |
164 | if (0xFF == value) |
165 | *empty = true; | |
166 | else | |
167 | *empty = false; | |
168a2c10 | 168 | } else { |
2865d42c | 169 | ret = false; |
168a2c10 | 170 | } |
2865d42c LF |
171 | return ret; |
172 | } | |
173 | ||
174 | void r8712_efuse_change_max_size(struct _adapter *padapter) | |
175 | { | |
176 | u16 pre_pg_data_saddr = 0x1FB; | |
177 | u16 i; | |
178 | u16 pre_pg_data_size = 5; | |
179 | u8 pre_pg_data[5]; | |
180 | ||
181 | for (i = 0; i < pre_pg_data_size; i++) | |
182 | efuse_one_byte_read(padapter, pre_pg_data_saddr + i, | |
183 | &pre_pg_data[i]); | |
184 | if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) && | |
185 | (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) && | |
186 | (pre_pg_data[4] == 0x0C)) | |
187 | efuse_available_max_size -= pre_pg_data_size; | |
188 | } | |
189 | ||
190 | int r8712_efuse_get_max_size(struct _adapter *padapter) | |
191 | { | |
192 | return efuse_available_max_size; | |
193 | } | |
194 | ||
195 | static u8 calculate_word_cnts(const u8 word_en) | |
196 | { | |
197 | u8 word_cnts = 0; | |
198 | u8 word_idx; | |
199 | ||
200 | for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) | |
201 | if (!(word_en & BIT(word_idx))) | |
202 | word_cnts++; /* 0 : write enable */ | |
203 | return word_cnts; | |
204 | } | |
205 | ||
206 | static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata, | |
207 | u8 *targetdata) | |
208 | { | |
209 | u8 tmpindex = 0; | |
210 | u8 word_idx, byte_idx; | |
211 | ||
212 | for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) { | |
4ef2de5a | 213 | if (!(word_en & BIT(word_idx))) { |
2865d42c LF |
214 | byte_idx = word_idx * 2; |
215 | targetdata[byte_idx] = sourdata[tmpindex++]; | |
216 | targetdata[byte_idx + 1] = sourdata[tmpindex++]; | |
217 | } | |
218 | } | |
219 | } | |
220 | ||
221 | u16 r8712_efuse_get_current_size(struct _adapter *padapter) | |
222 | { | |
223 | int bContinual = true; | |
224 | u16 efuse_addr = 0; | |
e29d3ebc | 225 | u8 hworden = 0; |
2865d42c LF |
226 | u8 efuse_data, word_cnts = 0; |
227 | ||
228 | while (bContinual && efuse_one_byte_read(padapter, efuse_addr, | |
229 | &efuse_data) && (efuse_addr < efuse_available_max_size)) { | |
230 | if (efuse_data != 0xFF) { | |
2865d42c LF |
231 | hworden = efuse_data & 0x0F; |
232 | word_cnts = calculate_word_cnts(hworden); | |
233 | /* read next header */ | |
234 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; | |
168a2c10 | 235 | } else { |
77e73e8c | 236 | bContinual = false; |
168a2c10 | 237 | } |
2865d42c LF |
238 | } |
239 | return efuse_addr; | |
240 | } | |
241 | ||
242 | u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data) | |
243 | { | |
244 | u8 hoffset = 0, hworden = 0, word_cnts = 0; | |
245 | u16 efuse_addr = 0; | |
246 | u8 efuse_data; | |
247 | u8 tmpidx = 0; | |
248 | u8 tmpdata[PGPKT_DATA_SIZE]; | |
249 | u8 ret = true; | |
250 | ||
251 | if (data == NULL) | |
252 | return false; | |
253 | if (offset > 0x0f) | |
254 | return false; | |
4ef2de5a | 255 | memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE); |
2865d42c | 256 | while (efuse_addr < efuse_available_max_size) { |
1ca96884 | 257 | if (efuse_one_byte_read(padapter, efuse_addr, &efuse_data)) { |
2865d42c LF |
258 | if (efuse_data == 0xFF) |
259 | break; | |
260 | hoffset = (efuse_data >> 4) & 0x0F; | |
261 | hworden = efuse_data & 0x0F; | |
262 | word_cnts = calculate_word_cnts(hworden); | |
263 | if (hoffset == offset) { | |
264 | memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); | |
265 | for (tmpidx = 0; tmpidx < word_cnts * 2; | |
266 | tmpidx++) { | |
267 | if (efuse_one_byte_read(padapter, | |
4ef2de5a LB |
268 | efuse_addr + 1 + tmpidx, |
269 | &efuse_data)) { | |
2865d42c | 270 | tmpdata[tmpidx] = efuse_data; |
168a2c10 | 271 | } else { |
2865d42c | 272 | ret = false; |
168a2c10 | 273 | } |
2865d42c LF |
274 | } |
275 | pgpacket_copy_data(hworden, tmpdata, data); | |
276 | } | |
4ef2de5a | 277 | efuse_addr += 1 + (word_cnts * 2); |
2865d42c LF |
278 | } else { |
279 | ret = false; | |
280 | break; | |
281 | } | |
282 | } | |
283 | return ret; | |
284 | } | |
285 | ||
286 | static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr) | |
287 | { | |
288 | struct PGPKT_STRUCT pkt; | |
289 | u8 offset, word_en, value; | |
290 | u16 addr; | |
291 | int i; | |
292 | u8 ret = true; | |
293 | ||
294 | pkt.offset = GET_EFUSE_OFFSET(header); | |
295 | pkt.word_en = GET_EFUSE_WORD_EN(header); | |
296 | addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2; | |
297 | if (addr > efuse_available_max_size) | |
298 | return false; | |
299 | /* retrieve original data */ | |
300 | addr = 0; | |
301 | while (addr < header_addr) { | |
1ca96884 | 302 | if (!efuse_one_byte_read(padapter, addr++, &value)) { |
2865d42c LF |
303 | ret = false; |
304 | break; | |
305 | } | |
306 | offset = GET_EFUSE_OFFSET(value); | |
307 | word_en = GET_EFUSE_WORD_EN(value); | |
308 | if (pkt.offset != offset) { | |
4ef2de5a | 309 | addr += calculate_word_cnts(word_en) * 2; |
2865d42c LF |
310 | continue; |
311 | } | |
312 | for (i = 0; i < PGPKG_MAX_WORDS; i++) { | |
0aeb623d AB |
313 | if (BIT(i) & word_en) { |
314 | if (BIT(i) & pkt.word_en) { | |
315 | if (efuse_one_byte_read( | |
316 | padapter, addr, | |
1ca96884 | 317 | &value)) |
4ef2de5a | 318 | pkt.data[i * 2] = value; |
0aeb623d AB |
319 | else |
320 | return false; | |
321 | if (efuse_one_byte_read( | |
322 | padapter, | |
323 | addr + 1, | |
1ca96884 | 324 | &value)) |
4ef2de5a | 325 | pkt.data[i * 2 + 1] = |
0aeb623d AB |
326 | value; |
327 | else | |
328 | return false; | |
329 | } | |
330 | addr += 2; | |
2865d42c | 331 | } |
2865d42c LF |
332 | } |
333 | } | |
334 | if (addr != header_addr) | |
335 | return false; | |
336 | addr++; | |
337 | /* fill original data */ | |
338 | for (i = 0; i < PGPKG_MAX_WORDS; i++) { | |
0aeb623d | 339 | if (BIT(i) & pkt.word_en) { |
4ef2de5a LB |
340 | efuse_one_byte_write(padapter, addr, pkt.data[i * 2]); |
341 | efuse_one_byte_write(padapter, addr + 1, | |
342 | pkt.data[i * 2 + 1]); | |
0aeb623d | 343 | /* additional check */ |
168a2c10 | 344 | if (!efuse_one_byte_read(padapter, addr, &value)) { |
0aeb623d | 345 | ret = false; |
4ef2de5a | 346 | } else if (pkt.data[i * 2] != value) { |
0aeb623d AB |
347 | ret = false; |
348 | if (0xFF == value) /* write again */ | |
349 | efuse_one_byte_write(padapter, addr, | |
350 | pkt.data[i * 2]); | |
351 | } | |
4ef2de5a | 352 | if (!efuse_one_byte_read(padapter, addr + 1, &value)) { |
0aeb623d | 353 | ret = false; |
4ef2de5a | 354 | } else if (pkt.data[i * 2 + 1] != value) { |
0aeb623d AB |
355 | ret = false; |
356 | if (0xFF == value) /* write again */ | |
4ef2de5a LB |
357 | efuse_one_byte_write(padapter, addr + 1, |
358 | pkt.data[i * 2 + | |
359 | 1]); | |
0aeb623d | 360 | } |
2865d42c LF |
361 | } |
362 | addr += 2; | |
363 | } | |
364 | return ret; | |
365 | } | |
366 | ||
367 | u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset, | |
368 | const u8 word_en, const u8 *data) | |
369 | { | |
370 | u8 pg_header = 0; | |
371 | u16 efuse_addr = 0, curr_size = 0; | |
372 | u8 efuse_data, target_word_cnts = 0; | |
373 | static int repeat_times; | |
374 | int sub_repeat; | |
375 | u8 bResult = true; | |
376 | ||
377 | /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */ | |
378 | efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL); | |
379 | if (efuse_data != 0x03) | |
380 | return false; | |
381 | pg_header = MAKE_EFUSE_HEADER(offset, word_en); | |
382 | target_word_cnts = calculate_word_cnts(word_en); | |
383 | repeat_times = 0; | |
384 | efuse_addr = 0; | |
385 | while (efuse_addr < efuse_available_max_size) { | |
386 | curr_size = r8712_efuse_get_current_size(padapter); | |
387 | if ((curr_size + 1 + target_word_cnts * 2) > | |
388 | efuse_available_max_size) | |
389 | return false; /*target_word_cnts + pg header(1 byte)*/ | |
390 | efuse_addr = curr_size; /* current size is also the last addr*/ | |
391 | efuse_one_byte_write(padapter, efuse_addr, pg_header); /*hdr*/ | |
392 | sub_repeat = 0; | |
393 | /* check if what we read is what we write */ | |
1ca96884 LB |
394 | while (!efuse_one_byte_read(padapter, efuse_addr, |
395 | &efuse_data)) { | |
2865d42c LF |
396 | if (++sub_repeat > _REPEAT_THRESHOLD_) { |
397 | bResult = false; /* continue to blind write */ | |
398 | break; /* continue to blind write */ | |
399 | } | |
400 | } | |
401 | if ((sub_repeat > _REPEAT_THRESHOLD_) || | |
402 | (pg_header == efuse_data)) { | |
403 | /* write header ok OR can't check header(creep) */ | |
404 | u8 i; | |
405 | ||
406 | /* go to next address */ | |
407 | efuse_addr++; | |
4ef2de5a | 408 | for (i = 0; i < target_word_cnts * 2; i++) { |
2865d42c LF |
409 | efuse_one_byte_write(padapter, |
410 | efuse_addr + i, | |
411 | *(data + i)); | |
1ca96884 LB |
412 | if (!efuse_one_byte_read(padapter, |
413 | efuse_addr + i, | |
414 | &efuse_data)) | |
2865d42c | 415 | bResult = false; |
4ef2de5a | 416 | else if (*(data + i) != efuse_data) /* fail */ |
2865d42c LF |
417 | bResult = false; |
418 | } | |
419 | break; | |
2865d42c | 420 | } |
a15522c0 SP |
421 | /* write header fail */ |
422 | bResult = false; | |
423 | if (0xFF == efuse_data) | |
424 | return bResult; /* nothing damaged. */ | |
425 | /* call rescue procedure */ | |
426 | if (!fix_header(padapter, efuse_data, efuse_addr)) | |
427 | return false; /* rescue fail */ | |
428 | ||
429 | if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */ | |
430 | break; | |
431 | /* otherwise, take another risk... */ | |
2865d42c LF |
432 | } |
433 | return bResult; | |
434 | } | |
435 | ||
436 | u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr, | |
437 | u16 cnts, u8 *data) | |
438 | { | |
439 | int i; | |
859171ca | 440 | u8 res = true; |
2865d42c LF |
441 | |
442 | if (start_addr > EFUSE_MAX_SIZE) | |
443 | return false; | |
1ca96884 | 444 | if (!bRead && ((start_addr + cnts) > |
2865d42c LF |
445 | efuse_available_max_size)) |
446 | return false; | |
1ca96884 | 447 | if (!bRead && !r8712_efuse_reg_init(padapter)) |
2865d42c LF |
448 | return false; |
449 | /* -----------------e-fuse one byte read / write ---------------------*/ | |
450 | for (i = 0; i < cnts; i++) { | |
451 | if ((start_addr + i) > EFUSE_MAX_SIZE) { | |
452 | res = false; | |
453 | break; | |
454 | } | |
455 | res = efuse_one_byte_rw(padapter, bRead, start_addr + i, | |
456 | data + i); | |
1ca96884 | 457 | if (!bRead && !res) |
2865d42c LF |
458 | break; |
459 | } | |
1ca96884 | 460 | if (!bRead) |
2865d42c LF |
461 | r8712_efuse_reg_uninit(padapter); |
462 | return res; | |
463 | } | |
464 | ||
465 | u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data) | |
466 | { | |
467 | u8 offset, ret = true; | |
468 | u8 pktdata[PGPKT_DATA_SIZE]; | |
469 | int i, idx; | |
470 | ||
471 | if ((addr + cnts) > EFUSE_MAP_MAX_SIZE) | |
472 | return false; | |
1ca96884 | 473 | if (efuse_is_empty(padapter, &offset) && offset) { |
2865d42c LF |
474 | for (i = 0; i < cnts; i++) |
475 | data[i] = 0xFF; | |
476 | return ret; | |
477 | } | |
478 | offset = (addr >> 3) & 0xF; | |
479 | ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata); | |
480 | i = addr & 0x7; /* pktdata index */ | |
481 | idx = 0; /* data index */ | |
482 | ||
483 | do { | |
484 | for (; i < PGPKT_DATA_SIZE; i++) { | |
485 | data[idx++] = pktdata[i]; | |
486 | if (idx == cnts) | |
487 | return ret; | |
488 | } | |
489 | offset++; | |
490 | if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata)) | |
491 | ret = false; | |
492 | i = 0; | |
493 | } while (1); | |
494 | return ret; | |
495 | } | |
496 | ||
497 | u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts, | |
498 | u8 *data) | |
499 | { | |
500 | u8 offset, word_en, empty; | |
501 | u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE]; | |
502 | int i, j, idx; | |
503 | ||
504 | if ((addr + cnts) > EFUSE_MAP_MAX_SIZE) | |
505 | return false; | |
506 | /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */ | |
507 | empty = r8712_read8(padapter, EFUSE_CLK_CTRL); | |
508 | if (empty != 0x03) | |
509 | return false; | |
1ca96884 LB |
510 | if (efuse_is_empty(padapter, &empty)) { |
511 | if (empty) | |
2865d42c | 512 | memset(pktdata, 0xFF, PGPKT_DATA_SIZE); |
168a2c10 | 513 | } else { |
2865d42c | 514 | return false; |
168a2c10 | 515 | } |
2865d42c | 516 | offset = (addr >> 3) & 0xF; |
1ca96884 | 517 | if (!empty) |
2865d42c LF |
518 | if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata)) |
519 | return false; | |
520 | word_en = 0xF; | |
521 | memset(newdata, 0xFF, PGPKT_DATA_SIZE); | |
522 | i = addr & 0x7; /* pktdata index */ | |
523 | j = 0; /* newdata index */ | |
524 | idx = 0; /* data index */ | |
525 | ||
526 | if (i & 0x1) { | |
527 | /* odd start */ | |
528 | if (data[idx] != pktdata[i]) { | |
529 | word_en &= ~BIT(i >> 1); | |
530 | newdata[j++] = pktdata[i - 1]; | |
531 | newdata[j++] = data[idx]; | |
532 | } | |
533 | i++; | |
534 | idx++; | |
535 | } | |
536 | do { | |
537 | for (; i < PGPKT_DATA_SIZE; i += 2) { | |
538 | if ((cnts - idx) == 1) { | |
539 | if (data[idx] != pktdata[i]) { | |
540 | word_en &= ~BIT(i >> 1); | |
541 | newdata[j++] = data[idx]; | |
542 | newdata[j++] = pktdata[1 + 1]; | |
543 | } | |
544 | idx++; | |
545 | break; | |
2865d42c | 546 | } |
a15522c0 | 547 | |
4ef2de5a LB |
548 | if ((data[idx] != pktdata[i]) || (data[idx + 1] != |
549 | pktdata[i + 1])) { | |
a15522c0 SP |
550 | word_en &= ~BIT(i >> 1); |
551 | newdata[j++] = data[idx]; | |
552 | newdata[j++] = data[idx + 1]; | |
553 | } | |
554 | idx += 2; | |
555 | ||
2865d42c LF |
556 | if (idx == cnts) |
557 | break; | |
558 | } | |
559 | ||
560 | if (word_en != 0xF) | |
1ca96884 LB |
561 | if (!r8712_efuse_pg_packet_write(padapter, offset, |
562 | word_en, newdata)) | |
2865d42c LF |
563 | return false; |
564 | if (idx == cnts) | |
565 | break; | |
566 | offset++; | |
1ca96884 | 567 | if (!empty) |
2865d42c LF |
568 | if (!r8712_efuse_pg_packet_read(padapter, offset, |
569 | pktdata)) | |
570 | return false; | |
571 | i = 0; | |
572 | j = 0; | |
573 | word_en = 0xF; | |
574 | memset(newdata, 0xFF, PGPKT_DATA_SIZE); | |
575 | } while (1); | |
576 | ||
577 | return true; | |
578 | } |