0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define _RTL8712_EFUSE_C_
0018
0019 #include "osdep_service.h"
0020 #include "drv_types.h"
0021 #include "rtl8712_efuse.h"
0022
0023
0024 static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 ;
0025
0026 static void efuse_reg_ctrl(struct _adapter *adapter, u8 bPowerOn)
0027 {
0028 u8 tmpu8 = 0;
0029
0030 if (bPowerOn) {
0031
0032
0033
0034 tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
0035 tmpu8 |= 0x80;
0036 r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
0037 msleep(20);
0038
0039 r8712_write8(adapter, EFUSE_CLK_CTRL, 0x03);
0040 msleep(20);
0041 } else {
0042
0043
0044
0045 tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
0046 tmpu8 &= 0x7F;
0047 r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
0048
0049 r8712_write8(adapter, EFUSE_CLK_CTRL, 0x02);
0050 }
0051 }
0052
0053
0054
0055
0056 u8 r8712_efuse_reg_init(struct _adapter *adapter)
0057 {
0058 return true;
0059 }
0060
0061 void r8712_efuse_reg_uninit(struct _adapter *adapter)
0062 {
0063 efuse_reg_ctrl(adapter, false);
0064 }
0065
0066 static u8 efuse_one_byte_read(struct _adapter *adapter, u16 addr, u8 *data)
0067 {
0068 u8 tmpidx = 0, bResult;
0069
0070
0071 r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF));
0072 r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
0073 (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
0074 r8712_write8(adapter, EFUSE_CTRL + 3, 0x72);
0075
0076 while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
0077 (tmpidx < 100))
0078 tmpidx++;
0079 if (tmpidx < 100) {
0080 *data = r8712_read8(adapter, EFUSE_CTRL);
0081 bResult = true;
0082 } else {
0083 *data = 0xff;
0084 bResult = false;
0085 }
0086 return bResult;
0087 }
0088
0089 static u8 efuse_one_byte_write(struct _adapter *adapter, u16 addr, u8 data)
0090 {
0091 u8 tmpidx = 0, bResult;
0092
0093
0094 r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF));
0095 r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
0096 (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
0097 r8712_write8(adapter, EFUSE_CTRL, data);
0098 r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2);
0099
0100 while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
0101 (tmpidx < 100))
0102 tmpidx++;
0103 if (tmpidx < 100)
0104 bResult = true;
0105 else
0106 bResult = false;
0107 return bResult;
0108 }
0109
0110 static u8 efuse_one_byte_rw(struct _adapter *adapter, u8 bRead, u16 addr,
0111 u8 *data)
0112 {
0113 u8 tmpidx = 0, tmpv8 = 0, bResult;
0114
0115
0116 r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF));
0117 tmpv8 = ((u8)((addr >> 8) & 0x03)) |
0118 (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC);
0119 r8712_write8(adapter, EFUSE_CTRL + 2, tmpv8);
0120 if (bRead) {
0121 r8712_write8(adapter, EFUSE_CTRL + 3, 0x72);
0122 while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
0123 (tmpidx < 100))
0124 tmpidx++;
0125 if (tmpidx < 100) {
0126 *data = r8712_read8(adapter, EFUSE_CTRL);
0127 bResult = true;
0128 } else {
0129 *data = 0;
0130 bResult = false;
0131 }
0132 } else {
0133 r8712_write8(adapter, EFUSE_CTRL, *data);
0134 r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2);
0135 while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
0136 (tmpidx < 100))
0137 tmpidx++;
0138 if (tmpidx < 100)
0139 bResult = true;
0140 else
0141 bResult = false;
0142 }
0143 return bResult;
0144 }
0145
0146 static u8 efuse_is_empty(struct _adapter *adapter, u8 *empty)
0147 {
0148 u8 value, ret = true;
0149
0150
0151 if (efuse_one_byte_rw(adapter, true, 0, &value)) {
0152 if (value == 0xFF)
0153 *empty = true;
0154 else
0155 *empty = false;
0156 } else {
0157 ret = false;
0158 }
0159 return ret;
0160 }
0161
0162 void r8712_efuse_change_max_size(struct _adapter *adapter)
0163 {
0164 u16 pre_pg_data_saddr = 0x1FB;
0165 u16 i;
0166 u16 pre_pg_data_size = 5;
0167 u8 pre_pg_data[5];
0168
0169 for (i = 0; i < pre_pg_data_size; i++)
0170 efuse_one_byte_read(adapter, pre_pg_data_saddr + i,
0171 &pre_pg_data[i]);
0172 if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) &&
0173 (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) &&
0174 (pre_pg_data[4] == 0x0C))
0175 efuse_available_max_size -= pre_pg_data_size;
0176 }
0177
0178 int r8712_efuse_get_max_size(struct _adapter *adapter)
0179 {
0180 return efuse_available_max_size;
0181 }
0182
0183 static u8 calculate_word_cnts(const u8 word_en)
0184 {
0185 u8 word_cnts = 0;
0186 u8 word_idx;
0187
0188 for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++)
0189 if (!(word_en & BIT(word_idx)))
0190 word_cnts++;
0191 return word_cnts;
0192 }
0193
0194 static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata,
0195 u8 *targetdata)
0196 {
0197 u8 tmpindex = 0;
0198 u8 word_idx, byte_idx;
0199
0200 for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) {
0201 if (!(word_en & BIT(word_idx))) {
0202 byte_idx = word_idx * 2;
0203 targetdata[byte_idx] = sourdata[tmpindex++];
0204 targetdata[byte_idx + 1] = sourdata[tmpindex++];
0205 }
0206 }
0207 }
0208
0209 u16 r8712_efuse_get_current_size(struct _adapter *adapter)
0210 {
0211 int bContinual = true;
0212 u16 efuse_addr = 0;
0213 u8 hworden = 0;
0214 u8 efuse_data, word_cnts = 0;
0215
0216 while (bContinual && efuse_one_byte_read(adapter, efuse_addr,
0217 &efuse_data) && (efuse_addr < efuse_available_max_size)) {
0218 if (efuse_data != 0xFF) {
0219 hworden = efuse_data & 0x0F;
0220 word_cnts = calculate_word_cnts(hworden);
0221
0222 efuse_addr = efuse_addr + (word_cnts * 2) + 1;
0223 } else {
0224 bContinual = false;
0225 }
0226 }
0227 return efuse_addr;
0228 }
0229
0230 u8 r8712_efuse_pg_packet_read(struct _adapter *adapter, u8 offset, u8 *data)
0231 {
0232 u8 hoffset = 0, hworden = 0, word_cnts = 0;
0233 u16 efuse_addr = 0;
0234 u8 efuse_data;
0235 u8 tmpidx = 0;
0236 u8 tmpdata[PGPKT_DATA_SIZE];
0237 u8 ret = true;
0238
0239 if (!data)
0240 return false;
0241 if (offset > 0x0f)
0242 return false;
0243 memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE);
0244 while (efuse_addr < efuse_available_max_size) {
0245 if (efuse_one_byte_read(adapter, efuse_addr, &efuse_data)) {
0246 if (efuse_data == 0xFF)
0247 break;
0248 hoffset = (efuse_data >> 4) & 0x0F;
0249 hworden = efuse_data & 0x0F;
0250 word_cnts = calculate_word_cnts(hworden);
0251 if (hoffset == offset) {
0252 memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
0253 for (tmpidx = 0; tmpidx < word_cnts * 2;
0254 tmpidx++) {
0255 if (efuse_one_byte_read(adapter,
0256 efuse_addr + 1 + tmpidx,
0257 &efuse_data)) {
0258 tmpdata[tmpidx] = efuse_data;
0259 } else {
0260 ret = false;
0261 }
0262 }
0263 pgpacket_copy_data(hworden, tmpdata, data);
0264 }
0265 efuse_addr += 1 + (word_cnts * 2);
0266 } else {
0267 ret = false;
0268 break;
0269 }
0270 }
0271 return ret;
0272 }
0273
0274 static u8 fix_header(struct _adapter *adapter, u8 header, u16 header_addr)
0275 {
0276 struct PGPKT_STRUCT pkt;
0277 u8 offset, word_en, value;
0278 u16 addr;
0279 int i;
0280 u8 ret = true;
0281
0282 pkt.offset = GET_EFUSE_OFFSET(header);
0283 pkt.word_en = GET_EFUSE_WORD_EN(header);
0284 addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2;
0285 if (addr > efuse_available_max_size)
0286 return false;
0287
0288 addr = 0;
0289 while (addr < header_addr) {
0290 if (!efuse_one_byte_read(adapter, addr++, &value)) {
0291 ret = false;
0292 break;
0293 }
0294 offset = GET_EFUSE_OFFSET(value);
0295 word_en = GET_EFUSE_WORD_EN(value);
0296 if (pkt.offset != offset) {
0297 addr += calculate_word_cnts(word_en) * 2;
0298 continue;
0299 }
0300 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
0301 if (!(BIT(i) & word_en))
0302 continue;
0303 if (BIT(i) & pkt.word_en) {
0304 if (efuse_one_byte_read(adapter,
0305 addr,
0306 &value))
0307 pkt.data[i * 2] = value;
0308 else
0309 return false;
0310 if (efuse_one_byte_read(adapter,
0311 addr + 1,
0312 &value))
0313 pkt.data[i * 2 + 1] = value;
0314 else
0315 return false;
0316 }
0317 addr += 2;
0318 }
0319 }
0320 if (addr != header_addr)
0321 return false;
0322 addr++;
0323
0324 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
0325 if (BIT(i) & pkt.word_en) {
0326 efuse_one_byte_write(adapter, addr, pkt.data[i * 2]);
0327 efuse_one_byte_write(adapter, addr + 1,
0328 pkt.data[i * 2 + 1]);
0329
0330 if (!efuse_one_byte_read(adapter, addr, &value)) {
0331 ret = false;
0332 } else if (pkt.data[i * 2] != value) {
0333 ret = false;
0334 if (value == 0xFF)
0335 efuse_one_byte_write(adapter, addr,
0336 pkt.data[i * 2]);
0337 }
0338 if (!efuse_one_byte_read(adapter, addr + 1, &value)) {
0339 ret = false;
0340 } else if (pkt.data[i * 2 + 1] != value) {
0341 ret = false;
0342 if (value == 0xFF)
0343 efuse_one_byte_write(adapter, addr + 1,
0344 pkt.data[i * 2 +
0345 1]);
0346 }
0347 }
0348 addr += 2;
0349 }
0350 return ret;
0351 }
0352
0353 u8 r8712_efuse_pg_packet_write(struct _adapter *adapter, const u8 offset,
0354 const u8 word_en, const u8 *data)
0355 {
0356 u8 pg_header = 0;
0357 u16 efuse_addr = 0, curr_size = 0;
0358 u8 efuse_data, target_word_cnts = 0;
0359 int repeat_times;
0360 int sub_repeat;
0361 u8 bResult = true;
0362
0363
0364 efuse_data = r8712_read8(adapter, EFUSE_CLK_CTRL);
0365 if (efuse_data != 0x03)
0366 return false;
0367 pg_header = MAKE_EFUSE_HEADER(offset, word_en);
0368 target_word_cnts = calculate_word_cnts(word_en);
0369 repeat_times = 0;
0370 efuse_addr = 0;
0371 while (efuse_addr < efuse_available_max_size) {
0372 curr_size = r8712_efuse_get_current_size(adapter);
0373 if ((curr_size + 1 + target_word_cnts * 2) >
0374 efuse_available_max_size)
0375 return false;
0376 efuse_addr = curr_size;
0377 efuse_one_byte_write(adapter, efuse_addr, pg_header);
0378 sub_repeat = 0;
0379
0380 while (!efuse_one_byte_read(adapter, efuse_addr,
0381 &efuse_data)) {
0382 if (++sub_repeat > _REPEAT_THRESHOLD_) {
0383 bResult = false;
0384 break;
0385 }
0386 }
0387 if ((sub_repeat > _REPEAT_THRESHOLD_) ||
0388 (pg_header == efuse_data)) {
0389
0390 u8 i;
0391
0392
0393 efuse_addr++;
0394 for (i = 0; i < target_word_cnts * 2; i++) {
0395 efuse_one_byte_write(adapter,
0396 efuse_addr + i,
0397 *(data + i));
0398 if (!efuse_one_byte_read(adapter,
0399 efuse_addr + i,
0400 &efuse_data))
0401 bResult = false;
0402 else if (*(data + i) != efuse_data)
0403 bResult = false;
0404 }
0405 break;
0406 }
0407
0408 bResult = false;
0409 if (efuse_data == 0xFF)
0410 return bResult;
0411
0412 if (!fix_header(adapter, efuse_data, efuse_addr))
0413 return false;
0414
0415 if (++repeat_times > _REPEAT_THRESHOLD_)
0416 break;
0417
0418 }
0419 return bResult;
0420 }
0421
0422 u8 r8712_efuse_access(struct _adapter *adapter, u8 bRead, u16 start_addr,
0423 u16 cnts, u8 *data)
0424 {
0425 int i;
0426 u8 res = true;
0427
0428 if (start_addr > EFUSE_MAX_SIZE)
0429 return false;
0430 if (!bRead && ((start_addr + cnts) >
0431 efuse_available_max_size))
0432 return false;
0433 if (!bRead && !r8712_efuse_reg_init(adapter))
0434 return false;
0435
0436 for (i = 0; i < cnts; i++) {
0437 if ((start_addr + i) > EFUSE_MAX_SIZE) {
0438 res = false;
0439 break;
0440 }
0441 res = efuse_one_byte_rw(adapter, bRead, start_addr + i,
0442 data + i);
0443 if (!bRead && !res)
0444 break;
0445 }
0446 if (!bRead)
0447 r8712_efuse_reg_uninit(adapter);
0448 return res;
0449 }
0450
0451 u8 r8712_efuse_map_read(struct _adapter *adapter, u16 addr, u16 cnts, u8 *data)
0452 {
0453 u8 offset, ret = true;
0454 u8 pktdata[PGPKT_DATA_SIZE];
0455 int i, idx;
0456
0457 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
0458 return false;
0459 if (efuse_is_empty(adapter, &offset) && offset) {
0460 for (i = 0; i < cnts; i++)
0461 data[i] = 0xFF;
0462 return ret;
0463 }
0464 offset = (addr >> 3) & 0xF;
0465 ret = r8712_efuse_pg_packet_read(adapter, offset, pktdata);
0466 i = addr & 0x7;
0467 idx = 0;
0468
0469 do {
0470 for (; i < PGPKT_DATA_SIZE; i++) {
0471 data[idx++] = pktdata[i];
0472 if (idx == cnts)
0473 return ret;
0474 }
0475 offset++;
0476 if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
0477 ret = false;
0478 i = 0;
0479 } while (1);
0480 return ret;
0481 }
0482
0483 u8 r8712_efuse_map_write(struct _adapter *adapter, u16 addr, u16 cnts,
0484 u8 *data)
0485 {
0486 u8 offset, word_en, empty;
0487 u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE];
0488 int i, j, idx;
0489
0490 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
0491 return false;
0492
0493 empty = r8712_read8(adapter, EFUSE_CLK_CTRL);
0494 if (empty != 0x03)
0495 return false;
0496 if (efuse_is_empty(adapter, &empty)) {
0497 if (empty)
0498 memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
0499 } else {
0500 return false;
0501 }
0502 offset = (addr >> 3) & 0xF;
0503 if (!empty)
0504 if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
0505 return false;
0506 word_en = 0xF;
0507 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
0508 i = addr & 0x7;
0509 j = 0;
0510 idx = 0;
0511
0512 if (i & 0x1) {
0513
0514 if (data[idx] != pktdata[i]) {
0515 word_en &= ~BIT(i >> 1);
0516 newdata[j++] = pktdata[i - 1];
0517 newdata[j++] = data[idx];
0518 }
0519 i++;
0520 idx++;
0521 }
0522 do {
0523 for (; i < PGPKT_DATA_SIZE; i += 2) {
0524 if ((cnts - idx) == 1) {
0525 if (data[idx] != pktdata[i]) {
0526 word_en &= ~BIT(i >> 1);
0527 newdata[j++] = data[idx];
0528 newdata[j++] = pktdata[1 + 1];
0529 }
0530 idx++;
0531 break;
0532 }
0533
0534 if ((data[idx] != pktdata[i]) || (data[idx + 1] !=
0535 pktdata[i + 1])) {
0536 word_en &= ~BIT(i >> 1);
0537 newdata[j++] = data[idx];
0538 newdata[j++] = data[idx + 1];
0539 }
0540 idx += 2;
0541
0542 if (idx == cnts)
0543 break;
0544 }
0545
0546 if (word_en != 0xF)
0547 if (!r8712_efuse_pg_packet_write(adapter, offset,
0548 word_en, newdata))
0549 return false;
0550 if (idx == cnts)
0551 break;
0552 offset++;
0553 if (!empty)
0554 if (!r8712_efuse_pg_packet_read(adapter, offset,
0555 pktdata))
0556 return false;
0557 i = 0;
0558 j = 0;
0559 word_en = 0xF;
0560 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
0561 } while (1);
0562
0563 return true;
0564 }