// SPDX-License-Identifier: GPL-2.0 /****************************************************************************** * * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. * ******************************************************************************/ #define _RTW_EFUSE_C_ #include #include #include #include /* Define global variables */ 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 REG_EFUSE_CTRL 0x0030 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ bool Efuse_Read1ByteFromFakeContent( struct adapter *padapter, u16 Offset, u8 *Value); bool Efuse_Read1ByteFromFakeContent( struct adapter *padapter, u16 Offset, u8 *Value) { if (Offset >= EFUSE_MAX_HW_SIZE) { return false; } /* DbgPrint("Read fake content, offset = %d\n", Offset); */ if (fakeEfuseBank == 0) *Value = fakeEfuseContent[Offset]; else *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset]; return true; } bool Efuse_Write1ByteToFakeContent( struct adapter *padapter, u16 Offset, u8 Value); 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; } /*----------------------------------------------------------------------------- * Function: Efuse_PowerSwitch * * Overview: When we want to enable write operation, we should change to * pwr on state. When we stop write, we should switch to 500k mode * and disable LDO 2.5V. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/17/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ void Efuse_PowerSwitch( struct adapter *padapter, u8 bWrite, u8 PwrState) { padapter->HalFunc.EfusePowerSwitch(padapter, bWrite, PwrState); } /*----------------------------------------------------------------------------- * Function: Efuse_GetCurrentSize * * Overview: Get current efuse size!!! * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/16/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ u16 Efuse_GetCurrentSize( struct adapter *padapter, u8 efuseType, bool bPseudoTest) { u16 ret = 0; ret = padapter->HalFunc.EfuseGetCurrentSize(padapter, efuseType, bPseudoTest); return ret; } /* 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: */ /* 1. Execute E-Fuse read byte operation according as map offset and */ /* save to E-Fuse table. */ /* 2. 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. */ /* */ /* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ /* 2. Add efuse utilization collect. */ /* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ /* write addr must be after sec5. */ /* */ void efuse_ReadEFuse( struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest ); void efuse_ReadEFuse( struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest ) { Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); } void EFUSE_GetEfuseDefinition( struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest ) { padapter->HalFunc.EFUSEGetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); } /*----------------------------------------------------------------------------- * Function: EFUSE_Read1Byte * * Overview: Copy from WMAC fot EFUSE read 1 byte. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 09/23/2008 MHC Copy from WMAC. * *---------------------------------------------------------------------------*/ u8 EFUSE_Read1Byte( struct adapter *Adapter, u16 Address) { u8 data; u8 Bytetemp = {0x00}; u8 temp = {0x00}; u32 k = 0; u16 contentLen = 0; EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); if (Address < contentLen) {/* E-fuse 512Byte */ /* Write E-fuse Register address bit0~7 */ temp = Address & 0xFF; rtw_write8(Adapter, EFUSE_CTRL+1, temp); Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); /* Write E-fuse Register address bit8~9 */ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); rtw_write8(Adapter, EFUSE_CTRL+2, temp); /* Write 0x30[31]= 0 */ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); temp = Bytetemp & 0x7F; rtw_write8(Adapter, EFUSE_CTRL+3, temp); /* Wait Write-ready (0x30[31]= 1) */ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); while (!(Bytetemp & 0x80)) { Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); k++; if (k == 1000) { k = 0; break; } } data = rtw_read8(Adapter, EFUSE_CTRL); return data; } else return 0xFF; } /* EFUSE_Read1Byte */ /* 11/16/2008 MH Read one byte from real Efuse. */ u8 efuse_OneByteRead( struct adapter *padapter, u16 addr, u8 *data, bool bPseudoTest) { u32 tmpidx = 0; u8 bResult; u8 readbyte; /* DBG_871X("===> EFUSE_OneByteRead(), addr = %x\n", addr); */ /* DBG_871X("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ if (bPseudoTest) { bResult = Efuse_Read1ByteFromFakeContent(padapter, addr, data); return bResult; } /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ /* PHY_SetMacReg(padapter, 0x34, BIT11, 0); */ rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34) & (~BIT11)); /* -----------------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 */ /* Write bit 32 0 */ readbyte = rtw_read8(padapter, EFUSE_CTRL+3); rtw_write8(padapter, EFUSE_CTRL+3, (readbyte & 0x7f)); while (!(0x80 & rtw_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 1000)) { mdelay(1); tmpidx++; } if (tmpidx < 100) { *data = rtw_read8(padapter, EFUSE_CTRL); bResult = true; } else{ *data = 0xff; bResult = false; DBG_871X("%s: [ERROR] addr = 0x%x bResult =%d time out 1s !!!\n", __func__, addr, bResult); DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); } return bResult; } /* 11/16/2008 MH Write one byte to reald Efuse. */ u8 efuse_OneByteWrite( struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest) { u8 tmpidx = 0; u8 bResult = false; u32 efuseValue = 0; /* DBG_871X("===> EFUSE_OneByteWrite(), addr = %x data =%x\n", addr, data); */ /* DBG_871X("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ if (bPseudoTest) { bResult = Efuse_Write1ByteToFakeContent(padapter, addr, data); return bResult; } /* -----------------e-fuse reg ctrl --------------------------------- */ /* address */ efuseValue = rtw_read32(padapter, EFUSE_CTRL); efuseValue |= (BIT21|BIT31); efuseValue &= ~(0x3FFFF); efuseValue |= ((addr<<8 | data) & 0x3FFFF); /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ /* PHY_SetMacReg(padapter, 0x34, BIT11, 1); */ rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34) | (BIT11)); rtw_write32(padapter, EFUSE_CTRL, 0x90600000|((addr<<8 | data))); while ((0x80 & rtw_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 100)) { mdelay(1); tmpidx++; } if (tmpidx < 100) { bResult = true; } else{ bResult = false; DBG_871X("%s: [ERROR] addr = 0x%x , efuseValue = 0x%x , bResult =%d time out 1s !!!\n", __func__, addr, efuseValue, bResult); DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); } /* disable Efuse program enable */ PHY_SetMacReg(padapter, EFUSE_TEST, BIT(11), 0); return bResult; } int Efuse_PgPacketRead(struct adapter *padapter, u8 offset, u8 *data, bool bPseudoTest) { int ret = 0; ret = padapter->HalFunc.Efuse_PgPacketRead(padapter, offset, data, bPseudoTest); return ret; } int Efuse_PgPacketWrite(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) { int ret; ret = padapter->HalFunc.Efuse_PgPacketWrite(padapter, offset, word_en, data, bPseudoTest); return ret; } /*----------------------------------------------------------------------------- * 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]; } } u8 Efuse_WordEnableDataWrite(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) { u8 ret = 0; ret = padapter->HalFunc.Efuse_WordEnableDataWrite(padapter, efuse_addr, word_en, data, bPseudoTest); return ret; } /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ void Efuse_ReadAllMap( struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest); void Efuse_ReadAllMap( struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest) { u16 mapLen = 0; Efuse_PowerSwitch(padapter, false, true); EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); efuse_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, bPseudoTest); Efuse_PowerSwitch(padapter, false, false); } /*----------------------------------------------------------------------------- * Function: efuse_ShadowRead1Byte * efuse_ShadowRead2Byte * efuse_ShadowRead4Byte * * Overview: Read from efuse init map by one/two/four bytes !!!!! * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ static void efuse_ShadowRead1Byte( struct adapter *padapter, u16 Offset, u8 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); *Value = pEEPROM->efuse_eeprom_data[Offset]; } /* EFUSE_ShadowRead1Byte */ /* Read Two Bytes */ static void efuse_ShadowRead2Byte( struct adapter *padapter, u16 Offset, u16 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); *Value = pEEPROM->efuse_eeprom_data[Offset]; *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; } /* EFUSE_ShadowRead2Byte */ /* Read Four Bytes */ static void efuse_ShadowRead4Byte( struct adapter *padapter, u16 Offset, u32 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); *Value = pEEPROM->efuse_eeprom_data[Offset]; *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; } /* efuse_ShadowRead4Byte */ /*----------------------------------------------------------------------------- * 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 bPseudoTest) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); u16 mapLen = 0; EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); if (pEEPROM->bautoload_fail_flag) memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); else Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data, bPseudoTest); /* PlatformMoveMemory((void *)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ /* void *)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ } /* EFUSE_ShadowMapUpdate */ /*----------------------------------------------------------------------------- * Function: EFUSE_ShadowRead * * Overview: Read from efuse init map !!!!! * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ void EFUSE_ShadowRead( struct adapter *padapter, u8 Type, u16 Offset, u32 *Value) { if (Type == 1) efuse_ShadowRead1Byte(padapter, Offset, (u8 *)Value); else if (Type == 2) efuse_ShadowRead2Byte(padapter, Offset, (u16 *)Value); else if (Type == 4) efuse_ShadowRead4Byte(padapter, Offset, (u32 *)Value); } /* EFUSE_ShadowRead*/