// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2007 - 2011 Realtek Corporation. */ #define _RTW_EFUSE_C_ #include "../include/osdep_service.h" #include "../include/drv_types.h" #include "../include/rtw_efuse.h" /*------------------------Define local variable------------------------------*/ u8 fakeEfuseBank; u32 fakeEfuseUsedBytes; u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; u32 BTEfuseUsedBytes; u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; u32 fakeBTEfuseUsedBytes; u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; /*------------------------Define local variable------------------------------*/ #define REG_EFUSE_CTRL 0x0030 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ static bool Efuse_Read1ByteFromFakeContent(u16 Offset, u8 *Value) { if (Offset >= EFUSE_MAX_HW_SIZE) return false; if (fakeEfuseBank == 0) *Value = fakeEfuseContent[Offset]; else *Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset]; return true; } static bool Efuse_Write1ByteToFakeContent( struct adapter *pAdapter, u16 Offset, u8 Value) { if (Offset >= EFUSE_MAX_HW_SIZE) return false; if (fakeEfuseBank == 0) { fakeEfuseContent[Offset] = Value; } else { fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value; } return true; } /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ u8 Efuse_CalculateWordCnts(u8 word_en) { u8 word_cnts = 0; if (!(word_en & BIT(0))) word_cnts++; /* 0 : write enable */ if (!(word_en & BIT(1))) word_cnts++; if (!(word_en & BIT(2))) word_cnts++; if (!(word_en & BIT(3))) word_cnts++; return word_cnts; } /* */ /* Description: */ /* Execute E-Fuse read byte operation. */ /* Referred from SD1 Richard. */ /* */ /* Assumption: */ /* 1. Boot from E-Fuse and successfully auto-load. */ /* 2. PASSIVE_LEVEL (USB interface) */ /* */ /* Created by Roger, 2008.10.21. */ /* */ void ReadEFuseByte( struct adapter *Adapter, u16 _offset, u8 *pbuf, bool pseudo) { u32 value32; u8 readbyte; u16 retry; if (pseudo) { Efuse_Read1ByteFromFakeContent(_offset, pbuf); return; } /* Write Address */ rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff)); readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2); rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); /* Write bit 32 0 */ readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3); rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); /* Check bit 32 read-ready */ retry = 0; value32 = rtw_read32(Adapter, EFUSE_CTRL); while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { value32 = rtw_read32(Adapter, EFUSE_CTRL); retry++; } /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ /* This fix the problem that Efuse read error in high temperature condition. */ /* Designer says that there shall be some delay after ready bit is set, or the */ /* result will always stay on last data we read. */ udelay(50); value32 = rtw_read32(Adapter, EFUSE_CTRL); *pbuf = (u8)(value32 & 0xff); } /* 11/16/2008 MH Read one byte from real Efuse. */ u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data, bool pseudo) { u8 tmpidx = 0; u8 result; if (pseudo) { result = Efuse_Read1ByteFromFakeContent(addr, data); return result; } /* -----------------e-fuse reg ctrl --------------------------------- */ /* address */ rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC)); rtw_write8(pAdapter, EFUSE_CTRL + 3, 0x72);/* read cmd */ while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) tmpidx++; if (tmpidx < 100) { *data = rtw_read8(pAdapter, EFUSE_CTRL); result = true; } else { *data = 0xff; result = false; } return result; } /* 11/16/2008 MH Write one byte to reald Efuse. */ u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data, bool pseudo) { u8 tmpidx = 0; u8 result; if (pseudo) { result = Efuse_Write1ByteToFakeContent(pAdapter, addr, data); return result; } /* -----------------e-fuse reg ctrl --------------------------------- */ /* address */ rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); rtw_write8(pAdapter, EFUSE_CTRL + 2, (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC) | (u8)((addr >> 8) & 0x03)); rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */ rtw_write8(pAdapter, EFUSE_CTRL + 3, 0xF2);/* write cmd */ while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) tmpidx++; if (tmpidx < 100) result = true; else result = false; return result; } /*----------------------------------------------------------------------------- * Function: efuse_WordEnableDataRead * * Overview: Read allowed word in current efuse section data. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/16/2008 MHC Create Version 0. * 11/21/2008 MHC Fix Write bug when we only enable late word. * *---------------------------------------------------------------------------*/ void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata) { if (!(word_en & BIT(0))) { targetdata[0] = sourdata[0]; targetdata[1] = sourdata[1]; } if (!(word_en & BIT(1))) { targetdata[2] = sourdata[2]; targetdata[3] = sourdata[3]; } if (!(word_en & BIT(2))) { targetdata[4] = sourdata[4]; targetdata[5] = sourdata[5]; } if (!(word_en & BIT(3))) { targetdata[6] = sourdata[6]; targetdata[7] = sourdata[7]; } } /*----------------------------------------------------------------------------- * Function: Efuse_ReadAllMap * * Overview: Read All Efuse content * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/11/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse, bool pseudo) { u16 mapLen = 0; rtl8188e_EfusePowerSwitch(pAdapter, false, true); rtl8188e_EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo); rtl8188e_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, pseudo); rtl8188e_EfusePowerSwitch(pAdapter, false, false); } /*----------------------------------------------------------------------------- * Function: EFUSE_ShadowMapUpdate * * Overview: Transfer current EFUSE content to shadow init and modify map. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/13/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ void EFUSE_ShadowMapUpdate( struct adapter *pAdapter, u8 efuseType, bool pseudo) { struct eeprom_priv *pEEPROM = &pAdapter->eeprompriv; u16 mapLen = 0; rtl8188e_EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo); if (pEEPROM->bautoload_fail_flag) memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); else Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data, pseudo); } /* EFUSE_ShadowMapUpdate */