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:
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;
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 hworden = efuse_data & 0x0F;
229 word_cnts = calculate_word_cnts(hworden);
230 /* read next header */
231 efuse_addr = efuse_addr + (word_cnts * 2) + 1;
238 u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
240 u8 hoffset = 0, hworden = 0, word_cnts = 0;
244 u8 tmpdata[PGPKT_DATA_SIZE];
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) ==
255 if (efuse_data == 0xFF)
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;
264 if (efuse_one_byte_read(padapter,
265 efuse_addr+1+tmpidx, &efuse_data) ==
267 tmpdata[tmpidx] = efuse_data;
271 pgpacket_copy_data(hworden, tmpdata, data);
273 efuse_addr += 1 + (word_cnts*2);
282 static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
284 struct PGPKT_STRUCT pkt;
285 u8 offset, word_en, value;
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)
295 /* retrieve original data */
297 while (addr < header_addr) {
298 if (efuse_one_byte_read(padapter, addr++, &value) == false) {
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;
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(
314 pkt.data[i*2] = value;
317 if (efuse_one_byte_read(
330 if (addr != header_addr)
333 /* fill original data */
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,
339 /* additional check */
340 if (efuse_one_byte_read(padapter, addr, &value)
343 else if (pkt.data[i*2] != value) {
345 if (0xFF == value) /* write again */
346 efuse_one_byte_write(padapter, addr,
349 if (efuse_one_byte_read(padapter, addr+1, &value) ==
352 else if (pkt.data[i*2 + 1] != value) {
354 if (0xFF == value) /* write again */
355 efuse_one_byte_write(padapter, addr+1,
364 u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
365 const u8 word_en, const u8 *data)
368 u16 efuse_addr = 0, curr_size = 0;
369 u8 efuse_data, target_word_cnts = 0;
370 static int repeat_times;
374 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
375 efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL);
376 if (efuse_data != 0x03)
378 pg_header = MAKE_EFUSE_HEADER(offset, word_en);
379 target_word_cnts = calculate_word_cnts(word_en);
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; /*target_word_cnts + pg header(1 byte)*/
387 efuse_addr = curr_size; /* current size is also the last addr*/
388 efuse_one_byte_write(padapter, efuse_addr, pg_header); /*hdr*/
390 /* check if what we read is what we write */
391 while (efuse_one_byte_read(padapter, efuse_addr,
392 &efuse_data) == false) {
393 if (++sub_repeat > _REPEAT_THRESHOLD_) {
394 bResult = false; /* continue to blind write */
395 break; /* continue to blind write */
398 if ((sub_repeat > _REPEAT_THRESHOLD_) ||
399 (pg_header == efuse_data)) {
400 /* write header ok OR can't check header(creep) */
403 /* go to next address */
405 for (i = 0; i < target_word_cnts*2; i++) {
406 efuse_one_byte_write(padapter,
409 if (efuse_one_byte_read(padapter,
410 efuse_addr + i, &efuse_data) == false)
412 else if (*(data+i) != efuse_data) /* fail */
417 /* write header fail */
419 if (0xFF == efuse_data)
420 return bResult; /* nothing damaged. */
421 /* call rescue procedure */
422 if (!fix_header(padapter, efuse_data, efuse_addr))
423 return false; /* rescue fail */
425 if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */
427 /* otherwise, take another risk... */
432 u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
438 if (start_addr > EFUSE_MAX_SIZE)
440 if ((bRead == false) && ((start_addr + cnts) >
441 efuse_available_max_size))
443 if ((false == bRead) && (r8712_efuse_reg_init(padapter) == false))
445 /* -----------------e-fuse one byte read / write ---------------------*/
446 for (i = 0; i < cnts; i++) {
447 if ((start_addr + i) > EFUSE_MAX_SIZE) {
451 res = efuse_one_byte_rw(padapter, bRead, start_addr + i,
453 if ((false == bRead) && (false == res))
457 r8712_efuse_reg_uninit(padapter);
461 u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
463 u8 offset, ret = true;
464 u8 pktdata[PGPKT_DATA_SIZE];
467 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
469 if ((efuse_is_empty(padapter, &offset) == true) && (offset ==
471 for (i = 0; i < cnts; i++)
475 offset = (addr >> 3) & 0xF;
476 ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata);
477 i = addr & 0x7; /* pktdata index */
478 idx = 0; /* data index */
481 for (; i < PGPKT_DATA_SIZE; i++) {
482 data[idx++] = pktdata[i];
487 if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
494 u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
497 u8 offset, word_en, empty;
498 u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE];
501 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
503 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
504 empty = r8712_read8(padapter, EFUSE_CLK_CTRL);
507 if (efuse_is_empty(padapter, &empty) == true) {
509 memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
512 offset = (addr >> 3) & 0xF;
514 if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
517 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
518 i = addr & 0x7; /* pktdata index */
519 j = 0; /* newdata index */
520 idx = 0; /* data index */
524 if (data[idx] != pktdata[i]) {
525 word_en &= ~BIT(i >> 1);
526 newdata[j++] = pktdata[i - 1];
527 newdata[j++] = data[idx];
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];
544 if ((data[idx] != pktdata[i]) || (data[idx+1] !=
546 word_en &= ~BIT(i >> 1);
547 newdata[j++] = data[idx];
548 newdata[j++] = data[idx + 1];
557 if (r8712_efuse_pg_packet_write(padapter, offset,
558 word_en, newdata) == false)
564 if (!r8712_efuse_pg_packet_read(padapter, offset,
570 memset(newdata, 0xFF, PGPKT_DATA_SIZE);