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
)
42 if (true == 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)) && (tmpidx
< 100))
91 *data
= r8712_read8(padapter
, EFUSE_CTRL
);
100 static u8
efuse_one_byte_write(struct _adapter
*padapter
, u16 addr
, u8 data
)
102 u8 tmpidx
= 0, bResult
;
104 /* -----------------e-fuse reg ctrl -------------------------------- */
105 r8712_write8(padapter
, EFUSE_CTRL
+1, (u8
)(addr
&0xFF)); /* address */
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
); /* data */
109 r8712_write8(padapter
, EFUSE_CTRL
+3, 0xF2); /* write cmd */
110 /* wait for complete */
111 while ((0x80 & r8712_read8(padapter
, EFUSE_CTRL
+3)) && (tmpidx
< 100))
120 static u8
efuse_one_byte_rw(struct _adapter
*padapter
, u8 bRead
, u16 addr
,
123 u8 tmpidx
= 0, tmpv8
= 0, bResult
;
125 /* -----------------e-fuse reg ctrl --------------------------------- */
126 r8712_write8(padapter
, EFUSE_CTRL
+1, (u8
)(addr
&0xFF)); /* address */
127 tmpv8
= ((u8
)((addr
>> 8) & 0x03)) |
128 (r8712_read8(padapter
, EFUSE_CTRL
+ 2) & 0xFC);
129 r8712_write8(padapter
, EFUSE_CTRL
+2, tmpv8
);
131 r8712_write8(padapter
, EFUSE_CTRL
+3, 0x72); /* read cmd */
132 while (!(0x80 & r8712_read8(padapter
, EFUSE_CTRL
+3)) &&
136 *data
= r8712_read8(padapter
, EFUSE_CTRL
);
143 r8712_write8(padapter
, EFUSE_CTRL
, *data
); /* data */
144 r8712_write8(padapter
, EFUSE_CTRL
+3, 0xF2); /* write cmd */
145 while ((0x80 & r8712_read8(padapter
, EFUSE_CTRL
+3)) &&
156 static u8
efuse_is_empty(struct _adapter
*padapter
, u8
*empty
)
158 u8 value
, ret
= true;
160 /* read one byte to check if E-Fuse is empty */
161 if (efuse_one_byte_rw(padapter
, true, 0, &value
) == true) {
171 void r8712_efuse_change_max_size(struct _adapter
*padapter
)
173 u16 pre_pg_data_saddr
= 0x1FB;
175 u16 pre_pg_data_size
= 5;
178 for (i
= 0; i
< pre_pg_data_size
; i
++)
179 efuse_one_byte_read(padapter
, pre_pg_data_saddr
+ 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
;
187 int r8712_efuse_get_max_size(struct _adapter
*padapter
)
189 return efuse_available_max_size
;
192 static u8
calculate_word_cnts(const u8 word_en
)
197 for (word_idx
= 0; word_idx
< PGPKG_MAX_WORDS
; word_idx
++)
198 if (!(word_en
& BIT(word_idx
)))
199 word_cnts
++; /* 0 : write enable */
203 static void pgpacket_copy_data(const u8 word_en
, const u8
*sourdata
,
207 u8 word_idx
, byte_idx
;
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
++];
218 u16
r8712_efuse_get_current_size(struct _adapter
*padapter
)
220 int bContinual
= true;
222 u8 hoffset
= 0, hworden
= 0;
223 u8 efuse_data
, word_cnts
= 0;
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 hoffset
= (efuse_data
>> 4) & 0x0F;
229 hworden
= efuse_data
& 0x0F;
230 word_cnts
= calculate_word_cnts(hworden
);
231 /* read next header */
232 efuse_addr
= efuse_addr
+ (word_cnts
* 2) + 1;
239 u8
r8712_efuse_pg_packet_read(struct _adapter
*padapter
, u8 offset
, u8
*data
)
241 u8 hoffset
= 0, hworden
= 0, word_cnts
= 0;
245 u8 tmpdata
[PGPKT_DATA_SIZE
];
252 memset(data
, 0xFF, sizeof(u8
)*PGPKT_DATA_SIZE
);
253 while (efuse_addr
< efuse_available_max_size
) {
254 if (efuse_one_byte_read(padapter
, efuse_addr
, &efuse_data
) ==
256 if (efuse_data
== 0xFF)
258 hoffset
= (efuse_data
>> 4) & 0x0F;
259 hworden
= efuse_data
& 0x0F;
260 word_cnts
= calculate_word_cnts(hworden
);
261 if (hoffset
== offset
) {
262 memset(tmpdata
, 0xFF, PGPKT_DATA_SIZE
);
263 for (tmpidx
= 0; tmpidx
< word_cnts
* 2;
265 if (efuse_one_byte_read(padapter
,
266 efuse_addr
+1+tmpidx
, &efuse_data
) ==
268 tmpdata
[tmpidx
] = efuse_data
;
272 pgpacket_copy_data(hworden
, tmpdata
, data
);
274 efuse_addr
+= 1 + (word_cnts
*2);
283 static u8
fix_header(struct _adapter
*padapter
, u8 header
, u16 header_addr
)
285 struct PGPKT_STRUCT pkt
;
286 u8 offset
, word_en
, value
;
291 pkt
.offset
= GET_EFUSE_OFFSET(header
);
292 pkt
.word_en
= GET_EFUSE_WORD_EN(header
);
293 addr
= header_addr
+ 1 + calculate_word_cnts(pkt
.word_en
) * 2;
294 if (addr
> efuse_available_max_size
)
296 /* retrieve original data */
298 while (addr
< header_addr
) {
299 if (efuse_one_byte_read(padapter
, addr
++, &value
) == false) {
303 offset
= GET_EFUSE_OFFSET(value
);
304 word_en
= GET_EFUSE_WORD_EN(value
);
305 if (pkt
.offset
!= offset
) {
306 addr
+= calculate_word_cnts(word_en
)*2;
309 for (i
= 0; i
< PGPKG_MAX_WORDS
; i
++) {
310 if (BIT(i
) & word_en
) {
311 if (BIT(i
) & pkt
.word_en
) {
312 if (efuse_one_byte_read(
315 pkt
.data
[i
*2] = value
;
318 if (efuse_one_byte_read(
331 if (addr
!= header_addr
)
334 /* fill original data */
335 for (i
= 0; i
< PGPKG_MAX_WORDS
; i
++) {
336 if (BIT(i
) & pkt
.word_en
) {
337 efuse_one_byte_write(padapter
, addr
, pkt
.data
[i
*2]);
338 efuse_one_byte_write(padapter
, addr
+1,
340 /* additional check */
341 if (efuse_one_byte_read(padapter
, addr
, &value
)
344 else if (pkt
.data
[i
*2] != value
) {
346 if (0xFF == value
) /* write again */
347 efuse_one_byte_write(padapter
, addr
,
350 if (efuse_one_byte_read(padapter
, addr
+1, &value
) ==
353 else if (pkt
.data
[i
*2 + 1] != value
) {
355 if (0xFF == value
) /* write again */
356 efuse_one_byte_write(padapter
, addr
+1,
365 u8
r8712_efuse_pg_packet_write(struct _adapter
*padapter
, const u8 offset
,
366 const u8 word_en
, const u8
*data
)
369 u16 efuse_addr
= 0, curr_size
= 0;
370 u8 efuse_data
, target_word_cnts
= 0;
371 static int repeat_times
;
375 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
376 efuse_data
= r8712_read8(padapter
, EFUSE_CLK_CTRL
);
377 if (efuse_data
!= 0x03)
379 pg_header
= MAKE_EFUSE_HEADER(offset
, word_en
);
380 target_word_cnts
= calculate_word_cnts(word_en
);
383 while (efuse_addr
< efuse_available_max_size
) {
384 curr_size
= r8712_efuse_get_current_size(padapter
);
385 if ((curr_size
+ 1 + target_word_cnts
* 2) >
386 efuse_available_max_size
)
387 return false; /*target_word_cnts + pg header(1 byte)*/
388 efuse_addr
= curr_size
; /* current size is also the last addr*/
389 efuse_one_byte_write(padapter
, efuse_addr
, pg_header
); /*hdr*/
391 /* check if what we read is what we write */
392 while (efuse_one_byte_read(padapter
, efuse_addr
,
393 &efuse_data
) == false) {
394 if (++sub_repeat
> _REPEAT_THRESHOLD_
) {
395 bResult
= false; /* continue to blind write */
396 break; /* continue to blind write */
399 if ((sub_repeat
> _REPEAT_THRESHOLD_
) ||
400 (pg_header
== efuse_data
)) {
401 /* write header ok OR can't check header(creep) */
404 /* go to next address */
406 for (i
= 0; i
< target_word_cnts
*2; i
++) {
407 efuse_one_byte_write(padapter
,
410 if (efuse_one_byte_read(padapter
,
411 efuse_addr
+ i
, &efuse_data
) == false)
413 else if (*(data
+i
) != efuse_data
) /* fail */
417 } else { /* write header fail */
419 if (0xFF == efuse_data
)
420 return bResult
; /* not thing damaged. */
421 /* call rescue procedure */
422 if (fix_header(padapter
, efuse_data
, efuse_addr
) ==
424 return false; /* rescue fail */
426 if (++repeat_times
> _REPEAT_THRESHOLD_
) /* fail */
428 /* otherwise, take another risk... */
434 u8
r8712_efuse_access(struct _adapter
*padapter
, u8 bRead
, u16 start_addr
,
440 if (start_addr
> EFUSE_MAX_SIZE
)
442 if ((bRead
== false) && ((start_addr
+ cnts
) >
443 efuse_available_max_size
))
445 if ((false == bRead
) && (r8712_efuse_reg_init(padapter
) == false))
447 /* -----------------e-fuse one byte read / write ---------------------*/
448 for (i
= 0; i
< cnts
; i
++) {
449 if ((start_addr
+ i
) > EFUSE_MAX_SIZE
) {
453 res
= efuse_one_byte_rw(padapter
, bRead
, start_addr
+ i
,
455 if ((false == bRead
) && (false == res
))
459 r8712_efuse_reg_uninit(padapter
);
463 u8
r8712_efuse_map_read(struct _adapter
*padapter
, u16 addr
, u16 cnts
, u8
*data
)
465 u8 offset
, ret
= true;
466 u8 pktdata
[PGPKT_DATA_SIZE
];
469 if ((addr
+ cnts
) > EFUSE_MAP_MAX_SIZE
)
471 if ((efuse_is_empty(padapter
, &offset
) == true) && (offset
==
473 for (i
= 0; i
< cnts
; i
++)
477 offset
= (addr
>> 3) & 0xF;
478 ret
= r8712_efuse_pg_packet_read(padapter
, offset
, pktdata
);
479 i
= addr
& 0x7; /* pktdata index */
480 idx
= 0; /* data index */
483 for (; i
< PGPKT_DATA_SIZE
; i
++) {
484 data
[idx
++] = pktdata
[i
];
489 if (!r8712_efuse_pg_packet_read(padapter
, offset
, pktdata
))
496 u8
r8712_efuse_map_write(struct _adapter
*padapter
, u16 addr
, u16 cnts
,
499 u8 offset
, word_en
, empty
;
500 u8 pktdata
[PGPKT_DATA_SIZE
], newdata
[PGPKT_DATA_SIZE
];
503 if ((addr
+ cnts
) > EFUSE_MAP_MAX_SIZE
)
505 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
506 empty
= r8712_read8(padapter
, EFUSE_CLK_CTRL
);
509 if (efuse_is_empty(padapter
, &empty
) == true) {
511 memset(pktdata
, 0xFF, PGPKT_DATA_SIZE
);
514 offset
= (addr
>> 3) & 0xF;
516 if (!r8712_efuse_pg_packet_read(padapter
, offset
, pktdata
))
519 memset(newdata
, 0xFF, PGPKT_DATA_SIZE
);
520 i
= addr
& 0x7; /* pktdata index */
521 j
= 0; /* newdata index */
522 idx
= 0; /* data index */
526 if (data
[idx
] != pktdata
[i
]) {
527 word_en
&= ~BIT(i
>> 1);
528 newdata
[j
++] = pktdata
[i
- 1];
529 newdata
[j
++] = data
[idx
];
535 for (; i
< PGPKT_DATA_SIZE
; i
+= 2) {
536 if ((cnts
- idx
) == 1) {
537 if (data
[idx
] != pktdata
[i
]) {
538 word_en
&= ~BIT(i
>> 1);
539 newdata
[j
++] = data
[idx
];
540 newdata
[j
++] = pktdata
[1 + 1];
545 if ((data
[idx
] != pktdata
[i
]) || (data
[idx
+1] !=
547 word_en
&= ~BIT(i
>> 1);
548 newdata
[j
++] = data
[idx
];
549 newdata
[j
++] = data
[idx
+ 1];
558 if (r8712_efuse_pg_packet_write(padapter
, offset
,
559 word_en
, newdata
) == false)
565 if (!r8712_efuse_pg_packet_read(padapter
, offset
,
571 memset(newdata
, 0xFF, PGPKT_DATA_SIZE
);