blob: 44b92ef5db926fb923677fe2364632d0eeae475f [file] [log] [blame]
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
******************************************************************************/
#define _RTW_EFUSE_C_
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_data.h>
#include <linux/jiffies.h>
/*------------------------Define local variable------------------------------*/
u8 fakeEfuseBank = 0;
u32 fakeEfuseUsedBytes = 0;
u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
u32 BTEfuseUsedBytes = 0;
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 = 0;
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. */
/* */
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 == true) {
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*/