1/****************************************************************************** 2 * 3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 17 * 18 * 19 ******************************************************************************/ 20#define _RTW_EFUSE_C_ 21 22#include <osdep_service.h> 23#include <drv_types.h> 24#include <rtw_efuse.h> 25#include <usb_ops_linux.h> 26#include <rtl8188e_hal.h> 27#include <rtw_iol.h> 28 29#define REG_EFUSE_CTRL 0x0030 30#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ 31 32enum{ 33 VOLTAGE_V25 = 0x03, 34 LDOE25_SHIFT = 28 , 35 }; 36 37/* 38 * Function: Efuse_PowerSwitch 39 * 40 * Overview: When we want to enable write operation, we should change to 41 * pwr on state. When we stop write, we should switch to 500k mode 42 * and disable LDO 2.5V. 43 */ 44 45void Efuse_PowerSwitch( 46 struct adapter *pAdapter, 47 u8 bWrite, 48 u8 PwrState) 49{ 50 u8 tempval; 51 u16 tmpV16; 52 53 if (PwrState) { 54 usb_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); 55 56 /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */ 57 tmpV16 = usb_read16(pAdapter, REG_SYS_ISO_CTRL); 58 if (!(tmpV16 & PWC_EV12V)) { 59 tmpV16 |= PWC_EV12V; 60 usb_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16); 61 } 62 /* Reset: 0x0000h[28], default valid */ 63 tmpV16 = usb_read16(pAdapter, REG_SYS_FUNC_EN); 64 if (!(tmpV16 & FEN_ELDR)) { 65 tmpV16 |= FEN_ELDR; 66 usb_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16); 67 } 68 69 /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ 70 tmpV16 = usb_read16(pAdapter, REG_SYS_CLKR); 71 if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { 72 tmpV16 |= (LOADER_CLK_EN | ANA8M); 73 usb_write16(pAdapter, REG_SYS_CLKR, tmpV16); 74 } 75 76 if (bWrite) { 77 /* Enable LDO 2.5V before read/write action */ 78 tempval = usb_read8(pAdapter, EFUSE_TEST+3); 79 tempval &= 0x0F; 80 tempval |= (VOLTAGE_V25 << 4); 81 usb_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80)); 82 } 83 } else { 84 usb_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); 85 86 if (bWrite) { 87 /* Disable LDO 2.5V after read/write action */ 88 tempval = usb_read8(pAdapter, EFUSE_TEST+3); 89 usb_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F)); 90 } 91 } 92} 93 94static void 95efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) 96{ 97 u8 *efuseTbl = NULL; 98 u8 rtemp8; 99 u16 eFuse_Addr = 0; 100 u8 offset, wren; 101 u16 i, j; 102 u16 **eFuseWord = NULL; 103 u16 efuse_utilized = 0; 104 u8 u1temp = 0; 105 106 efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL); 107 if (efuseTbl == NULL) { 108 DBG_88E("%s: alloc efuseTbl fail!\n", __func__); 109 goto exit; 110 } 111 112 eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); 113 if (eFuseWord == NULL) { 114 DBG_88E("%s: alloc eFuseWord fail!\n", __func__); 115 goto exit; 116 } 117 118 /* 0. Refresh efuse init map as all oxFF. */ 119 for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) 120 for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) 121 eFuseWord[i][j] = 0xFFFF; 122 123 /* */ 124 /* 1. Read the first byte to check if efuse is empty!!! */ 125 /* */ 126 /* */ 127 rtemp8 = *(phymap+eFuse_Addr); 128 if (rtemp8 != 0xFF) { 129 efuse_utilized++; 130 eFuse_Addr++; 131 } else { 132 DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8); 133 goto exit; 134 } 135 136 /* */ 137 /* 2. Read real efuse content. Filter PG header and every section data. */ 138 /* */ 139 while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { 140 /* Check PG header for section num. */ 141 if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */ 142 u1temp = ((rtemp8 & 0xE0) >> 5); 143 rtemp8 = *(phymap+eFuse_Addr); 144 if ((rtemp8 & 0x0F) == 0x0F) { 145 eFuse_Addr++; 146 rtemp8 = *(phymap+eFuse_Addr); 147 148 if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) 149 eFuse_Addr++; 150 continue; 151 } else { 152 offset = ((rtemp8 & 0xF0) >> 1) | u1temp; 153 wren = (rtemp8 & 0x0F); 154 eFuse_Addr++; 155 } 156 } else { 157 offset = ((rtemp8 >> 4) & 0x0f); 158 wren = (rtemp8 & 0x0f); 159 } 160 161 if (offset < EFUSE_MAX_SECTION_88E) { 162 /* Get word enable value from PG header */ 163 for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { 164 /* Check word enable condition in the section */ 165 if (!(wren & 0x01)) { 166 rtemp8 = *(phymap+eFuse_Addr); 167 eFuse_Addr++; 168 efuse_utilized++; 169 eFuseWord[offset][i] = (rtemp8 & 0xff); 170 if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) 171 break; 172 rtemp8 = *(phymap+eFuse_Addr); 173 eFuse_Addr++; 174 efuse_utilized++; 175 eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00); 176 177 if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) 178 break; 179 } 180 wren >>= 1; 181 } 182 } 183 /* Read next PG header */ 184 rtemp8 = *(phymap+eFuse_Addr); 185 186 if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { 187 efuse_utilized++; 188 eFuse_Addr++; 189 } 190 } 191 192 /* */ 193 /* 3. Collect 16 sections and 4 word unit into Efuse map. */ 194 /* */ 195 for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) { 196 for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { 197 efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff); 198 efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff); 199 } 200 } 201 202 /* */ 203 /* 4. Copy from Efuse map to output pointer memory!!! */ 204 /* */ 205 for (i = 0; i < _size_byte; i++) 206 pbuf[i] = efuseTbl[_offset+i]; 207 208 /* */ 209 /* 5. Calculate Efuse utilization. */ 210 /* */ 211 212exit: 213 kfree(efuseTbl); 214 215 if (eFuseWord) 216 kfree(eFuseWord); 217} 218 219static void efuse_read_phymap_from_txpktbuf( 220 struct adapter *adapter, 221 int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */ 222 u8 *content, /* buffer to store efuse physical map */ 223 u16 *size /* for efuse content: the max byte to read. will update to byte read */ 224 ) 225{ 226 u16 dbg_addr = 0; 227 u32 start = 0, passing_time = 0; 228 u8 reg_0x143 = 0; 229 u32 lo32 = 0, hi32 = 0; 230 u16 len = 0, count = 0; 231 int i = 0; 232 u16 limit = *size; 233 234 u8 *pos = content; 235 236 if (bcnhead < 0) /* if not valid */ 237 bcnhead = usb_read8(adapter, REG_TDECTRL+1); 238 239 DBG_88E("%s bcnhead:%d\n", __func__, bcnhead); 240 241 usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); 242 243 dbg_addr = bcnhead*128/8; /* 8-bytes addressing */ 244 245 while (1) { 246 usb_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i); 247 248 usb_write8(adapter, REG_TXPKTBUF_DBG, 0); 249 start = jiffies; 250 while (!(reg_0x143 = usb_read8(adapter, REG_TXPKTBUF_DBG)) && 251 (passing_time = rtw_get_passing_time_ms(start)) < 1000) { 252 DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, usb_read8(adapter, 0x106)); 253 msleep(1); 254 } 255 256 lo32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_L); 257 hi32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_H); 258 259 if (i == 0) { 260 u8 lenc[2]; 261 u16 lenbak, aaabak; 262 u16 aaa; 263 lenc[0] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L); 264 lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L+1); 265 266 aaabak = le16_to_cpup((__le16 *)lenc); 267 lenbak = le16_to_cpu(*((__le16 *)lenc)); 268 aaa = le16_to_cpup((__le16 *)&lo32); 269 len = le16_to_cpu(*((__le16 *)&lo32)); 270 271 limit = (len-2 < limit) ? len-2 : limit; 272 273 DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak); 274 275 memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count); 276 count += (limit >= count+2) ? 2 : limit-count; 277 pos = content+count; 278 279 } else { 280 memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count); 281 count += (limit >= count+4) ? 4 : limit-count; 282 pos = content+count; 283 } 284 285 if (limit > count && len-2 > count) { 286 memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count); 287 count += (limit >= count+4) ? 4 : limit-count; 288 pos = content+count; 289 } 290 291 if (limit <= count || len-2 <= count) 292 break; 293 i++; 294 } 295 usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); 296 DBG_88E("%s read count:%u\n", __func__, count); 297 *size = count; 298} 299 300static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map) 301{ 302 s32 status = _FAIL; 303 u8 physical_map[512]; 304 u16 size = 512; 305 306 usb_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); 307 memset(physical_map, 0xFF, 512); 308 usb_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); 309 status = iol_execute(padapter, CMD_READ_EFUSE_MAP); 310 if (status == _SUCCESS) 311 efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size); 312 efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map); 313 return status; 314} 315 316void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf) 317{ 318 319 if (rtw_IOL_applied(Adapter)) { 320 rtw_hal_power_on(Adapter); 321 iol_mode_enable(Adapter, 1); 322 iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf); 323 iol_mode_enable(Adapter, 0); 324 } 325 return; 326} 327 328/* Do not support BT */ 329void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut) 330{ 331 switch (type) { 332 case TYPE_EFUSE_MAX_SECTION: 333 { 334 u8 *pMax_section; 335 pMax_section = (u8 *)pOut; 336 *pMax_section = EFUSE_MAX_SECTION_88E; 337 } 338 break; 339 case TYPE_EFUSE_REAL_CONTENT_LEN: 340 { 341 u16 *pu2Tmp; 342 pu2Tmp = (u16 *)pOut; 343 *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; 344 } 345 break; 346 case TYPE_EFUSE_CONTENT_LEN_BANK: 347 { 348 u16 *pu2Tmp; 349 pu2Tmp = (u16 *)pOut; 350 *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; 351 } 352 break; 353 case TYPE_AVAILABLE_EFUSE_BYTES_BANK: 354 { 355 u16 *pu2Tmp; 356 pu2Tmp = (u16 *)pOut; 357 *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); 358 } 359 break; 360 case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: 361 { 362 u16 *pu2Tmp; 363 pu2Tmp = (u16 *)pOut; 364 *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); 365 } 366 break; 367 case TYPE_EFUSE_MAP_LEN: 368 { 369 u16 *pu2Tmp; 370 pu2Tmp = (u16 *)pOut; 371 *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; 372 } 373 break; 374 case TYPE_EFUSE_PROTECT_BYTES_BANK: 375 { 376 u8 *pu1Tmp; 377 pu1Tmp = (u8 *)pOut; 378 *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); 379 } 380 break; 381 default: 382 { 383 u8 *pu1Tmp; 384 pu1Tmp = (u8 *)pOut; 385 *pu1Tmp = 0; 386 } 387 break; 388 } 389} 390 391u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data) 392{ 393 u16 tmpaddr = 0; 394 u16 start_addr = efuse_addr; 395 u8 badworden = 0x0F; 396 u8 tmpdata[8]; 397 398 memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE); 399 400 if (!(word_en&BIT0)) { 401 tmpaddr = start_addr; 402 efuse_OneByteWrite(pAdapter, start_addr++, data[0]); 403 efuse_OneByteWrite(pAdapter, start_addr++, data[1]); 404 405 efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0]); 406 efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1]); 407 if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) 408 badworden &= (~BIT0); 409 } 410 if (!(word_en&BIT1)) { 411 tmpaddr = start_addr; 412 efuse_OneByteWrite(pAdapter, start_addr++, data[2]); 413 efuse_OneByteWrite(pAdapter, start_addr++, data[3]); 414 415 efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[2]); 416 efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3]); 417 if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) 418 badworden &= (~BIT1); 419 } 420 if (!(word_en&BIT2)) { 421 tmpaddr = start_addr; 422 efuse_OneByteWrite(pAdapter, start_addr++, data[4]); 423 efuse_OneByteWrite(pAdapter, start_addr++, data[5]); 424 425 efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4]); 426 efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5]); 427 if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) 428 badworden &= (~BIT2); 429 } 430 if (!(word_en&BIT3)) { 431 tmpaddr = start_addr; 432 efuse_OneByteWrite(pAdapter, start_addr++, data[6]); 433 efuse_OneByteWrite(pAdapter, start_addr++, data[7]); 434 435 efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6]); 436 efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7]); 437 if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) 438 badworden &= (~BIT3); 439 } 440 return badworden; 441} 442 443static u16 Efuse_GetCurrentSize(struct adapter *pAdapter) 444{ 445 int bContinual = true; 446 u16 efuse_addr = 0; 447 u8 hoffset = 0, hworden = 0; 448 u8 efuse_data, word_cnts = 0; 449 450 rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); 451 452 while (bContinual && 453 efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) && 454 AVAILABLE_EFUSE_ADDR(efuse_addr)) { 455 if (efuse_data != 0xFF) { 456 if ((efuse_data&0x1F) == 0x0F) { /* extended header */ 457 hoffset = efuse_data; 458 efuse_addr++; 459 efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data); 460 if ((efuse_data & 0x0F) == 0x0F) { 461 efuse_addr++; 462 continue; 463 } else { 464 hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); 465 hworden = efuse_data & 0x0F; 466 } 467 } else { 468 hoffset = (efuse_data>>4) & 0x0F; 469 hworden = efuse_data & 0x0F; 470 } 471 word_cnts = Efuse_CalculateWordCnts(hworden); 472 /* read next header */ 473 efuse_addr = efuse_addr + (word_cnts*2)+1; 474 } else { 475 bContinual = false; 476 } 477 } 478 479 rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); 480 481 return efuse_addr; 482} 483 484int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data) 485{ 486 u8 ReadState = PG_STATE_HEADER; 487 int bContinual = true; 488 int bDataEmpty = true; 489 u8 efuse_data, word_cnts = 0; 490 u16 efuse_addr = 0; 491 u8 hoffset = 0, hworden = 0; 492 u8 tmpidx = 0; 493 u8 tmpdata[8]; 494 u8 max_section = 0; 495 u8 tmp_header = 0; 496 497 EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section); 498 499 if (data == NULL) 500 return false; 501 if (offset > max_section) 502 return false; 503 504 memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); 505 memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); 506 507 /* <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ 508 /* Skip dummy parts to prevent unexpected data read from Efuse. */ 509 /* By pass right now. 2009.02.19. */ 510 while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) { 511 /* Header Read ------------- */ 512 if (ReadState & PG_STATE_HEADER) { 513 if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) && (efuse_data != 0xFF)) { 514 if (EXT_HEADER(efuse_data)) { 515 tmp_header = efuse_data; 516 efuse_addr++; 517 efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data); 518 if (!ALL_WORDS_DISABLED(efuse_data)) { 519 hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); 520 hworden = efuse_data & 0x0F; 521 } else { 522 DBG_88E("Error, All words disabled\n"); 523 efuse_addr++; 524 continue; 525 } 526 } else { 527 hoffset = (efuse_data>>4) & 0x0F; 528 hworden = efuse_data & 0x0F; 529 } 530 word_cnts = Efuse_CalculateWordCnts(hworden); 531 bDataEmpty = true; 532 533 if (hoffset == offset) { 534 for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) { 535 if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data)) { 536 tmpdata[tmpidx] = efuse_data; 537 if (efuse_data != 0xff) 538 bDataEmpty = false; 539 } 540 } 541 if (bDataEmpty == false) { 542 ReadState = PG_STATE_DATA; 543 } else {/* read next header */ 544 efuse_addr = efuse_addr + (word_cnts*2)+1; 545 ReadState = PG_STATE_HEADER; 546 } 547 } else {/* read next header */ 548 efuse_addr = efuse_addr + (word_cnts*2)+1; 549 ReadState = PG_STATE_HEADER; 550 } 551 } else { 552 bContinual = false; 553 } 554 } else if (ReadState & PG_STATE_DATA) { 555 /* Data section Read ------------- */ 556 efuse_WordEnableDataRead(hworden, tmpdata, data); 557 efuse_addr = efuse_addr + (word_cnts*2)+1; 558 ReadState = PG_STATE_HEADER; 559 } 560 561 } 562 563 if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff) && (data[3] == 0xff) && 564 (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff) && (data[7] == 0xff)) 565 return false; 566 else 567 return true; 568} 569 570static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr) 571{ 572 u8 originaldata[8], badworden = 0; 573 u16 efuse_addr = *pAddr; 574 u32 PgWriteSuccess = 0; 575 576 memset((void *)originaldata, 0xff, 8); 577 578 if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata)) { 579 /* check if data exist */ 580 badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata); 581 582 if (badworden != 0xf) { /* write fail */ 583 PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata); 584 585 if (!PgWriteSuccess) 586 return false; 587 else 588 efuse_addr = Efuse_GetCurrentSize(pAdapter); 589 } else { 590 efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1; 591 } 592 } else { 593 efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1; 594 } 595 *pAddr = efuse_addr; 596 return true; 597} 598 599static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) 600{ 601 bool bRet = false; 602 u16 efuse_addr = *pAddr, efuse_max_available_len = 0; 603 u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0; 604 u8 repeatcnt = 0; 605 606 EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len); 607 608 while (efuse_addr < efuse_max_available_len) { 609 pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; 610 efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); 611 efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); 612 613 while (tmp_header == 0xFF) { 614 if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) 615 return false; 616 617 efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); 618 efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); 619 } 620 621 /* to write ext_header */ 622 if (tmp_header == pg_header) { 623 efuse_addr++; 624 pg_header_temp = pg_header; 625 pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; 626 627 efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); 628 efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); 629 630 while (tmp_header == 0xFF) { 631 if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) 632 return false; 633 634 efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); 635 efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); 636 } 637 638 if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */ 639 if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { 640 return false; 641 } else { 642 efuse_addr++; 643 continue; 644 } 645 } else if (pg_header != tmp_header) { /* offset PG fail */ 646 struct pgpkt fixPkt; 647 fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1); 648 fixPkt.word_en = tmp_header & 0x0F; 649 fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); 650 if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr)) 651 return false; 652 } else { 653 bRet = true; 654 break; 655 } 656 } else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */ 657 efuse_addr += 2; 658 continue; 659 } 660 } 661 662 *pAddr = efuse_addr; 663 return bRet; 664} 665 666static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) 667{ 668 bool bRet = false; 669 u8 pg_header = 0, tmp_header = 0; 670 u16 efuse_addr = *pAddr; 671 u8 repeatcnt = 0; 672 673 pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; 674 675 efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); 676 efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); 677 678 while (tmp_header == 0xFF) { 679 if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) 680 return false; 681 efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); 682 efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); 683 } 684 685 if (pg_header == tmp_header) { 686 bRet = true; 687 } else { 688 struct pgpkt fixPkt; 689 fixPkt.offset = (tmp_header>>4) & 0x0F; 690 fixPkt.word_en = tmp_header & 0x0F; 691 fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); 692 if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr)) 693 return false; 694 } 695 696 *pAddr = efuse_addr; 697 return bRet; 698} 699 700static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) 701{ 702 u16 efuse_addr = *pAddr; 703 u8 badworden = 0; 704 u32 PgWriteSuccess = 0; 705 706 badworden = 0x0f; 707 badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data); 708 if (badworden == 0x0F) { 709 /* write ok */ 710 return true; 711 } else { 712 /* reorganize other pg packet */ 713 PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data); 714 if (!PgWriteSuccess) 715 return false; 716 else 717 return true; 718 } 719} 720 721static bool 722hal_EfusePgPacketWriteHeader( 723 struct adapter *pAdapter, 724 u8 efuseType, 725 u16 *pAddr, 726 struct pgpkt *pTargetPkt) 727{ 728 bool bRet = false; 729 730 if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) 731 bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt); 732 else 733 bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt); 734 735 return bRet; 736} 737 738static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt, 739 u8 *pWden) 740{ 741 u8 match_word_en = 0x0F; /* default all words are disabled */ 742 743 /* check if the same words are enabled both target and current PG packet */ 744 if (((pTargetPkt->word_en & BIT0) == 0) && 745 ((pCurPkt->word_en & BIT0) == 0)) 746 match_word_en &= ~BIT0; /* enable word 0 */ 747 if (((pTargetPkt->word_en & BIT1) == 0) && 748 ((pCurPkt->word_en & BIT1) == 0)) 749 match_word_en &= ~BIT1; /* enable word 1 */ 750 if (((pTargetPkt->word_en & BIT2) == 0) && 751 ((pCurPkt->word_en & BIT2) == 0)) 752 match_word_en &= ~BIT2; /* enable word 2 */ 753 if (((pTargetPkt->word_en & BIT3) == 0) && 754 ((pCurPkt->word_en & BIT3) == 0)) 755 match_word_en &= ~BIT3; /* enable word 3 */ 756 757 *pWden = match_word_en; 758 759 if (match_word_en != 0xf) 760 return true; 761 else 762 return false; 763} 764 765static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr) 766{ 767 bool bRet = false; 768 u8 i, efuse_data; 769 770 for (i = 0; i < (word_cnts*2); i++) { 771 if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data) && (efuse_data != 0xFF)) 772 bRet = true; 773 } 774 return bRet; 775} 776 777static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) 778{ 779 bool bRet = false; 780 u8 i, efuse_data = 0, cur_header = 0; 781 u8 matched_wden = 0, badworden = 0; 782 u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; 783 struct pgpkt curPkt; 784 785 EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len); 786 EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max); 787 788 rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); 789 startAddr %= EFUSE_REAL_CONTENT_LEN; 790 791 while (1) { 792 if (startAddr >= efuse_max_available_len) { 793 bRet = false; 794 break; 795 } 796 797 if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data) && (efuse_data != 0xFF)) { 798 if (EXT_HEADER(efuse_data)) { 799 cur_header = efuse_data; 800 startAddr++; 801 efuse_OneByteRead(pAdapter, startAddr, &efuse_data); 802 if (ALL_WORDS_DISABLED(efuse_data)) { 803 bRet = false; 804 break; 805 } else { 806 curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); 807 curPkt.word_en = efuse_data & 0x0F; 808 } 809 } else { 810 cur_header = efuse_data; 811 curPkt.offset = (cur_header>>4) & 0x0F; 812 curPkt.word_en = cur_header & 0x0F; 813 } 814 815 curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); 816 /* if same header is found but no data followed */ 817 /* write some part of data followed by the header. */ 818 if ((curPkt.offset == pTargetPkt->offset) && 819 (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1)) && 820 wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) { 821 /* Here to write partial data */ 822 badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data); 823 if (badworden != 0x0F) { 824 u32 PgWriteSuccess = 0; 825 /* if write fail on some words, write these bad words again */ 826 827 PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data); 828 829 if (!PgWriteSuccess) { 830 bRet = false; /* write fail, return */ 831 break; 832 } 833 } 834 /* partial write ok, update the target packet for later use */ 835 for (i = 0; i < 4; i++) { 836 if ((matched_wden & (0x1<<i)) == 0) /* this word has been written */ 837 pTargetPkt->word_en |= (0x1<<i); /* disable the word */ 838 } 839 pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); 840 } 841 /* read from next header */ 842 startAddr = startAddr + (curPkt.word_cnts*2) + 1; 843 } else { 844 /* not used header, 0xff */ 845 *pAddr = startAddr; 846 bRet = true; 847 break; 848 } 849 } 850 return bRet; 851} 852 853static bool 854hal_EfusePgCheckAvailableAddr( 855 struct adapter *pAdapter, 856 u8 efuseType 857 ) 858{ 859 u16 efuse_max_available_len = 0; 860 861 /* Change to check TYPE_EFUSE_MAP_LEN , because 8188E raw 256, logic map over 256. */ 862 EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len); 863 864 if (Efuse_GetCurrentSize(pAdapter) >= efuse_max_available_len) 865 return false; 866 return true; 867} 868 869static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt) 870{ 871 memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8); 872 pTargetPkt->offset = offset; 873 pTargetPkt->word_en = word_en; 874 efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); 875 pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); 876} 877 878bool Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData) 879{ 880 struct pgpkt targetPkt; 881 u16 startAddr = 0; 882 u8 efuseType = EFUSE_WIFI; 883 884 if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType)) 885 return false; 886 887 hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); 888 889 if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt)) 890 return false; 891 892 if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt)) 893 return false; 894 895 if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt)) 896 return false; 897 898 return true; 899} 900 901u8 Efuse_CalculateWordCnts(u8 word_en) 902{ 903 u8 word_cnts = 0; 904 if (!(word_en & BIT(0))) 905 word_cnts++; /* 0 : write enable */ 906 if (!(word_en & BIT(1))) 907 word_cnts++; 908 if (!(word_en & BIT(2))) 909 word_cnts++; 910 if (!(word_en & BIT(3))) 911 word_cnts++; 912 return word_cnts; 913} 914 915u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data) 916{ 917 u8 tmpidx = 0; 918 u8 result; 919 920 usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff)); 921 usb_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) | 922 (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC)); 923 924 usb_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */ 925 926 while (!(0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100)) 927 tmpidx++; 928 if (tmpidx < 100) { 929 *data = usb_read8(pAdapter, EFUSE_CTRL); 930 result = true; 931 } else { 932 *data = 0xff; 933 result = false; 934 } 935 return result; 936} 937 938u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data) 939{ 940 u8 tmpidx = 0; 941 u8 result; 942 943 usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); 944 usb_write8(pAdapter, EFUSE_CTRL+2, 945 (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) | 946 (u8)((addr>>8) & 0x03)); 947 usb_write8(pAdapter, EFUSE_CTRL, data);/* data */ 948 949 usb_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */ 950 951 while ((0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100)) 952 tmpidx++; 953 954 if (tmpidx < 100) 955 result = true; 956 else 957 result = false; 958 959 return result; 960} 961 962/* 963 * Overview: Read allowed word in current efuse section data. 964 */ 965void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata) 966{ 967 if (!(word_en&BIT(0))) { 968 targetdata[0] = sourdata[0]; 969 targetdata[1] = sourdata[1]; 970 } 971 if (!(word_en&BIT(1))) { 972 targetdata[2] = sourdata[2]; 973 targetdata[3] = sourdata[3]; 974 } 975 if (!(word_en&BIT(2))) { 976 targetdata[4] = sourdata[4]; 977 targetdata[5] = sourdata[5]; 978 } 979 if (!(word_en&BIT(3))) { 980 targetdata[6] = sourdata[6]; 981 targetdata[7] = sourdata[7]; 982 } 983} 984 985/* 986 * Overview: Read All Efuse content 987 */ 988static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse) 989{ 990 u16 mapLen = 0; 991 992 Efuse_PowerSwitch(pAdapter, false, true); 993 994 EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); 995 996 efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse); 997 998 Efuse_PowerSwitch(pAdapter, false, false); 999} 1000 1001/* 1002 * Overview: Transfer current EFUSE content to shadow init and modify map. 1003 */ 1004void EFUSE_ShadowMapUpdate( 1005 struct adapter *pAdapter, 1006 u8 efuseType) 1007{ 1008 struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); 1009 u16 mapLen = 0; 1010 1011 EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); 1012 1013 if (pEEPROM->bautoload_fail_flag) 1014 memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); 1015 else 1016 Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data); 1017} 1018