4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
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.
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
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
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>.
25 * Larry Finger <Larry.Finger@lwfinger.net>
27 ******************************************************************************/
29 #define _RTL8712_EFUSE_C_
31 #include "osdep_service.h"
32 #include "drv_types.h"
33 #include "rtl8712_efuse.h"
35 /* reserve 3 bytes for HW stop read */
36 static int efuse_available_max_size
= EFUSE_MAX_SIZE
- 3 /*0x1FD*/;
38 static void efuse_reg_ctrl(struct _adapter
*padapter
, u8 bPowerOn
)
43 /* -----------------e-fuse pwr & clk reg ctrl ---------------
44 * Enable LDOE25 Macro Block
46 tmpu8
= r8712_read8(padapter
, EFUSE_TEST
+ 3);
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 */
54 /* -----------------e-fuse pwr & clk reg ctrl -----------------
55 * Disable LDOE25 Macro Block
57 tmpu8
= r8712_read8(padapter
, EFUSE_TEST
+ 3);
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);
66 * Before write E-Fuse, this function must be called.
68 u8
r8712_efuse_reg_init(struct _adapter
*padapter
)
73 void r8712_efuse_reg_uninit(struct _adapter
*padapter
)
75 efuse_reg_ctrl(padapter
, false);
78 static u8
efuse_one_byte_read(struct _adapter
*padapter
, u16 addr
, u8
*data
)
80 u8 tmpidx
= 0, bResult
;
82 /* -----------------e-fuse reg ctrl --------------------------------- */
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 */
87 /* wait for complete */
88 while (!(0x80 & r8712_read8(padapter
, EFUSE_CTRL
+ 3)) &&
92 *data
= r8712_read8(padapter
, EFUSE_CTRL
);
101 static u8
efuse_one_byte_write(struct _adapter
*padapter
, u16 addr
, u8 data
)
103 u8 tmpidx
= 0, bResult
;
105 /* -----------------e-fuse reg ctrl -------------------------------- */
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));
109 r8712_write8(padapter
, EFUSE_CTRL
, data
); /* data */
110 r8712_write8(padapter
, EFUSE_CTRL
+ 3, 0xF2); /* write cmd */
111 /* wait for complete */
112 while ((0x80 & r8712_read8(padapter
, EFUSE_CTRL
+ 3)) &&
122 static u8
efuse_one_byte_rw(struct _adapter
*padapter
, u8 bRead
, u16 addr
,
125 u8 tmpidx
= 0, tmpv8
= 0, bResult
;
127 /* -----------------e-fuse reg ctrl --------------------------------- */
128 r8712_write8(padapter
, EFUSE_CTRL
+ 1, (u8
)(addr
& 0xFF)); /* address */
129 tmpv8
= ((u8
)((addr
>> 8) & 0x03)) |
130 (r8712_read8(padapter
, EFUSE_CTRL
+ 2) & 0xFC);
131 r8712_write8(padapter
, EFUSE_CTRL
+ 2, tmpv8
);
133 r8712_write8(padapter
, EFUSE_CTRL
+ 3, 0x72); /* read cmd */
134 while (!(0x80 & r8712_read8(padapter
, EFUSE_CTRL
+ 3)) &&
138 *data
= r8712_read8(padapter
, EFUSE_CTRL
);
145 r8712_write8(padapter
, EFUSE_CTRL
, *data
); /* data */
146 r8712_write8(padapter
, EFUSE_CTRL
+ 3, 0xF2); /* write cmd */
147 while ((0x80 & r8712_read8(padapter
, EFUSE_CTRL
+ 3)) &&
158 static u8
efuse_is_empty(struct _adapter
*padapter
, u8
*empty
)
160 u8 value
, ret
= true;
162 /* read one byte to check if E-Fuse is empty */
163 if (efuse_one_byte_rw(padapter
, true, 0, &value
)) {
174 void r8712_efuse_change_max_size(struct _adapter
*padapter
)
176 u16 pre_pg_data_saddr
= 0x1FB;
178 u16 pre_pg_data_size
= 5;
181 for (i
= 0; i
< pre_pg_data_size
; i
++)
182 efuse_one_byte_read(padapter
, pre_pg_data_saddr
+ 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
;
190 int r8712_efuse_get_max_size(struct _adapter
*padapter
)
192 return efuse_available_max_size
;
195 static u8
calculate_word_cnts(const u8 word_en
)
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 */
206 static void pgpacket_copy_data(const u8 word_en
, const u8
*sourdata
,
210 u8 word_idx
, byte_idx
;
212 for (word_idx
= 0; word_idx
< PGPKG_MAX_WORDS
; word_idx
++) {
213 if (!(word_en
& BIT(word_idx
))) {
214 byte_idx
= word_idx
* 2;
215 targetdata
[byte_idx
] = sourdata
[tmpindex
++];
216 targetdata
[byte_idx
+ 1] = sourdata
[tmpindex
++];
221 u16
r8712_efuse_get_current_size(struct _adapter
*padapter
)
223 int bContinual
= true;
226 u8 efuse_data
, word_cnts
= 0;
228 while (bContinual
&& efuse_one_byte_read(padapter
, efuse_addr
,
229 &efuse_data
) && (efuse_addr
< efuse_available_max_size
)) {
230 if (efuse_data
!= 0xFF) {
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;
242 u8
r8712_efuse_pg_packet_read(struct _adapter
*padapter
, u8 offset
, u8
*data
)
244 u8 hoffset
= 0, hworden
= 0, word_cnts
= 0;
248 u8 tmpdata
[PGPKT_DATA_SIZE
];
255 memset(data
, 0xFF, sizeof(u8
) * PGPKT_DATA_SIZE
);
256 while (efuse_addr
< efuse_available_max_size
) {
257 if (efuse_one_byte_read(padapter
, efuse_addr
, &efuse_data
)) {
258 if (efuse_data
== 0xFF)
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;
267 if (efuse_one_byte_read(padapter
,
268 efuse_addr
+ 1 + tmpidx
,
270 tmpdata
[tmpidx
] = efuse_data
;
275 pgpacket_copy_data(hworden
, tmpdata
, data
);
277 efuse_addr
+= 1 + (word_cnts
* 2);
286 static u8
fix_header(struct _adapter
*padapter
, u8 header
, u16 header_addr
)
288 struct PGPKT_STRUCT pkt
;
289 u8 offset
, word_en
, value
;
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
)
299 /* retrieve original data */
301 while (addr
< header_addr
) {
302 if (!efuse_one_byte_read(padapter
, addr
++, &value
)) {
306 offset
= GET_EFUSE_OFFSET(value
);
307 word_en
= GET_EFUSE_WORD_EN(value
);
308 if (pkt
.offset
!= offset
) {
309 addr
+= calculate_word_cnts(word_en
) * 2;
312 for (i
= 0; i
< PGPKG_MAX_WORDS
; i
++) {
313 if (BIT(i
) & word_en
) {
314 if (BIT(i
) & pkt
.word_en
) {
315 if (efuse_one_byte_read(
318 pkt
.data
[i
* 2] = value
;
321 if (efuse_one_byte_read(
325 pkt
.data
[i
* 2 + 1] =
334 if (addr
!= header_addr
)
337 /* fill original data */
338 for (i
= 0; i
< PGPKG_MAX_WORDS
; i
++) {
339 if (BIT(i
) & pkt
.word_en
) {
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]);
343 /* additional check */
344 if (!efuse_one_byte_read(padapter
, addr
, &value
)) {
346 } else if (pkt
.data
[i
* 2] != value
) {
348 if (value
== 0xFF) /* write again */
349 efuse_one_byte_write(padapter
, addr
,
352 if (!efuse_one_byte_read(padapter
, addr
+ 1, &value
)) {
354 } else if (pkt
.data
[i
* 2 + 1] != value
) {
356 if (value
== 0xFF) /* write again */
357 efuse_one_byte_write(padapter
, addr
+ 1,
367 u8
r8712_efuse_pg_packet_write(struct _adapter
*padapter
, const u8 offset
,
368 const u8 word_en
, const u8
*data
)
371 u16 efuse_addr
= 0, curr_size
= 0;
372 u8 efuse_data
, target_word_cnts
= 0;
373 static int repeat_times
;
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)
381 pg_header
= MAKE_EFUSE_HEADER(offset
, word_en
);
382 target_word_cnts
= calculate_word_cnts(word_en
);
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*/
393 /* check if what we read is what we write */
394 while (!efuse_one_byte_read(padapter
, efuse_addr
,
396 if (++sub_repeat
> _REPEAT_THRESHOLD_
) {
397 bResult
= false; /* continue to blind write */
398 break; /* continue to blind write */
401 if ((sub_repeat
> _REPEAT_THRESHOLD_
) ||
402 (pg_header
== efuse_data
)) {
403 /* write header ok OR can't check header(creep) */
406 /* go to next address */
408 for (i
= 0; i
< target_word_cnts
* 2; i
++) {
409 efuse_one_byte_write(padapter
,
412 if (!efuse_one_byte_read(padapter
,
416 else if (*(data
+ i
) != efuse_data
) /* fail */
421 /* write header fail */
423 if (efuse_data
== 0xFF)
424 return bResult
; /* nothing damaged. */
425 /* call rescue procedure */
426 if (!fix_header(padapter
, efuse_data
, efuse_addr
))
427 return false; /* rescue fail */
429 if (++repeat_times
> _REPEAT_THRESHOLD_
) /* fail */
431 /* otherwise, take another risk... */
436 u8
r8712_efuse_access(struct _adapter
*padapter
, u8 bRead
, u16 start_addr
,
442 if (start_addr
> EFUSE_MAX_SIZE
)
444 if (!bRead
&& ((start_addr
+ cnts
) >
445 efuse_available_max_size
))
447 if (!bRead
&& !r8712_efuse_reg_init(padapter
))
449 /* -----------------e-fuse one byte read / write ---------------------*/
450 for (i
= 0; i
< cnts
; i
++) {
451 if ((start_addr
+ i
) > EFUSE_MAX_SIZE
) {
455 res
= efuse_one_byte_rw(padapter
, bRead
, start_addr
+ i
,
461 r8712_efuse_reg_uninit(padapter
);
465 u8
r8712_efuse_map_read(struct _adapter
*padapter
, u16 addr
, u16 cnts
, u8
*data
)
467 u8 offset
, ret
= true;
468 u8 pktdata
[PGPKT_DATA_SIZE
];
471 if ((addr
+ cnts
) > EFUSE_MAP_MAX_SIZE
)
473 if (efuse_is_empty(padapter
, &offset
) && offset
) {
474 for (i
= 0; i
< cnts
; i
++)
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 */
484 for (; i
< PGPKT_DATA_SIZE
; i
++) {
485 data
[idx
++] = pktdata
[i
];
490 if (!r8712_efuse_pg_packet_read(padapter
, offset
, pktdata
))
497 u8
r8712_efuse_map_write(struct _adapter
*padapter
, u16 addr
, u16 cnts
,
500 u8 offset
, word_en
, empty
;
501 u8 pktdata
[PGPKT_DATA_SIZE
], newdata
[PGPKT_DATA_SIZE
];
504 if ((addr
+ cnts
) > EFUSE_MAP_MAX_SIZE
)
506 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
507 empty
= r8712_read8(padapter
, EFUSE_CLK_CTRL
);
510 if (efuse_is_empty(padapter
, &empty
)) {
512 memset(pktdata
, 0xFF, PGPKT_DATA_SIZE
);
516 offset
= (addr
>> 3) & 0xF;
518 if (!r8712_efuse_pg_packet_read(padapter
, offset
, pktdata
))
521 memset(newdata
, 0xFF, PGPKT_DATA_SIZE
);
522 i
= addr
& 0x7; /* pktdata index */
523 j
= 0; /* newdata index */
524 idx
= 0; /* data index */
528 if (data
[idx
] != pktdata
[i
]) {
529 word_en
&= ~BIT(i
>> 1);
530 newdata
[j
++] = pktdata
[i
- 1];
531 newdata
[j
++] = data
[idx
];
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];
548 if ((data
[idx
] != pktdata
[i
]) || (data
[idx
+ 1] !=
550 word_en
&= ~BIT(i
>> 1);
551 newdata
[j
++] = data
[idx
];
552 newdata
[j
++] = data
[idx
+ 1];
561 if (!r8712_efuse_pg_packet_write(padapter
, offset
,
568 if (!r8712_efuse_pg_packet_read(padapter
, offset
,
574 memset(newdata
, 0xFF, PGPKT_DATA_SIZE
);
This page took 0.045057 seconds and 5 git commands to generate.