1 // SPDX-License-Identifier: GPL-2.0 2 /****************************************************************************** 3 * 4 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. 5 * 6 ******************************************************************************/ 7 #define _RTW_EFUSE_C_ 8 9 #include <drv_types.h> 10 #include <rtw_debug.h> 11 #include <hal_data.h> 12 #include <linux/jiffies.h> 13 14 15 /* Define global variables */ 16 u8 fakeEfuseBank; 17 u32 fakeEfuseUsedBytes; 18 u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; 19 u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; 20 u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; 21 22 u32 BTEfuseUsedBytes; 23 u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; 24 u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; 25 u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; 26 27 u32 fakeBTEfuseUsedBytes; 28 u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; 29 u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; 30 u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; 31 32 #define REG_EFUSE_CTRL 0x0030 33 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ 34 35 bool 36 Efuse_Read1ByteFromFakeContent( 37 struct adapter *padapter, 38 u16 Offset, 39 u8 *Value); 40 bool 41 Efuse_Read1ByteFromFakeContent( 42 struct adapter *padapter, 43 u16 Offset, 44 u8 *Value) 45 { 46 if (Offset >= EFUSE_MAX_HW_SIZE) { 47 return false; 48 } 49 /* DbgPrint("Read fake content, offset = %d\n", Offset); */ 50 if (fakeEfuseBank == 0) 51 *Value = fakeEfuseContent[Offset]; 52 else 53 *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset]; 54 return true; 55 } 56 57 bool 58 Efuse_Write1ByteToFakeContent( 59 struct adapter *padapter, 60 u16 Offset, 61 u8 Value); 62 bool 63 Efuse_Write1ByteToFakeContent( 64 struct adapter *padapter, 65 u16 Offset, 66 u8 Value) 67 { 68 if (Offset >= EFUSE_MAX_HW_SIZE) { 69 return false; 70 } 71 if (fakeEfuseBank == 0) 72 fakeEfuseContent[Offset] = Value; 73 else { 74 fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value; 75 } 76 return true; 77 } 78 79 /*----------------------------------------------------------------------------- 80 * Function: Efuse_PowerSwitch 81 * 82 * Overview: When we want to enable write operation, we should change to 83 * pwr on state. When we stop write, we should switch to 500k mode 84 * and disable LDO 2.5V. 85 * 86 * Input: NONE 87 * 88 * Output: NONE 89 * 90 * Return: NONE 91 * 92 * Revised History: 93 * When Who Remark 94 * 11/17/2008 MHC Create Version 0. 95 * 96 *---------------------------------------------------------------------------*/ 97 void 98 Efuse_PowerSwitch( 99 struct adapter *padapter, 100 u8 bWrite, 101 u8 PwrState) 102 { 103 padapter->HalFunc.EfusePowerSwitch(padapter, bWrite, PwrState); 104 } 105 106 /*----------------------------------------------------------------------------- 107 * Function: Efuse_GetCurrentSize 108 * 109 * Overview: Get current efuse size!!! 110 * 111 * Input: NONE 112 * 113 * Output: NONE 114 * 115 * Return: NONE 116 * 117 * Revised History: 118 * When Who Remark 119 * 11/16/2008 MHC Create Version 0. 120 * 121 *---------------------------------------------------------------------------*/ 122 u16 123 Efuse_GetCurrentSize( 124 struct adapter *padapter, 125 u8 efuseType, 126 bool bPseudoTest) 127 { 128 return padapter->HalFunc.EfuseGetCurrentSize(padapter, efuseType, 129 bPseudoTest); 130 } 131 132 /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ 133 u8 134 Efuse_CalculateWordCnts(u8 word_en) 135 { 136 u8 word_cnts = 0; 137 if (!(word_en & BIT(0))) 138 word_cnts++; /* 0 : write enable */ 139 if (!(word_en & BIT(1))) 140 word_cnts++; 141 if (!(word_en & BIT(2))) 142 word_cnts++; 143 if (!(word_en & BIT(3))) 144 word_cnts++; 145 return word_cnts; 146 } 147 148 /* */ 149 /* Description: */ 150 /* 1. Execute E-Fuse read byte operation according as map offset and */ 151 /* save to E-Fuse table. */ 152 /* 2. Referred from SD1 Richard. */ 153 /* */ 154 /* Assumption: */ 155 /* 1. Boot from E-Fuse and successfully auto-load. */ 156 /* 2. PASSIVE_LEVEL (USB interface) */ 157 /* */ 158 /* Created by Roger, 2008.10.21. */ 159 /* */ 160 /* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ 161 /* 2. Add efuse utilization collect. */ 162 /* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ 163 /* write addr must be after sec5. */ 164 /* */ 165 166 void 167 efuse_ReadEFuse( 168 struct adapter *Adapter, 169 u8 efuseType, 170 u16 _offset, 171 u16 _size_byte, 172 u8 *pbuf, 173 bool bPseudoTest 174 ); 175 void 176 efuse_ReadEFuse( 177 struct adapter *Adapter, 178 u8 efuseType, 179 u16 _offset, 180 u16 _size_byte, 181 u8 *pbuf, 182 bool bPseudoTest 183 ) 184 { 185 Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); 186 } 187 188 void 189 EFUSE_GetEfuseDefinition( 190 struct adapter *padapter, 191 u8 efuseType, 192 u8 type, 193 void *pOut, 194 bool bPseudoTest 195 ) 196 { 197 padapter->HalFunc.EFUSEGetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); 198 } 199 200 /*----------------------------------------------------------------------------- 201 * Function: EFUSE_Read1Byte 202 * 203 * Overview: Copy from WMAC fot EFUSE read 1 byte. 204 * 205 * Input: NONE 206 * 207 * Output: NONE 208 * 209 * Return: NONE 210 * 211 * Revised History: 212 * When Who Remark 213 * 09/23/2008 MHC Copy from WMAC. 214 * 215 *---------------------------------------------------------------------------*/ 216 u8 217 EFUSE_Read1Byte( 218 struct adapter *Adapter, 219 u16 Address) 220 { 221 u8 Bytetemp = {0x00}; 222 u8 temp = {0x00}; 223 u32 k = 0; 224 u16 contentLen = 0; 225 226 EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); 227 228 if (Address < contentLen) {/* E-fuse 512Byte */ 229 /* Write E-fuse Register address bit0~7 */ 230 temp = Address & 0xFF; 231 rtw_write8(Adapter, EFUSE_CTRL+1, temp); 232 Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); 233 /* Write E-fuse Register address bit8~9 */ 234 temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); 235 rtw_write8(Adapter, EFUSE_CTRL+2, temp); 236 237 /* Write 0x30[31]= 0 */ 238 Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); 239 temp = Bytetemp & 0x7F; 240 rtw_write8(Adapter, EFUSE_CTRL+3, temp); 241 242 /* Wait Write-ready (0x30[31]= 1) */ 243 Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); 244 while (!(Bytetemp & 0x80)) { 245 Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); 246 k++; 247 if (k == 1000) { 248 k = 0; 249 break; 250 } 251 } 252 return rtw_read8(Adapter, EFUSE_CTRL); 253 } else 254 return 0xFF; 255 256 } /* EFUSE_Read1Byte */ 257 258 /* 11/16/2008 MH Read one byte from real Efuse. */ 259 u8 260 efuse_OneByteRead( 261 struct adapter *padapter, 262 u16 addr, 263 u8 *data, 264 bool bPseudoTest) 265 { 266 u32 tmpidx = 0; 267 u8 bResult; 268 u8 readbyte; 269 270 /* DBG_871X("===> EFUSE_OneByteRead(), addr = %x\n", addr); */ 271 /* DBG_871X("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ 272 273 if (bPseudoTest) { 274 bResult = Efuse_Read1ByteFromFakeContent(padapter, addr, data); 275 return bResult; 276 } 277 278 /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ 279 /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ 280 /* PHY_SetMacReg(padapter, 0x34, BIT11, 0); */ 281 rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34) & (~BIT11)); 282 283 /* -----------------e-fuse reg ctrl --------------------------------- */ 284 /* address */ 285 rtw_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xff)); 286 rtw_write8(padapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) | 287 (rtw_read8(padapter, EFUSE_CTRL+2)&0xFC)); 288 289 /* rtw_write8(padapter, EFUSE_CTRL+3, 0x72); read cmd */ 290 /* Write bit 32 0 */ 291 readbyte = rtw_read8(padapter, EFUSE_CTRL+3); 292 rtw_write8(padapter, EFUSE_CTRL+3, (readbyte & 0x7f)); 293 294 while (!(0x80 & rtw_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 1000)) { 295 mdelay(1); 296 tmpidx++; 297 } 298 if (tmpidx < 100) { 299 *data = rtw_read8(padapter, EFUSE_CTRL); 300 bResult = true; 301 } else { 302 *data = 0xff; 303 bResult = false; 304 DBG_871X("%s: [ERROR] addr = 0x%x bResult =%d time out 1s !!!\n", __func__, addr, bResult); 305 DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); 306 } 307 308 return bResult; 309 } 310 311 /* 11/16/2008 MH Write one byte to reald Efuse. */ 312 u8 313 efuse_OneByteWrite( 314 struct adapter *padapter, 315 u16 addr, 316 u8 data, 317 bool bPseudoTest) 318 { 319 u8 tmpidx = 0; 320 u8 bResult = false; 321 u32 efuseValue = 0; 322 323 /* DBG_871X("===> EFUSE_OneByteWrite(), addr = %x data =%x\n", addr, data); */ 324 /* DBG_871X("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ 325 326 if (bPseudoTest) { 327 bResult = Efuse_Write1ByteToFakeContent(padapter, addr, data); 328 return bResult; 329 } 330 331 332 /* -----------------e-fuse reg ctrl --------------------------------- */ 333 /* address */ 334 335 336 efuseValue = rtw_read32(padapter, EFUSE_CTRL); 337 efuseValue |= (BIT21|BIT31); 338 efuseValue &= ~(0x3FFFF); 339 efuseValue |= ((addr<<8 | data) & 0x3FFFF); 340 341 342 /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ 343 344 /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ 345 /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ 346 /* PHY_SetMacReg(padapter, 0x34, BIT11, 1); */ 347 rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34) | (BIT11)); 348 rtw_write32(padapter, EFUSE_CTRL, 0x90600000|((addr<<8 | data))); 349 350 while ((0x80 & rtw_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 100)) { 351 mdelay(1); 352 tmpidx++; 353 } 354 355 if (tmpidx < 100) { 356 bResult = true; 357 } else { 358 bResult = false; 359 DBG_871X("%s: [ERROR] addr = 0x%x , efuseValue = 0x%x , bResult =%d time out 1s !!!\n", 360 __func__, addr, efuseValue, bResult); 361 DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); 362 } 363 364 /* disable Efuse program enable */ 365 PHY_SetMacReg(padapter, EFUSE_TEST, BIT(11), 0); 366 367 return bResult; 368 } 369 370 int 371 Efuse_PgPacketRead(struct adapter *padapter, 372 u8 offset, 373 u8 *data, 374 bool bPseudoTest) 375 { 376 return padapter->HalFunc.Efuse_PgPacketRead(padapter, offset, data, 377 bPseudoTest); 378 } 379 380 int 381 Efuse_PgPacketWrite(struct adapter *padapter, 382 u8 offset, 383 u8 word_en, 384 u8 *data, 385 bool bPseudoTest) 386 { 387 return padapter->HalFunc.Efuse_PgPacketWrite(padapter, offset, word_en, 388 data, bPseudoTest); 389 } 390 391 /*----------------------------------------------------------------------------- 392 * Function: efuse_WordEnableDataRead 393 * 394 * Overview: Read allowed word in current efuse section data. 395 * 396 * Input: NONE 397 * 398 * Output: NONE 399 * 400 * Return: NONE 401 * 402 * Revised History: 403 * When Who Remark 404 * 11/16/2008 MHC Create Version 0. 405 * 11/21/2008 MHC Fix Write bug when we only enable late word. 406 * 407 *---------------------------------------------------------------------------*/ 408 void 409 efuse_WordEnableDataRead(u8 word_en, 410 u8 *sourdata, 411 u8 *targetdata) 412 { 413 if (!(word_en&BIT(0))) { 414 targetdata[0] = sourdata[0]; 415 targetdata[1] = sourdata[1]; 416 } 417 if (!(word_en&BIT(1))) { 418 targetdata[2] = sourdata[2]; 419 targetdata[3] = sourdata[3]; 420 } 421 if (!(word_en&BIT(2))) { 422 targetdata[4] = sourdata[4]; 423 targetdata[5] = sourdata[5]; 424 } 425 if (!(word_en&BIT(3))) { 426 targetdata[6] = sourdata[6]; 427 targetdata[7] = sourdata[7]; 428 } 429 } 430 431 432 u8 433 Efuse_WordEnableDataWrite(struct adapter *padapter, 434 u16 efuse_addr, 435 u8 word_en, 436 u8 *data, 437 bool bPseudoTest) 438 { 439 return padapter->HalFunc.Efuse_WordEnableDataWrite(padapter, efuse_addr, 440 word_en, data, 441 bPseudoTest); 442 } 443 444 /*----------------------------------------------------------------------------- 445 * Function: Efuse_ReadAllMap 446 * 447 * Overview: Read All Efuse content 448 * 449 * Input: NONE 450 * 451 * Output: NONE 452 * 453 * Return: NONE 454 * 455 * Revised History: 456 * When Who Remark 457 * 11/11/2008 MHC Create Version 0. 458 * 459 *---------------------------------------------------------------------------*/ 460 void 461 Efuse_ReadAllMap( 462 struct adapter *padapter, 463 u8 efuseType, 464 u8 *Efuse, 465 bool bPseudoTest); 466 void 467 Efuse_ReadAllMap( 468 struct adapter *padapter, 469 u8 efuseType, 470 u8 *Efuse, 471 bool bPseudoTest) 472 { 473 u16 mapLen = 0; 474 475 Efuse_PowerSwitch(padapter, false, true); 476 477 EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); 478 479 efuse_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, bPseudoTest); 480 481 Efuse_PowerSwitch(padapter, false, false); 482 } 483 484 /*----------------------------------------------------------------------------- 485 * Function: efuse_ShadowRead1Byte 486 * efuse_ShadowRead2Byte 487 * efuse_ShadowRead4Byte 488 * 489 * Overview: Read from efuse init map by one/two/four bytes !!!!! 490 * 491 * Input: NONE 492 * 493 * Output: NONE 494 * 495 * Return: NONE 496 * 497 * Revised History: 498 * When Who Remark 499 * 11/12/2008 MHC Create Version 0. 500 * 501 *---------------------------------------------------------------------------*/ 502 static void 503 efuse_ShadowRead1Byte( 504 struct adapter *padapter, 505 u16 Offset, 506 u8 *Value) 507 { 508 struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); 509 510 *Value = pEEPROM->efuse_eeprom_data[Offset]; 511 512 } /* EFUSE_ShadowRead1Byte */ 513 514 /* Read Two Bytes */ 515 static void 516 efuse_ShadowRead2Byte( 517 struct adapter *padapter, 518 u16 Offset, 519 u16 *Value) 520 { 521 struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); 522 523 *Value = pEEPROM->efuse_eeprom_data[Offset]; 524 *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; 525 526 } /* EFUSE_ShadowRead2Byte */ 527 528 /* Read Four Bytes */ 529 static void 530 efuse_ShadowRead4Byte( 531 struct adapter *padapter, 532 u16 Offset, 533 u32 *Value) 534 { 535 struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); 536 537 *Value = pEEPROM->efuse_eeprom_data[Offset]; 538 *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; 539 *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; 540 *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; 541 542 } /* efuse_ShadowRead4Byte */ 543 544 /*----------------------------------------------------------------------------- 545 * Function: EFUSE_ShadowMapUpdate 546 * 547 * Overview: Transfer current EFUSE content to shadow init and modify map. 548 * 549 * Input: NONE 550 * 551 * Output: NONE 552 * 553 * Return: NONE 554 * 555 * Revised History: 556 * When Who Remark 557 * 11/13/2008 MHC Create Version 0. 558 * 559 *---------------------------------------------------------------------------*/ 560 void EFUSE_ShadowMapUpdate( 561 struct adapter *padapter, 562 u8 efuseType, 563 bool bPseudoTest) 564 { 565 struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); 566 u16 mapLen = 0; 567 568 EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); 569 570 if (pEEPROM->bautoload_fail_flag) 571 memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); 572 else 573 Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data, bPseudoTest); 574 575 /* PlatformMoveMemory((void *)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ 576 /* void *)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ 577 } /* EFUSE_ShadowMapUpdate */ 578 579 580 /*----------------------------------------------------------------------------- 581 * Function: EFUSE_ShadowRead 582 * 583 * Overview: Read from efuse init map !!!!! 584 * 585 * Input: NONE 586 * 587 * Output: NONE 588 * 589 * Return: NONE 590 * 591 * Revised History: 592 * When Who Remark 593 * 11/12/2008 MHC Create Version 0. 594 * 595 *---------------------------------------------------------------------------*/ 596 void 597 EFUSE_ShadowRead( 598 struct adapter *padapter, 599 u8 Type, 600 u16 Offset, 601 u32 *Value) 602 { 603 if (Type == 1) 604 efuse_ShadowRead1Byte(padapter, Offset, (u8 *)Value); 605 else if (Type == 2) 606 efuse_ShadowRead2Byte(padapter, Offset, (u16 *)Value); 607 else if (Type == 4) 608 efuse_ShadowRead4Byte(padapter, Offset, (u32 *)Value); 609 610 } /* EFUSE_ShadowRead*/ 611