text: /******************************************************************************
   *
   * 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*/
  