/****************************************************************************** * * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. * * Module: Efuse.c ( Source C File) * * Note: Copy from WMAC for the first version!!!! * * * Function: * * Export: * * Abbrev: * * History: * Data Who Remark * * 09/23/2008 MHC Porting Efuse R/W API from WMAC. * 11/10/2008 MHC 1. Porting from 8712 EFUSE. * 2. Add description and reorganize code arch. * 11/16/2008 MHC 1. Reorganize code architecture. * 2. Rename for some API and change extern or static type. * ******************************************************************************/ #include "r8192U.h" #include "r8192S_hw.h" #include "r8192S_phy.h" #include "r8192S_phyreg.h" #include "r8192S_Efuse.h" #include //typedef int INT32; // // In the future, we will always support EFUSE!! // /*---------------------------Define Local Constant---------------------------*/ #define _POWERON_DELAY_ #define _PRE_EXECUTE_READ_CMD_ #define EFUSE_REPEAT_THRESHOLD_ 3 #define EFUSE_ERROE_HANDLE 1 // From 8712!!!!! typedef struct _EFUSE_MAP_A{ u8 offset; //0~15 u8 word_start; //0~3 u8 byte_start; //0 or 1 u8 byte_cnts; }EFUSE_MAP, *PEFUSE_MAP; typedef struct PG_PKT_STRUCT_A{ u8 offset; u8 word_en; u8 data[8]; }PGPKT_STRUCT,*PPGPKT_STRUCT; typedef enum _EFUSE_DATA_ITEM{ EFUSE_CHIP_ID=0, EFUSE_LDO_SETTING, EFUSE_CLK_SETTING, EFUSE_SDIO_SETTING, EFUSE_CCCR, EFUSE_SDIO_MODE, EFUSE_OCR, EFUSE_F0CIS, EFUSE_F1CIS, EFUSE_MAC_ADDR, EFUSE_EEPROM_VER, EFUSE_CHAN_PLAN, EFUSE_TXPW_TAB } EFUSE_DATA_ITEM; struct efuse_priv { u8 id[2]; u8 ldo_setting[2]; u8 clk_setting[2]; u8 cccr; u8 sdio_mode; u8 ocr[3]; u8 cis0[17]; u8 cis1[48]; u8 mac_addr[6]; u8 eeprom_verno; u8 channel_plan; u8 tx_power_b[14]; u8 tx_power_g[14]; }; /*---------------------------Define Local Constant---------------------------*/ /*------------------------Define global variable-----------------------------*/ const u8 MAX_PGPKT_SIZE = 9; //header+ 2* 4 words (BYTES) const u8 PGPKT_DATA_SIZE = 8; //BYTES sizeof(u8)*8 const u32 EFUSE_MAX_SIZE = 512; const EFUSE_MAP RTL8712_SDIO_EFUSE_TABLE[]={ //offset word_s byte_start byte_cnts /*ID*/ {0 ,0 ,0 ,2 }, // 00~01h /*LDO Setting*/ {0 ,1 ,0 ,2 }, // 02~03h /*CLK Setting*/ {0 ,2 ,0 ,2 }, // 04~05h /*SDIO Setting*/ {1 ,0 ,0 ,1 }, // 08h /*CCCR*/ {1 ,0 ,1 ,1 }, // 09h /*SDIO MODE*/ {1 ,1 ,0 ,1 }, // 0Ah /*OCR*/ {1 ,1 ,1 ,3 }, // 0B~0Dh /*CCIS*/ {1 ,3 ,0 ,17 }, // 0E~1Eh 2...1 /*F1CIS*/ {3 ,3 ,1 ,48 }, // 1F~4Eh 6...0 /*MAC Addr*/ {10 ,0 ,0 ,6 }, // 50~55h /*EEPROM ver*/ {10 ,3 ,0 ,1 }, // 56h /*Channel plan*/ {10 ,3 ,1 ,1 }, // 57h /*TxPwIndex */ {11 ,0 ,0 ,28 } // 58~73h 3...4 }; /*------------------------Define global variable-----------------------------*/ /*------------------------Define local variable------------------------------*/ /*------------------------Define local variable------------------------------*/ /*--------------------Define function prototype-----------------------*/ // // From WMAC Efuse one byte R/W // extern void EFUSE_Initialize(struct net_device* dev); extern u8 EFUSE_Read1Byte(struct net_device* dev, u16 Address); extern void EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value); // // Efuse Shadow Area operation // static void efuse_ShadowRead1Byte(struct net_device* dev,u16 Offset,u8 *Value); static void efuse_ShadowRead2Byte(struct net_device* dev, u16 Offset,u16 *Value ); static void efuse_ShadowRead4Byte(struct net_device* dev, u16 Offset,u32 *Value ); static void efuse_ShadowWrite1Byte(struct net_device* dev, u16 Offset, u8 Value); static void efuse_ShadowWrite2Byte(struct net_device* dev, u16 Offset,u16 Value); static void efuse_ShadowWrite4Byte(struct net_device* dev, u16 Offset,u32 Value); // // Real Efuse operation // static u8 efuse_OneByteRead(struct net_device* dev,u16 addr,u8 *data); static u8 efuse_OneByteWrite(struct net_device* dev,u16 addr, u8 data); // // HW setting map file operation // static void efuse_ReadAllMap(struct net_device* dev,u8 *Efuse); #ifdef TO_DO_LIST static void efuse_WriteAllMap(struct net_device* dev,u8 *eeprom,u32 eeprom_size); static bool efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove); #endif // // Reald Efuse R/W or other operation API. // static u8 efuse_PgPacketRead( struct net_device* dev,u8 offset,u8 *data); static u8 efuse_PgPacketWrite(struct net_device* dev,u8 offset,u8 word_en,u8 *data); static void efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata); static u8 efuse_WordEnableDataWrite( struct net_device* dev, u16 efuse_addr, u8 word_en, u8 *data); static void efuse_PowerSwitch(struct net_device* dev,u8 PwrState); static u16 efuse_GetCurrentSize(struct net_device* dev); static u8 efuse_CalculateWordCnts(u8 word_en); // // API for power on power off!!! // #ifdef TO_DO_LIST static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn); #endif /*--------------------Define function prototype-----------------------*/ /*----------------------------------------------------------------------------- * Function: EFUSE_Initialize * * Overview: Copy from WMAC fot EFUSE testing setting init. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 09/23/2008 MHC Copy from WMAC. * *---------------------------------------------------------------------------*/ extern void EFUSE_Initialize(struct net_device* dev) { u8 Bytetemp = {0x00}; u8 temp = {0x00}; //Enable Digital Core Vdd : 0x2[13]=1 Bytetemp = read_nic_byte(dev, SYS_FUNC_EN+1); temp = Bytetemp | 0x20; write_nic_byte(dev, SYS_FUNC_EN+1, temp); //EE loader to retention path1: attach 0x0[8]=0 Bytetemp = read_nic_byte(dev, SYS_ISO_CTRL+1); temp = Bytetemp & 0xFE; write_nic_byte(dev, SYS_ISO_CTRL+1, temp); //Enable E-fuse use 2.5V LDO : 0x37[7]=1 Bytetemp = read_nic_byte(dev, EFUSE_TEST+3); temp = Bytetemp | 0x80; write_nic_byte(dev, EFUSE_TEST+3, temp); //E-fuse clk switch from 500k to 40M : 0x2F8[1:0]=11b write_nic_byte(dev, 0x2F8, 0x3); //Set E-fuse program time & read time : 0x30[30:24]=1110010b write_nic_byte(dev, EFUSE_CTRL+3, 0x72); } /* EFUSE_Initialize */ /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ extern u8 EFUSE_Read1Byte(struct net_device* dev, u16 Address) { u8 data; u8 Bytetemp = {0x00}; u8 temp = {0x00}; u32 k=0; if (Address < EFUSE_MAC_LEN) //E-fuse 512Byte { //Write E-fuse Register address bit0~7 temp = Address & 0xFF; write_nic_byte(dev, EFUSE_CTRL+1, temp); Bytetemp = read_nic_byte(dev, EFUSE_CTRL+2); //Write E-fuse Register address bit8~9 temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); write_nic_byte(dev, EFUSE_CTRL+2, temp); //Write 0x30[31]=0 Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); temp = Bytetemp & 0x7F; write_nic_byte(dev, EFUSE_CTRL+3, temp); //Wait Write-ready (0x30[31]=1) Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); while(!(Bytetemp & 0x80)) { Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); k++; if(k==1000) { k=0; break; } } data=read_nic_byte(dev, EFUSE_CTRL); return data; } else return 0xFF; } /* EFUSE_Read1Byte */ /*----------------------------------------------------------------------------- * Function: EFUSE_Write1Byte * * Overview: Copy from WMAC fot EFUSE write 1 byte. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 09/23/2008 MHC Copy from WMAC. * *---------------------------------------------------------------------------*/ extern void EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value) { //u8 data; u8 Bytetemp = {0x00}; u8 temp = {0x00}; u32 k=0; //RT_TRACE(COMP_EFUSE, "Addr=%x Data =%x\n", Address, Value); if( Address < EFUSE_MAC_LEN) //E-fuse 512Byte { write_nic_byte(dev, EFUSE_CTRL, Value); //Write E-fuse Register address bit0~7 temp = Address & 0xFF; write_nic_byte(dev, EFUSE_CTRL+1, temp); Bytetemp = read_nic_byte(dev, EFUSE_CTRL+2); //Write E-fuse Register address bit8~9 temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); write_nic_byte(dev, EFUSE_CTRL+2, temp); //Write 0x30[31]=1 Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); temp = Bytetemp | 0x80; write_nic_byte(dev, EFUSE_CTRL+3, temp); //Wait Write-ready (0x30[31]=0) Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); while(Bytetemp & 0x80) { Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); k++; if(k==100) { k=0; break; } } } } /* EFUSE_Write1Byte */ #ifdef EFUSE_FOR_92SU // // Description: // 1. Process CR93C46 Data polling cycle. // 2. Refered 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 do_93c46(struct net_device* dev, u8 addorvalue) { //u8 clear[1] = {0x0}; // cs=0 , sk=0 , di=0 , do=0 u8 cs[1] = {0x88}; // cs=1 , sk=0 , di=0 , do=0 u8 cssk[1] = {0x8c}; // cs=1 , sk=1 , di=0 , do=0 u8 csdi[1] = {0x8a}; // cs=1 , sk=0 , di=1 , do=0 u8 csskdi[1] = {0x8e}; // cs=1 , sk=1 , di=1 , do=0 //u8 di[1] = {0x82}; // cs=0 , sk=0 , di=1 , do=0 u8 count; for(count=0 ; count<8 ; count++) { if((addorvalue&0x80)!=0) { write_nic_byte(dev, EPROM_CMD, csdi[0]); write_nic_byte(dev, EPROM_CMD, csskdi[0]); } else { write_nic_byte(dev, EPROM_CMD, cs[0]); write_nic_byte(dev, EPROM_CMD, cssk[0]); } addorvalue = addorvalue << 1; } } // // Description: // Process CR93C46 Data read polling cycle. // Refered from SD1 Richard. // // Assumption: // 1. Boot from E-Fuse and successfully auto-load. // 2. PASSIVE_LEVEL (USB interface) // // Created by Roger, 2008.10.21. // u16 Read93C46(struct net_device* dev, u16 Reg ) { u8 clear[1] = {0x0}; // cs=0 , sk=0 , di=0 , do=0 u8 cs[1] = {0x88}; // cs=1 , sk=0 , di=0 , do=0 u8 cssk[1] = {0x8c}; // cs=1 , sk=1 , di=0 , do=0 u8 csdi[1] = {0x8a}; // cs=1 , sk=0 , di=1 , do=0 u8 csskdi[1] = {0x8e}; // cs=1 , sk=1 , di=1 , do=0 //u8 di[1] = {0x82}; // cs=0 , sk=0 , di=1 , do=0 u8 EepromSEL[1]={0x00}; u8 address; u16 storedataF[1] = {0x0}; //93c46 data packet for 16bits u8 t,data[1],storedata[1]; address = (u8)Reg; // Suggested by SD1 Alex, 2008.10.20. Revised by Roger. *EepromSEL= read_nic_byte(dev, EPROM_CMD); if((*EepromSEL & 0x10) == 0x10) // select 93c46 { address = address | 0x80; write_nic_byte(dev, EPROM_CMD, csdi[0]); write_nic_byte(dev, EPROM_CMD, csskdi[0]); do_93c46(dev, address); } for(t=0 ; t<16 ; t++) //if read 93c46 , t=16 { write_nic_byte(dev, EPROM_CMD, cs[0]); write_nic_byte(dev, EPROM_CMD, cssk[0]); *data= read_nic_byte(dev, EPROM_CMD); if(*data & 0x8d) //original code { *data = *data & 0x01; *storedata = *data; } else { *data = *data & 0x01 ; *storedata = *data; } *storedataF = (*storedataF << 1 ) + *storedata; } write_nic_byte(dev, EPROM_CMD, cs[0]); write_nic_byte(dev, EPROM_CMD, clear[0]); return *storedataF; } // // Description: // Execute E-Fuse read byte operation. // Refered 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 net_device* dev,u16 _offset, u8 *pbuf) { //u16 indexk=0; u32 value32; u8 readbyte; u16 retry; //Write Address write_nic_byte(dev, EFUSE_CTRL+1, (_offset & 0xff)); readbyte = read_nic_byte(dev, EFUSE_CTRL+2); write_nic_byte(dev, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); //Write bit 32 0 readbyte = read_nic_byte(dev, EFUSE_CTRL+3); write_nic_byte(dev, EFUSE_CTRL+3, (readbyte & 0x7f)); //Check bit 32 read-ready retry = 0; value32 = read_nic_dword(dev, EFUSE_CTRL); //while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000)) { value32 = read_nic_dword(dev, EFUSE_CTRL); retry++; } *pbuf = (u8)(value32 & 0xff); } #define EFUSE_READ_SWITCH 1 // // Description: // 1. Execute E-Fuse read byte operation according as map offset and // save to E-Fuse table. // 2. Refered 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 ReadEFuse(struct net_device* dev, u16 _offset, u16 _size_byte, u8 *pbuf) { u8 efuseTbl[128]; u8 rtemp8[1]; u16 eFuse_Addr = 0; u8 offset, wren; u16 i, j; u16 eFuseWord[16][4];// = {0xFF};//FIXLZM for(i=0; i<16; i++) for(j=0; j<4; j++) eFuseWord[i][j]=0xFF; // Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. if((_offset + _size_byte)>128) {// total E-Fuse table is 128bytes //RT_TRACE(COMP_EFUSE, "ReadEFuse(): Invalid offset(%#x) with read bytes(%#x)!!\n",_offset, _size_byte); printk("ReadEFuse(): Invalid offset with read bytes!!\n"); return; } // Refresh efuse init map as all oxFF. for (i = 0; i < 128; i++) efuseTbl[i] = 0xFF; #if (EFUSE_READ_SWITCH == 1) ReadEFuseByte(dev, eFuse_Addr, rtemp8); #else rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); #endif if(*rtemp8 != 0xFF) eFuse_Addr++; while((*rtemp8 != 0xFF) && (eFuse_Addr < 512)){ offset = ((*rtemp8 >> 4) & 0x0f); if(offset <= 0x0F){ wren = (*rtemp8 & 0x0f); for(i=0; i<4; i++){ if(!(wren & 0x01)){ #if (EFUSE_READ_SWITCH == 1) ReadEFuseByte(dev, eFuse_Addr, rtemp8); eFuse_Addr++; #else rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++; #endif eFuseWord[offset][i] = (*rtemp8 & 0xff); if(eFuse_Addr >= 512) break; #if (EFUSE_READ_SWITCH == 1) ReadEFuseByte(dev, eFuse_Addr, rtemp8); eFuse_Addr++; #else rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++; #endif eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00); if(eFuse_Addr >= 512) break; } wren >>= 1; } } #if (EFUSE_READ_SWITCH == 1) ReadEFuseByte(dev, eFuse_Addr, rtemp8); #else rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++; #endif if(*rtemp8 != 0xFF && (eFuse_Addr < 512)) eFuse_Addr++; } for(i=0; i<16; i++){ for(j=0; j<4; j++){ efuseTbl[(i*8)+(j*2)]=(eFuseWord[i][j] & 0xff); efuseTbl[(i*8)+((j*2)+1)]=((eFuseWord[i][j] >> 8) & 0xff); } } for(i=0; i<_size_byte; i++) pbuf[i] = efuseTbl[_offset+i]; } #endif // #if (EFUSE_FOR_92SU == 1) /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ extern void EFUSE_ShadowRead( struct net_device* dev, u8 Type, u16 Offset, u32 *Value) { //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); if (Type == 1) efuse_ShadowRead1Byte(dev, Offset, (u8 *)Value); else if (Type == 2) efuse_ShadowRead2Byte(dev, Offset, (u16 *)Value); else if (Type == 4) efuse_ShadowRead4Byte(dev, Offset, (u32 *)Value); } // EFUSE_ShadowRead /*----------------------------------------------------------------------------- * Function: EFUSE_ShadowWrite * * Overview: Write efuse modify map for later update operation to use!!!!! * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ extern void EFUSE_ShadowWrite( struct net_device* dev, u8 Type, u16 Offset,u32 Value) { //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); if (Offset >= 0x18 && Offset <= 0x1F) return; if (Type == 1) efuse_ShadowWrite1Byte(dev, Offset, (u8)Value); else if (Type == 2) efuse_ShadowWrite2Byte(dev, Offset, (u16)Value); else if (Type == 4) efuse_ShadowWrite4Byte(dev, Offset, (u32)Value); } // EFUSE_ShadowWrite /*----------------------------------------------------------------------------- * Function: EFUSE_ShadowUpdate * * Overview: Compare init and modify map to update Efuse!!!!! * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ extern void EFUSE_ShadowUpdate(struct net_device* dev) { //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); struct r8192_priv *priv = ieee80211_priv(dev); u16 i, offset, base = 0; u8 word_en = 0x0F; bool first_pg = false; // For Efuse write action, we must enable LDO2.5V and 40MHZ clk. efuse_PowerSwitch(dev, TRUE); // // Efuse support 16 write are with PG header packet!!!! // for (offset = 0; offset < 16; offset++) { // Offset 0x18-1F are reserved now!!! word_en = 0x0F; base = offset * 8; // // Decide Word Enable Bit for the Efuse section // One section contain 4 words = 8 bytes!!!!! // for (i = 0; i < 8; i++) { if (offset == 0 && priv->EfuseMap[EFUSE_INIT_MAP][base+i] == 0xFF) { first_pg = TRUE; } // 2008/12/11 MH HW autoload fail workaround for A/BCUT. if (first_pg == TRUE) { word_en &= ~(1<<(i/2)); priv->EfuseMap[EFUSE_INIT_MAP][base+i] = priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]; }else { if ( priv->EfuseMap[EFUSE_INIT_MAP][base+i] != priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]) { word_en &= ~(EFUSE_BIT(i/2)); //RT_TRACE(COMP_EFUSE, "Offset=%d Addr%x %x ==> %x Word_En=%02x\n", //offset, base+i, priv->EfuseMap[0][base+i], priv->EfuseMap[1][base+i],word_en); // Update init table!!! priv->EfuseMap[EFUSE_INIT_MAP][base+i] = priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]; } } } // // Call Efuse real write section !!!! // if (word_en != 0x0F) { u8 tmpdata[8]; //FIXLZM memcpy(tmpdata, &(priv->EfuseMap[EFUSE_MODIFY_MAP][base]), 8); //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("U-EFUSE\n"), tmpdata, 8); efuse_PgPacketWrite(dev,(u8)offset,word_en,tmpdata); } } // 2008/12/01 MH For Efuse HW load bug workarounf method!!!! // We will force write 0x10EC into address 10&11 after all Efuse content. // // For warm reboot, we must resume Efuse clock to 500K. efuse_PowerSwitch(dev, FALSE); // 2008/12/01 MH We update shadow content again!!!! EFUSE_ShadowMapUpdate(dev); } // EFUSE_ShadowUpdate /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ extern void EFUSE_ShadowMapUpdate(struct net_device* dev) { struct r8192_priv *priv = ieee80211_priv(dev); if (priv->AutoloadFailFlag == true){ memset(&(priv->EfuseMap[EFUSE_INIT_MAP][0]), 0xff, 128); }else{ efuse_ReadAllMap(dev, &priv->EfuseMap[EFUSE_INIT_MAP][0]); } //PlatformMoveMemory(&priv->EfuseMap[EFUSE_MODIFY_MAP][0], //&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);//FIXLZM memcpy(&priv->EfuseMap[EFUSE_MODIFY_MAP][0], &priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S); } // EFUSE_ShadowMapUpdate extern void EFUSE_ForceWriteVendorId( struct net_device* dev) { u8 tmpdata[8] = {0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF}; efuse_PowerSwitch(dev, TRUE); efuse_PgPacketWrite(dev, 1, 0xD, tmpdata); efuse_PowerSwitch(dev, FALSE); } // EFUSE_ForceWriteVendorId /*----------------------------------------------------------------------------- * 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 net_device* dev, u16 Offset, u8 *Value) { struct r8192_priv *priv = ieee80211_priv(dev); *Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset]; } // EFUSE_ShadowRead1Byte //---------------Read Two Bytes static void efuse_ShadowRead2Byte(struct net_device* dev, u16 Offset, u16 *Value) { struct r8192_priv *priv = ieee80211_priv(dev); *Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset]; *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1]<<8; } // EFUSE_ShadowRead2Byte //---------------Read Four Bytes static void efuse_ShadowRead4Byte(struct net_device* dev, u16 Offset, u32 *Value) { struct r8192_priv *priv = ieee80211_priv(dev); *Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset]; *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1]<<8; *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+2]<<16; *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+3]<<24; } // efuse_ShadowRead4Byte /*----------------------------------------------------------------------------- * Function: efuse_ShadowWrite1Byte * efuse_ShadowWrite2Byte * efuse_ShadowWrite4Byte * * Overview: Write efuse modify map by one/two/four byte. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ static void efuse_ShadowWrite1Byte(struct net_device* dev, u16 Offset, u8 Value) { struct r8192_priv *priv = ieee80211_priv(dev); priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = Value; } // efuse_ShadowWrite1Byte //---------------Write Two Bytes static void efuse_ShadowWrite2Byte(struct net_device* dev, u16 Offset, u16 Value) { struct r8192_priv *priv = ieee80211_priv(dev); priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = Value&0x00FF; priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1] = Value>>8; } // efuse_ShadowWrite1Byte //---------------Write Four Bytes static void efuse_ShadowWrite4Byte(struct net_device* dev, u16 Offset, u32 Value) { struct r8192_priv *priv = ieee80211_priv(dev); priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = (u8)(Value&0x000000FF); priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1] = (u8)((Value>>8)&0x0000FF); priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+2] = (u8)((Value>>16)&0x00FF); priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+3] = (u8)((Value>>24)&0xFF); } // efuse_ShadowWrite1Byte /* 11/16/2008 MH Read one byte from real Efuse. */ static u8 efuse_OneByteRead(struct net_device* dev, u16 addr,u8 *data) { u8 tmpidx = 0; u8 bResult; // -----------------e-fuse reg ctrl --------------------------------- //address write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff)); write_nic_byte(dev, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03) ) | (read_nic_byte(dev, EFUSE_CTRL+2)&0xFC )); write_nic_byte(dev, EFUSE_CTRL+3, 0x72);//read cmd while(!(0x80 &read_nic_byte(dev, EFUSE_CTRL+3))&&(tmpidx<100)) { tmpidx++; } if(tmpidx<100) { *data=read_nic_byte(dev, EFUSE_CTRL); bResult = TRUE; } else { *data = 0xff; bResult = FALSE; } return bResult; } // efuse_OneByteRead /* 11/16/2008 MH Write one byte to reald Efuse. */ static u8 efuse_OneByteWrite(struct net_device* dev, u16 addr, u8 data) { u8 tmpidx = 0; u8 bResult; //RT_TRACE(COMP_EFUSE, "Addr = %x Data=%x\n", addr, data); //return 0; // -----------------e-fuse reg ctrl --------------------------------- //address write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff)); write_nic_byte(dev, EFUSE_CTRL+2, read_nic_byte(dev, EFUSE_CTRL+2)|(u8)((addr>>8)&0x03) ); write_nic_byte(dev, EFUSE_CTRL, data);//data write_nic_byte(dev, EFUSE_CTRL+3, 0xF2);//write cmd while((0x80 & read_nic_byte(dev, EFUSE_CTRL+3)) && (tmpidx<100) ){ tmpidx++; } if(tmpidx<100) { bResult = TRUE; } else { bResult = FALSE; } return bResult; } // efuse_OneByteWrite /*----------------------------------------------------------------------------- * 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 net_device* dev, u8 *Efuse) { //u8 pg_data[8]; //u8 offset = 0; //u8 tmpidx; //static u8 index = 0; // // We must enable clock and LDO 2.5V otherwise, read all map will be fail!!!! // efuse_PowerSwitch(dev, TRUE); ReadEFuse(dev, 0, 128, Efuse); efuse_PowerSwitch(dev, FALSE); } // efuse_ReadAllMap /*----------------------------------------------------------------------------- * Function: efuse_WriteAllMap * * Overview: Write All Efuse content * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/11/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ #ifdef TO_DO_LIST static void efuse_WriteAllMap(struct net_device* dev,u8 *eeprom, u32 eeprom_size) { unsigned char word_en = 0x00; unsigned char tmpdata[8]; unsigned char offset; // For Efuse write action, we must enable LDO2.5V and 40MHZ clk. efuse_PowerSwitch(dev, TRUE); //sdio contents for(offset=0 ; offset< eeprom_size/PGPKT_DATA_SIZE ; offset++) { // 92S will only reserv 0x18-1F 8 bytes now. The 3rd efuse write area! if (IS_HARDWARE_TYPE_8192SE(dev)) { // Refer to // 0x18-1f Reserve >0x50 Reserve for tx power if (offset == 3/* || offset > 9*/) continue;//word_en = 0x0F; //else if (offset == 9) // 0x4c-4f Reserve //word_en = 0x0C; else word_en = 0x00; } //RT_TRACE(COMP_EFUSE, ("Addr=%d size=%d Word_En=%02x\n", offset, eeprom_size, word_en)); //memcpy(tmpdata,eeprom+(offset*PGPKT_DATA_SIZE),8); memcpy(tmpdata, (eeprom+(offset*PGPKT_DATA_SIZE)), 8); //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("EFUSE\t"), tmpdata, 8); efuse_PgPacketWrite(dev,offset,word_en,tmpdata); } // For warm reboot, we must resume Efuse clock to 500K. efuse_PowerSwitch(dev, FALSE); } // efuse_WriteAllMap #endif /*----------------------------------------------------------------------------- * Function: efuse_PgPacketRead * * Overview: Receive dedicated Efuse are content. For92s, we support 16 * area now. It will return 8 bytes content for every area. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/16/2008 MHC Reorganize code Arch and assign as local API. * *---------------------------------------------------------------------------*/ static u8 efuse_PgPacketRead( struct net_device* dev, u8 offset, u8 *data) { u8 ReadState = PG_STATE_HEADER; bool bContinual = TRUE; bool bDataEmpty = TRUE ; u8 efuse_data,word_cnts=0; u16 efuse_addr = 0; u8 hoffset=0,hworden=0; u8 tmpidx=0; u8 tmpdata[8]; if(data==NULL) return FALSE; if(offset>15) return FALSE; //FIXLZM //PlatformFillMemory((PVOID)data, sizeof(u8)*PGPKT_DATA_SIZE, 0xff); //PlatformFillMemory((PVOID)tmpdata, sizeof(u8)*PGPKT_DATA_SIZE, 0xff); memset(data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); memset(tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("efuse_PgPacketRead-1\n"), data, 8); //efuse_reg_ctrl(pAdapter,TRUE);//power on while(bContinual && (efuse_addr < EFUSE_MAX_SIZE) ) { //------- Header Read ------------- if(ReadState & PG_STATE_HEADER) { if(efuse_OneByteRead(dev, efuse_addr ,&efuse_data)&&(efuse_data!=0xFF)){ hoffset = (efuse_data>>4) & 0x0F; hworden = efuse_data & 0x0F; word_cnts = efuse_CalculateWordCnts(hworden); bDataEmpty = TRUE ; if(hoffset==offset){ for(tmpidx = 0;tmpidx< word_cnts*2 ;tmpidx++){ if(efuse_OneByteRead(dev, efuse_addr+1+tmpidx ,&efuse_data) ){ tmpdata[tmpidx] = efuse_data; if(efuse_data!=0xff){ bDataEmpty = FALSE; } } } if(bDataEmpty==FALSE){ ReadState = PG_STATE_DATA; }else{//read next header efuse_addr = efuse_addr + (word_cnts*2)+1; ReadState = PG_STATE_HEADER; } } else{//read next header efuse_addr = efuse_addr + (word_cnts*2)+1; ReadState = PG_STATE_HEADER; } } else{ bContinual = FALSE ; } } //------- Data section Read ------------- else if(ReadState & PG_STATE_DATA) { efuse_WordEnableDataRead(hworden,tmpdata,data); efuse_addr = efuse_addr + (word_cnts*2)+1; ReadState = PG_STATE_HEADER; } } //efuse_reg_ctrl(pAdapter,FALSE);//power off //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("efuse_PgPacketRead-2\n"), data, 8); if( (data[0]==0xff) &&(data[1]==0xff) && (data[2]==0xff) && (data[3]==0xff) && (data[4]==0xff) &&(data[5]==0xff) && (data[6]==0xff) && (data[7]==0xff)) return FALSE; else return TRUE; } // efuse_PgPacketRead /*----------------------------------------------------------------------------- * Function: efuse_PgPacketWrite * * Overview: Send A G package for different section in real efuse area. * For 92S, One PG package contain 8 bytes content and 4 word * unit. PG header = 0x[bit7-4=offset][bit3-0word enable] * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/16/2008 MHC Reorganize code Arch and assign as local API. * *---------------------------------------------------------------------------*/ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *data) { u8 WriteState = PG_STATE_HEADER; bool bContinual = TRUE,bDataEmpty=TRUE, bResult = TRUE; u16 efuse_addr = 0; u8 efuse_data; u8 pg_header = 0; //u16 tmp_addr=0; u8 tmp_word_cnts=0,target_word_cnts=0; u8 tmp_header,match_word_en,tmp_word_en; //u8 efuse_clk_ori,efuse_clk_new; PGPKT_STRUCT target_pkt; PGPKT_STRUCT tmp_pkt; u8 originaldata[sizeof(u8)*8]; u8 tmpindex = 0,badworden = 0x0F; static u32 repeat_times = 0; if( efuse_GetCurrentSize(dev) >= EFUSE_MAX_SIZE) { printk("efuse_PgPacketWrite error \n"); return FALSE; } // Init the 8 bytes content as 0xff target_pkt.offset = offset; target_pkt.word_en= word_en; //PlatformFillMemory((PVOID)target_pkt.data, sizeof(u8)*8, 0xFF); memset(target_pkt.data,0xFF,sizeof(u8)*8); efuse_WordEnableDataRead(word_en,data,target_pkt.data); target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en); //efuse_reg_ctrl(pAdapter,TRUE);//power on printk("EFUSE Power ON\n"); while( bContinual && (efuse_addr < EFUSE_MAX_SIZE) ) { if(WriteState==PG_STATE_HEADER) { bDataEmpty=TRUE; badworden = 0x0F; //************ so ******************* printk("EFUSE PG_STATE_HEADER\n"); if ( efuse_OneByteRead(dev, efuse_addr ,&efuse_data) && (efuse_data!=0xFF)) { tmp_header = efuse_data; tmp_pkt.offset = (tmp_header>>4) & 0x0F; tmp_pkt.word_en = tmp_header & 0x0F; tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); //************ so-1 ******************* if(tmp_pkt.offset != target_pkt.offset) { efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet #if (EFUSE_ERROE_HANDLE == 1) WriteState = PG_STATE_HEADER; #endif } else { //************ so-2 ******************* for(tmpindex=0 ; tmpindex<(tmp_word_cnts*2) ; tmpindex++) { if(efuse_OneByteRead(dev, (efuse_addr+1+tmpindex) ,&efuse_data)&&(efuse_data != 0xFF)){ bDataEmpty = FALSE; } } //************ so-2-1 ******************* if(bDataEmpty == FALSE) { efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet #if (EFUSE_ERROE_HANDLE == 1) WriteState=PG_STATE_HEADER; #endif } else {//************ so-2-2 ******************* match_word_en = 0x0F; if( !( (target_pkt.word_en&BIT0)|(tmp_pkt.word_en&BIT0) )) { match_word_en &= (~BIT0); } if( !( (target_pkt.word_en&BIT1)|(tmp_pkt.word_en&BIT1) )) { match_word_en &= (~BIT1); } if( !( (target_pkt.word_en&BIT2)|(tmp_pkt.word_en&BIT2) )) { match_word_en &= (~BIT2); } if( !( (target_pkt.word_en&BIT3)|(tmp_pkt.word_en&BIT3) )) { match_word_en &= (~BIT3); } //************ so-2-2-A ******************* if((match_word_en&0x0F)!=0x0F) { badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1, tmp_pkt.word_en ,target_pkt.data); //************ so-2-2-A-1 ******************* //############################ if(0x0F != (badworden&0x0F)) { u8 reorg_offset = offset; u8 reorg_worden=badworden; efuse_PgPacketWrite(dev,reorg_offset,reorg_worden,originaldata); } //############################ tmp_word_en = 0x0F; if( (target_pkt.word_en&BIT0)^(match_word_en&BIT0) ) { tmp_word_en &= (~BIT0); } if( (target_pkt.word_en&BIT1)^(match_word_en&BIT1) ) { tmp_word_en &= (~BIT1); } if( (target_pkt.word_en&BIT2)^(match_word_en&BIT2) ) { tmp_word_en &= (~BIT2); } if( (target_pkt.word_en&BIT3)^(match_word_en&BIT3) ) { tmp_word_en &=(~BIT3); } //************ so-2-2-A-2 ******************* if((tmp_word_en&0x0F)!=0x0F){ //reorganize other pg packet //efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr efuse_addr = efuse_GetCurrentSize(dev); //=========================== target_pkt.offset = offset; target_pkt.word_en= tmp_word_en; //=========================== }else{ bContinual = FALSE; } #if (EFUSE_ERROE_HANDLE == 1) WriteState=PG_STATE_HEADER; repeat_times++; if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ bContinual = FALSE; bResult = FALSE; } #endif } else{//************ so-2-2-B ******************* //reorganize other pg packet efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr //=========================== target_pkt.offset = offset; target_pkt.word_en= target_pkt.word_en; //=========================== #if (EFUSE_ERROE_HANDLE == 1) WriteState=PG_STATE_HEADER; #endif } } } printk("EFUSE PG_STATE_HEADER-1\n"); } else //************ s1: header == oxff ******************* { pg_header = ((target_pkt.offset << 4)&0xf0) |target_pkt.word_en; efuse_OneByteWrite(dev,efuse_addr, pg_header); efuse_OneByteRead(dev,efuse_addr, &tmp_header); if(tmp_header == pg_header) { //************ s1-1******************* WriteState = PG_STATE_DATA; } #if (EFUSE_ERROE_HANDLE == 1) else if(tmp_header == 0xFF){//************ s1-3: if Write or read func doesn't work ******************* //efuse_addr doesn't change WriteState = PG_STATE_HEADER; repeat_times++; if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ bContinual = FALSE; bResult = FALSE; } } #endif else {//************ s1-2 : fixed the header procedure ******************* tmp_pkt.offset = (tmp_header>>4) & 0x0F; tmp_pkt.word_en= tmp_header & 0x0F; tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); //************ s1-2-A :cover the exist data ******************* memset(originaldata,0xff,sizeof(u8)*8); //PlatformFillMemory((PVOID)originaldata, sizeof(u8)*8, 0xff); if(efuse_PgPacketRead( dev, tmp_pkt.offset,originaldata)) { //check if data exist //efuse_reg_ctrl(pAdapter,TRUE);//power on badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1,tmp_pkt.word_en,originaldata); //############################ if(0x0F != (badworden&0x0F)) { u8 reorg_offset = tmp_pkt.offset; u8 reorg_worden=badworden; efuse_PgPacketWrite(dev,reorg_offset,reorg_worden,originaldata); efuse_addr = efuse_GetCurrentSize(dev); } //############################ else{ efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet } } //************ s1-2-B: wrong address******************* else { efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet } #if (EFUSE_ERROE_HANDLE == 1) WriteState=PG_STATE_HEADER; repeat_times++; if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ bContinual = FALSE; bResult = FALSE; } #endif printk("EFUSE PG_STATE_HEADER-2\n"); } } } //write data state else if(WriteState==PG_STATE_DATA) { //************ s1-1 ******************* printk("EFUSE PG_STATE_DATA\n"); badworden = 0x0f; badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1,target_pkt.word_en,target_pkt.data); if((badworden&0x0F)==0x0F) { //************ s1-1-A ******************* bContinual = FALSE; } else {//reorganize other pg packet //************ s1-1-B ******************* efuse_addr = efuse_addr + (2*target_word_cnts) +1;//next pg packet addr //=========================== target_pkt.offset = offset; target_pkt.word_en= badworden; target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en); //=========================== #if (EFUSE_ERROE_HANDLE == 1) WriteState=PG_STATE_HEADER; repeat_times++; if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ bContinual = FALSE; bResult = FALSE; } #endif printk("EFUSE PG_STATE_HEADER-3\n"); } } } //efuse_reg_ctrl(pAdapter,FALSE);//power off return TRUE; } // efuse_PgPacketWrite /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ static void efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata) { //u8 tmpindex = 0; //DbgPrint("efuse_WordEnableDataRead word_en = %x\n", word_en); //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("sourdata\n"), sourdata, 8); //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("targetdata\n"), targetdata, 8); if (!(word_en&BIT0)) { targetdata[0] = sourdata[0];//sourdata[tmpindex++]; targetdata[1] = sourdata[1];//sourdata[tmpindex++]; } if (!(word_en&BIT1)) { targetdata[2] = sourdata[2];//sourdata[tmpindex++]; targetdata[3] = sourdata[3];//sourdata[tmpindex++]; } if (!(word_en&BIT2)) { targetdata[4] = sourdata[4];//sourdata[tmpindex++]; targetdata[5] = sourdata[5];//sourdata[tmpindex++]; } if (!(word_en&BIT3)) { targetdata[6] = sourdata[6];//sourdata[tmpindex++]; targetdata[7] = sourdata[7];//sourdata[tmpindex++]; } } // efuse_WordEnableDataRead /*----------------------------------------------------------------------------- * Function: efuse_WordEnableDataWrite * * Overview: Write necessary word unit into current efuse section! * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/16/2008 MHC Reorganize Efuse operate flow!!. * *---------------------------------------------------------------------------*/ static u8 efuse_WordEnableDataWrite( struct net_device* dev, u16 efuse_addr, u8 word_en, u8 *data) { u16 tmpaddr = 0; u16 start_addr = efuse_addr; u8 badworden = 0x0F; //u8 NextState; u8 tmpdata[8]; memset(tmpdata,0xff,PGPKT_DATA_SIZE); //PlatformFillMemory((PVOID)tmpdata, PGPKT_DATA_SIZE, 0xff); //RT_TRACE(COMP_EFUSE, "word_en = %x efuse_addr=%x\n", word_en, efuse_addr); //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("U-EFUSE\n"), data, 8); if(!(word_en&BIT0)) { tmpaddr = start_addr; efuse_OneByteWrite(dev,start_addr++, data[0]); efuse_OneByteWrite(dev,start_addr++, data[1]); efuse_OneByteRead(dev,tmpaddr, &tmpdata[0]); efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[1]); if((data[0]!=tmpdata[0])||(data[1]!=tmpdata[1])){ badworden &= (~BIT0); } } if(!(word_en&BIT1)) { tmpaddr = start_addr; efuse_OneByteWrite(dev,start_addr++, data[2]); efuse_OneByteWrite(dev,start_addr++, data[3]); efuse_OneByteRead(dev,tmpaddr , &tmpdata[2]); efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[3]); if((data[2]!=tmpdata[2])||(data[3]!=tmpdata[3])){ badworden &=( ~BIT1); } } if(!(word_en&BIT2)) { tmpaddr = start_addr; efuse_OneByteWrite(dev,start_addr++, data[4]); efuse_OneByteWrite(dev,start_addr++, data[5]); efuse_OneByteRead(dev,tmpaddr, &tmpdata[4]); efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[5]); if((data[4]!=tmpdata[4])||(data[5]!=tmpdata[5])){ badworden &=( ~BIT2); } } if(!(word_en&BIT3)) { tmpaddr = start_addr; efuse_OneByteWrite(dev,start_addr++, data[6]); efuse_OneByteWrite(dev,start_addr++, data[7]); efuse_OneByteRead(dev,tmpaddr, &tmpdata[6]); efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[7]); if((data[6]!=tmpdata[6])||(data[7]!=tmpdata[7])){ badworden &=( ~BIT3); } } return badworden; } // efuse_WordEnableDataWrite /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ static void efuse_PowerSwitch(struct net_device* dev, u8 PwrState) { u8 tempval; if (PwrState == TRUE) { // Enable LDO 2.5V for write action tempval = read_nic_byte(dev, EFUSE_TEST+3); write_nic_byte(dev, EFUSE_TEST+3, (tempval | 0x80)); // Change Efuse Clock for write action to 40MHZ write_nic_byte(dev, EFUSE_CLK, 0x03); } else { // Enable LDO 2.5V for write action tempval = read_nic_byte(dev, EFUSE_TEST+3); write_nic_byte(dev, EFUSE_TEST+3, (tempval & 0x7F)); // Change Efuse Clock for write action to 500K write_nic_byte(dev, EFUSE_CLK, 0x02); } } /* efuse_PowerSwitch */ /*----------------------------------------------------------------------------- * 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. * *---------------------------------------------------------------------------*/ static u16 efuse_GetCurrentSize(struct net_device* dev) { bool bContinual = TRUE; u16 efuse_addr = 0; u8 hoffset=0,hworden=0; u8 efuse_data,word_cnts=0; //efuse_reg_ctrl(pAdapter,TRUE);//power on while ( bContinual && efuse_OneByteRead(dev, efuse_addr ,&efuse_data) && (efuse_addr < EFUSE_MAX_SIZE) ) { if(efuse_data!=0xFF) { hoffset = (efuse_data>>4) & 0x0F; hworden = efuse_data & 0x0F; word_cnts = efuse_CalculateWordCnts(hworden); //read next header efuse_addr = efuse_addr + (word_cnts*2)+1; } else { bContinual = FALSE ; } } //efuse_reg_ctrl(pAdapter,FALSE);//power off return efuse_addr; } // efuse_GetCurrentSize} /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ static u8 efuse_CalculateWordCnts(u8 word_en) { u8 word_cnts = 0; if(!(word_en & BIT0)) word_cnts++; // 0 : write enable if(!(word_en & BIT1)) word_cnts++; if(!(word_en & BIT2)) word_cnts++; if(!(word_en & BIT3)) word_cnts++; return word_cnts; } // efuse_CalculateWordCnts /*----------------------------------------------------------------------------- * Function: EFUSE_ProgramMap * * Overview: Read EFUSE map file and execute PG. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/10/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ #ifdef TO_DO_LIST extern bool // 0=Shadow 1=Real Efuse EFUSE_ProgramMap(struct net_device* dev, char* pFileName,u8 TableType) { struct r8192_priv *priv = ieee80211_priv(dev); s4Byte nLinesRead, ithLine; RT_STATUS rtStatus = RT_STATUS_SUCCESS; char* szLine; u32 u4bRegValue, u4RegMask; u32 u4bMove; u16 index = 0; u16 i; u8 eeprom[HWSET_MAX_SIZE_92S]; rtStatus = PlatformReadFile( dev, pFileName, (u8*)(priv->BufOfLines), MAX_LINES_HWCONFIG_TXT, MAX_BYTES_LINE_HWCONFIG_TXT, &nLinesRead ); if(rtStatus == RT_STATUS_SUCCESS) { memcp(pHalData->BufOfLines3, pHalData->BufOfLines, nLinesRead*MAX_BYTES_LINE_HWCONFIG_TXT); pHalData->nLinesRead3 = nLinesRead; } if(rtStatus == RT_STATUS_SUCCESS) { printk("szEepromFile(): read %s ok\n", pFileName); for(ithLine = 0; ithLine < nLinesRead; ithLine++) { szLine = pHalData->BufOfLines[ithLine]; printk("Line-%d String =%s\n", ithLine, szLine); if(!IsCommentString(szLine)) { // EEPROM map one line has 8 words content. for (i = 0; i < 8; i++) { u32 j; //GetHexValueFromString(szLine, &u4bRegValue, &u4bMove); efuse_ParsingMap(szLine, &u4bRegValue, &u4bMove); // Get next hex value as EEPROM value. szLine += u4bMove; //WriteEEprom(dev, (u16)(ithLine*8+i), (u16)u4bRegValue); eeprom[index++] = (u8)(u4bRegValue&0xff); eeprom[index++] = (u8)((u4bRegValue>>8)&0xff); printk("Addr-%d = %x\n", (ithLine*8+i), u4bRegValue); } } } } else { printk("szEepromFile(): Fail read%s\n", pFileName); return RT_STATUS_FAILURE; } //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("EFUSE "), eeprom, HWSET_MAX_SIZE_92S); // Use map file to update real Efuse or shadow modify table. if (TableType == 1) { efuse_WriteAllMap(dev, eeprom, HWSET_MAX_SIZE_92S); } else { // Modify shadow table. for (i = 0; i < HWSET_MAX_SIZE_92S; i++) EFUSE_ShadowWrite(dev, 1, i, (u32)eeprom[i]); } return rtStatus; } /* EFUSE_ProgramMap */ #endif // // Description: // Return TRUE if chTmp is represent for hex digit and // FALSE otherwise. // // bool IsHexDigit( char chTmp) { if( (chTmp >= '0' && chTmp <= '9') || (chTmp >= 'a' && chTmp <= 'f') || (chTmp >= 'A' && chTmp <= 'F') ) { return TRUE; } else { return FALSE; } } // // Description: // Translate a character to hex digit. // u32 MapCharToHexDigit(char chTmp) { if(chTmp >= '0' && chTmp <= '9') return (chTmp - '0'); else if(chTmp >= 'a' && chTmp <= 'f') return (10 + (chTmp - 'a')); else if(chTmp >= 'A' && chTmp <= 'F') return (10 + (chTmp - 'A')); else return 0; } /*----------------------------------------------------------------------------- * Function: efuse_ParsingMap * * Overview: * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/08/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ #ifdef TO_DO_LIST static bool efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove) { char* szScan = szStr; // Check input parameter. if(szStr == NULL || pu4bVal == NULL || pu4bMove == NULL) { //RT_TRACE(COMP_EFUSE, //"eeprom_ParsingMap(): Invalid IN args! szStr: %p, pu4bVal: %p, pu4bMove: %p\n", //szStr, pu4bVal, pu4bMove); return FALSE; } // Initialize output. *pu4bMove = 0; *pu4bVal = 0; // Skip leading space. while( *szScan != '\0' && (*szScan == ' ' || *szScan == '\t') ) { szScan++; (*pu4bMove)++; } // Check if szScan is now pointer to a character for hex digit, // if not, it means this is not a valid hex number. if(!IsHexDigit(*szScan)) { return FALSE; } // Parse each digit. do { (*pu4bVal) <<= 4; *pu4bVal += MapCharToHexDigit(*szScan); szScan++; (*pu4bMove)++; } while(IsHexDigit(*szScan)); return TRUE; } /* efuse_ParsingMap */ #endif // // Useless Section Code Now!!!!!! // // Porting from 8712 SDIO int efuse_one_byte_rw(struct net_device* dev, u8 bRead, u16 addr, u8 *data) { u32 bResult; //u8 efuse_ctlreg,tmpidx = 0; u8 tmpidx = 0; u8 tmpv8=0; // -----------------e-fuse reg ctrl --------------------------------- write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff)); //address tmpv8 = ((u8)((addr>>8) &0x03) ) | (read_nic_byte(dev, EFUSE_CTRL+2)&0xFC ); write_nic_byte(dev, EFUSE_CTRL+2, tmpv8); if(TRUE==bRead){ write_nic_byte(dev, EFUSE_CTRL+3, 0x72);//read cmd while(!(0x80 & read_nic_byte(dev, EFUSE_CTRL+3)) && (tmpidx<100) ){ tmpidx++; } if(tmpidx<100){ *data=read_nic_byte(dev, EFUSE_CTRL); bResult = TRUE; } else { *data = 0; bResult = FALSE; } } else{ //return 0; write_nic_byte(dev, EFUSE_CTRL, *data);//data write_nic_byte(dev, EFUSE_CTRL+3, 0xF2);//write cmd while((0x80 & read_nic_byte(dev, EFUSE_CTRL+3)) && (tmpidx<100) ){ tmpidx++; } if(tmpidx<100) { *data=read_nic_byte(dev, EFUSE_CTRL); bResult = TRUE; } else { *data = 0; bResult = FALSE; } } return bResult; } //------------------------------------------------------------------------------ void efuse_access(struct net_device* dev, u8 bRead,u16 start_addr, u8 cnts, u8 *data) { u8 efuse_clk_ori,efuse_clk_new;//,tmp8; u32 i = 0; if(start_addr>0x200) return; //RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_, // ("\n ===> efuse_access [start_addr=0x%x cnts:%d dataarray:0x%08x Query Efuse].\n",start_addr,cnts,data)); // -----------------SYS_FUNC_EN Digital Core Vdd enable --------------------------------- efuse_clk_ori = read_nic_byte(dev,SYS_FUNC_EN+1); efuse_clk_new = efuse_clk_ori|0x20; if(efuse_clk_new!= efuse_clk_ori){ //RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n")); write_nic_byte(dev, SYS_FUNC_EN+1, efuse_clk_new); } #ifdef _POWERON_DELAY_ mdelay(10); #endif // -----------------e-fuse pwr & clk reg ctrl --------------------------------- write_nic_byte(dev, EFUSE_TEST+3, (read_nic_byte(dev, EFUSE_TEST+3)|0x80)); write_nic_byte(dev, EFUSE_CLK_CTRL, (read_nic_byte(dev, EFUSE_CLK_CTRL)|0x03)); #ifdef _PRE_EXECUTE_READ_CMD_ { unsigned char tmpdata; efuse_OneByteRead(dev, 0,&tmpdata); } #endif //-----------------e-fuse one byte read / write ------------------------------ for(i=0;iefuse_access addr:0x%02x value:0x%02x\n",data+i,*(data+i))); } // -----------------e-fuse pwr & clk reg ctrl --------------------------------- write_nic_byte(dev, EFUSE_TEST+3, read_nic_byte(dev, EFUSE_TEST+3)&0x7f); write_nic_byte(dev, EFUSE_CLK_CTRL, read_nic_byte(dev, EFUSE_CLK_CTRL)&0xfd); // -----------------SYS_FUNC_EN Digital Core Vdd disable --------------------------------- if(efuse_clk_new != efuse_clk_ori) write_nic_byte(dev, 0x10250003, efuse_clk_ori); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ #ifdef TO_DO_LIST static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn) { if(TRUE==bPowerOn){ // -----------------SYS_FUNC_EN Digital Core Vdd enable --------------------------------- write_nic_byte(dev, SYS_FUNC_EN+1, read_nic_byte(dev,SYS_FUNC_EN+1)|0x20); #ifdef _POWERON_DELAY_ mdelay(10); #endif // -----------------e-fuse pwr & clk reg ctrl --------------------------------- write_nic_byte(dev, EFUSE_TEST+4, (read_nic_byte(dev, EFUSE_TEST+4)|0x80)); write_nic_byte(dev, EFUSE_CLK_CTRL, (read_nic_byte(dev, EFUSE_CLK_CTRL)|0x03)); #ifdef _PRE_EXECUTE_READ_CMD_ { unsigned char tmpdata; efuse_OneByteRead(dev, 0,&tmpdata); } #endif } else{ // -----------------e-fuse pwr & clk reg ctrl --------------------------------- write_nic_byte(dev, EFUSE_TEST+4, read_nic_byte(dev, EFUSE_TEST+4)&0x7f); write_nic_byte(dev, EFUSE_CLK_CTRL, read_nic_byte(dev, EFUSE_CLK_CTRL)&0xfd); // -----------------SYS_FUNC_EN Digital Core Vdd disable --------------------------------- //write_nic_byte(pAdapter, SYS_FUNC_EN+1, read_nic_byte(pAdapter,SYS_FUNC_EN+1)&0xDF); } } #endif //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void efuse_read_data(struct net_device* dev,u8 efuse_read_item,u8 *data,u32 data_size) { u8 offset, word_start,byte_start,byte_cnts; u8 efusedata[EFUSE_MAC_LEN]; u8 *tmpdata = NULL; u8 pg_pkt_cnts ; u8 tmpidx; u8 pg_data[8]; //u8 temp_value[8] = {0xff}; if(efuse_read_item> (sizeof(RTL8712_SDIO_EFUSE_TABLE)/sizeof(EFUSE_MAP))){ //error msg return ; } offset = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].offset ; word_start = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].word_start; byte_start = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].byte_start; byte_cnts = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].byte_cnts; if(data_size!=byte_cnts){ //error msg return; } pg_pkt_cnts = (byte_cnts /PGPKT_DATA_SIZE) +1; if(pg_pkt_cnts > 1){ //tmpdata = _malloc(pg_pkt_cnts*PGPKT_DATA_SIZE); tmpdata = efusedata; if(tmpdata!=NULL) { memset(tmpdata,0xff,pg_pkt_cnts*PGPKT_DATA_SIZE); //PlatformFillMemory((PVOID)pg_data, pg_pkt_cnts*PGPKT_DATA_SIZE, 0xff); for(tmpidx=0;tmpidx (sizeof(RTL8712_SDIO_EFUSE_TABLE)/sizeof(EFUSE_MAP))){ //error msg return ; } offset = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].offset ; word_start = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].word_start; byte_start = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].byte_start; byte_cnts = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].byte_cnts; if(data_size > byte_cnts){ //error msg return; } pg_pkt_cnts = (byte_cnts /PGPKT_DATA_SIZE) +1; word_cnts = byte_cnts /2 ; if(byte_cnts %2){ word_cnts+=1; } if((byte_start==1)||((byte_cnts%2)==1)){//situation A if((efuse_write_item==EFUSE_F0CIS)||(efuse_write_item==EFUSE_F1CIS)){ memset(pg_data,0xff,PGPKT_DATA_SIZE); //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff); efuse_PgPacketRead(dev,offset,pg_data); if(efuse_write_item==EFUSE_F0CIS){ word_en = 0x07; memcpy(pg_data+word_start*2+byte_start,data,sizeof(u8)*2); //PlatformMoveMemory((PVOID)(pg_data+word_start*2+byte_start), (PVOID)data, sizeof(u8)*2); efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2)); word_en = 0x00; efuse_PgPacketWrite(dev,(offset+1),word_en,data+2); word_en = 0x00; efuse_PgPacketRead(dev,offset+2,pg_data); memcpy(pg_data,data+2+8,sizeof(u8)*7); //PlatformMoveMemory((PVOID)(pg_data), (PVOID)(data+2+8), sizeof(u8)*7); efuse_PgPacketWrite(dev,(offset+2),word_en,pg_data); } else if(efuse_write_item==EFUSE_F1CIS){ word_en = 0x07; efuse_PgPacketRead(dev,offset,pg_data); pg_data[7] = data[0]; efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2)); word_en = 0x00; for(tmpidx = 0 ;tmpidx<(word_cnts/4);tmpidx++){ efuse_PgPacketWrite(dev,(offset+1+tmpidx),word_en,data+1+(tmpidx*PGPKT_DATA_SIZE)); } } } else{ memset(pg_data,0xff,PGPKT_DATA_SIZE); //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff); if((efuse_write_item==EFUSE_SDIO_SETTING)||(efuse_write_item==EFUSE_CCCR)){ word_en = 0x0e ; tmpbytes = 2; } else if(efuse_write_item == EFUSE_SDIO_MODE){ word_en = 0x0d ; tmpbytes = 2; } else if(efuse_write_item == EFUSE_OCR){ word_en = 0x09 ; tmpbytes = 4; } else if((efuse_write_item == EFUSE_EEPROM_VER)||(efuse_write_item==EFUSE_CHAN_PLAN)){ word_en = 0x07 ; tmpbytes = 2; } if(bWordUnit==TRUE){ memcpy(pg_data+word_start*2 ,data,sizeof(u8)*tmpbytes); //PlatformMoveMemory((PVOID)(pg_data+word_start*2), (PVOID)(data), sizeof(u8)*tmpbytes); } else{ efuse_PgPacketRead(dev,offset,pg_data); memcpy(pg_data+(2*word_start)+byte_start,data,sizeof(u8)*byte_cnts); //PlatformMoveMemory((PVOID)(pg_data+(2*word_start)+byte_start), (PVOID)(data), sizeof(u8)*byte_cnts); } efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2)); } } //======================================================================== else if(pg_pkt_cnts>1){//situation B if(word_start==0){ word_en = 0x00; for(tmpidx = 0 ;tmpidx<(word_cnts/4);tmpidx++) { efuse_PgPacketWrite(dev,(offset+tmpidx),word_en,data+(tmpidx*PGPKT_DATA_SIZE)); } word_en = 0x0f; for(tmpidx= 0; tmpidx<(word_cnts%4) ; tmpidx++) { tmpbitmask =tmpidx; word_en &= (~(EFUSE_BIT(tmpbitmask))); //BIT0 } efuse_PgPacketWrite(dev,offset+(word_cnts/4),word_en,data+((word_cnts/4)*PGPKT_DATA_SIZE)); }else { } } //======================================================================== else{//situation C word_en = 0x0f; for(tmpidx= 0; tmpidx