/* ************************************************************************* * Ralink Tech Inc. * 5F., No.36, Taiyuan St., Jhubei City, * Hsinchu County 302, * Taiwan, R.O.C. * * (c) Copyright 2002-2007, Ralink Technology, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * 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. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * ************************************************************************* Module Name: eeprom.c Abstract: Revision History: Who When What -------- ---------- ---------------------------------------------- Name Date Modification logs */ #include "../rt_config.h" // IRQL = PASSIVE_LEVEL VOID RaiseClock( IN PRTMP_ADAPTER pAd, IN UINT32 *x) { *x = *x | EESK; RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition } // IRQL = PASSIVE_LEVEL VOID LowerClock( IN PRTMP_ADAPTER pAd, IN UINT32 *x) { *x = *x & ~EESK; RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); RTMPusecDelay(1); } // IRQL = PASSIVE_LEVEL USHORT ShiftInBits( IN PRTMP_ADAPTER pAd) { UINT32 x,i; USHORT data=0; RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~( EEDO | EEDI); for(i=0; i<16; i++) { data = data << 1; RaiseClock(pAd, &x); RTMP_IO_READ32(pAd, E2PROM_CSR, &x); LowerClock(pAd, &x); //prevent read failed x &= ~(EEDI); if(x & EEDO) data |= 1; } return data; } // IRQL = PASSIVE_LEVEL VOID ShiftOutBits( IN PRTMP_ADAPTER pAd, IN USHORT data, IN USHORT count) { UINT32 x,mask; mask = 0x01 << (count - 1); RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~(EEDO | EEDI); do { x &= ~EEDI; if(data & mask) x |= EEDI; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); RaiseClock(pAd, &x); LowerClock(pAd, &x); mask = mask >> 1; } while(mask); x &= ~EEDI; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); } // IRQL = PASSIVE_LEVEL VOID EEpromCleanup( IN PRTMP_ADAPTER pAd) { UINT32 x; RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~(EECS | EEDI); RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); RaiseClock(pAd, &x); LowerClock(pAd, &x); } VOID EWEN( IN PRTMP_ADAPTER pAd) { UINT32 x; // reset bits and set EECS RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~(EEDI | EEDO | EESK); x |= EECS; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); // kick a pulse RaiseClock(pAd, &x); LowerClock(pAd, &x); // output the read_opcode and six pulse in that order ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); ShiftOutBits(pAd, 0, 6); EEpromCleanup(pAd); } VOID EWDS( IN PRTMP_ADAPTER pAd) { UINT32 x; // reset bits and set EECS RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~(EEDI | EEDO | EESK); x |= EECS; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); // kick a pulse RaiseClock(pAd, &x); LowerClock(pAd, &x); // output the read_opcode and six pulse in that order ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); ShiftOutBits(pAd, 0, 6); EEpromCleanup(pAd); } // IRQL = PASSIVE_LEVEL USHORT RTMP_EEPROM_READ16( IN PRTMP_ADAPTER pAd, IN USHORT Offset) { UINT32 x; USHORT data; if (pAd->NicConfig2.field.AntDiversity) { pAd->EepromAccess = TRUE; } //2008/09/11:KH add to support efuse<-- //2008/09/11:KH add to support efuse--> { Offset /= 2; // reset bits and set EECS RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~(EEDI | EEDO | EESK); x |= EECS; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); // patch can not access e-Fuse issue if (!IS_RT3090(pAd)) { // kick a pulse RaiseClock(pAd, &x); LowerClock(pAd, &x); } // output the read_opcode and register number in that order ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); // Now read the data (16 bits) in from the selected EEPROM word data = ShiftInBits(pAd); EEpromCleanup(pAd); // Antenna and EEPROM access are both using EESK pin, // Therefor we should avoid accessing EESK at the same time // Then restore antenna after EEPROM access if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) { pAd->EepromAccess = FALSE; AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); } } return data; } //ReadEEprom VOID RTMP_EEPROM_WRITE16( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Data) { UINT32 x; if (pAd->NicConfig2.field.AntDiversity) { pAd->EepromAccess = TRUE; } //2008/09/11:KH add to support efuse<-- //2008/09/11:KH add to support efuse--> { Offset /= 2; EWEN(pAd); // reset bits and set EECS RTMP_IO_READ32(pAd, E2PROM_CSR, &x); x &= ~(EEDI | EEDO | EESK); x |= EECS; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); // patch can not access e-Fuse issue if (!IS_RT3090(pAd)) { // kick a pulse RaiseClock(pAd, &x); LowerClock(pAd, &x); } // output the read_opcode ,register number and data in that order ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ShiftOutBits(pAd, Data, 16); // 16-bit access // read DO status RTMP_IO_READ32(pAd, E2PROM_CSR, &x); EEpromCleanup(pAd); RTMPusecDelay(10000); //delay for twp(MAX)=10ms EWDS(pAd); EEpromCleanup(pAd); // Antenna and EEPROM access are both using EESK pin, // Therefor we should avoid accessing EESK at the same time // Then restore antenna after EEPROM access if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) { pAd->EepromAccess = FALSE; AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); } } } //2008/09/11:KH add to support efuse<-- #ifdef RT30xx /* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ UCHAR eFuseReadRegisters( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Length, OUT USHORT* pData) { EFUSE_CTRL_STRUC eFuseCtrlStruc; int i; USHORT efuseDataOffset; UINT32 data; RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. //Use the eeprom logical address and covert to address to block number eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 0. eFuseCtrlStruc.field.EFSROM_MODE = 0; //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. eFuseCtrlStruc.field.EFSROM_KICK = 1; NdisMoveMemory(&data, &eFuseCtrlStruc, 4); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. i = 0; while(i < 100) { //rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4); RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) { break; } RTMPusecDelay(2); i++; } //if EFSROM_AOUT is not found in physical address, write 0xffff if (eFuseCtrlStruc.field.EFSROM_AOUT == 0x3f) { for(i=0; i> (8*(Offset & 0x3)); #endif NdisMoveMemory(pData, &data, Length); } return (UCHAR) eFuseCtrlStruc.field.EFSROM_AOUT; } /* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ VOID eFusePhysicalReadRegisters( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Length, OUT USHORT* pData) { EFUSE_CTRL_STRUC eFuseCtrlStruc; int i; USHORT efuseDataOffset; UINT32 data; RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. //Read in physical view eFuseCtrlStruc.field.EFSROM_MODE = 1; //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. eFuseCtrlStruc.field.EFSROM_KICK = 1; NdisMoveMemory(&data, &eFuseCtrlStruc, 4); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. i = 0; while(i < 100) { RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) break; RTMPusecDelay(2); i++; } //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) //Because the size of each EFUSE_DATA is 4 Bytes, the size of address of each is 2 bits. //The previous 2 bits is the EFUSE_DATA number, the last 2 bits is used to decide which bytes //Decide which EFUSE_DATA to read //590:F E D C //594:B A 9 8 //598:7 6 5 4 //59C:3 2 1 0 efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; RTMP_IO_READ32(pAd, efuseDataOffset, &data); #ifdef RT_BIG_ENDIAN data = data << (8*((Offset & 0x3)^0x2)); #else data = data >> (8*(Offset & 0x3)); #endif NdisMoveMemory(pData, &data, Length); } /* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ VOID eFuseReadPhysical( IN PRTMP_ADAPTER pAd, IN PUSHORT lpInBuffer, IN ULONG nInBufferSize, OUT PUSHORT lpOutBuffer, IN ULONG nOutBufferSize ) { USHORT* pInBuf = (USHORT*)lpInBuffer; USHORT* pOutBuf = (USHORT*)lpOutBuffer; USHORT Offset = pInBuf[0]; //addr USHORT Length = pInBuf[1]; //length int i; for(i=0; i> 2; data = pData[0] & 0xffff; //The offset should be 0x***10 or 0x***00 if((Offset % 4) != 0) { eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff) | (data << 16); } else { eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff0000) | data; } efuseDataOffset = EFUSE_DATA3; for(i=0; i< 4; i++) { RTMP_IO_WRITE32(pAd, efuseDataOffset, eFuseDataBuffer[i]); efuseDataOffset -= 4; } ///////////////////////////////////////////////////////////////// //Step1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; //Step2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. eFuseCtrlStruc.field.EFSROM_MODE = 3; //Step3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. eFuseCtrlStruc.field.EFSROM_KICK = 1; NdisMoveMemory(&data, &eFuseCtrlStruc, 4); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It¡¦s done. i = 0; while(i < 100) { RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) break; RTMPusecDelay(2); i++; } } /* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ NTSTATUS eFuseWriteRegisters( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Length, IN USHORT* pData) { USHORT i; USHORT eFuseData; USHORT LogicalAddress, BlkNum = 0xffff; UCHAR EFSROM_AOUT; USHORT addr,tmpaddr, InBuf[3], tmpOffset; USHORT buffer[8]; BOOLEAN bWriteSuccess = TRUE; DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters Offset=%x, pData=%x\n", Offset, *pData)); //Step 0. find the entry in the mapping table //The address of EEPROM is 2-bytes alignment. //The last bit is used for alignment, so it must be 0. tmpOffset = Offset & 0xfffe; EFSROM_AOUT = eFuseReadRegisters(pAd, tmpOffset, 2, &eFuseData); if( EFSROM_AOUT == 0x3f) { //find available logical address pointer //the logical address does not exist, find an empty one //from the first address of block 45=16*45=0x2d0 to the last address of block 47 //==>48*16-3(reserved)=2FC for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) { //Retrive the logical block nubmer form each logical address pointer //It will access two logical address pointer each time. eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if( (LogicalAddress & 0xff) == 0) {//Not used logical address pointer BlkNum = i-EFUSE_USAGE_MAP_START; break; } else if(( (LogicalAddress >> 8) & 0xff) == 0) {//Not used logical address pointer if (i != EFUSE_USAGE_MAP_END) { BlkNum = i-EFUSE_USAGE_MAP_START+1; } break; } } } else { BlkNum = EFSROM_AOUT; } DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); if(BlkNum == 0xffff) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); return FALSE; } //Step 1. Save data of this block which is pointed by the avaible logical address pointer // read and save the original block data for(i =0; i<8; i++) { addr = BlkNum * 0x10 ; InBuf[0] = addr+2*i; InBuf[1] = 2; InBuf[2] = 0x0; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); buffer[i] = InBuf[2]; } //Step 2. Update the data in buffer, and write the data to Efuse buffer[ (Offset >> 1) % 8] = pData[0]; do { //Step 3. Write the data to Efuse if(!bWriteSuccess) { for(i =0; i<8; i++) { addr = BlkNum * 0x10 ; InBuf[0] = addr+2*i; InBuf[1] = 2; InBuf[2] = buffer[i]; eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); } } else { addr = BlkNum * 0x10 ; InBuf[0] = addr+(Offset % 16); InBuf[1] = 2; InBuf[2] = pData[0]; eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); } //Step 4. Write mapping table addr = EFUSE_USAGE_MAP_START+BlkNum; tmpaddr = addr; if(addr % 2 != 0) addr = addr -1; InBuf[0] = addr; InBuf[1] = 2; //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry tmpOffset = Offset; tmpOffset >>= 4; tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; // write the logical address if(tmpaddr%2 != 0) InBuf[2] = tmpOffset<<8; else InBuf[2] = tmpOffset; eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); //Step 5. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted bWriteSuccess = TRUE; for(i =0; i<8; i++) { addr = BlkNum * 0x10 ; InBuf[0] = addr+2*i; InBuf[1] = 2; InBuf[2] = 0x0; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); if(buffer[i] != InBuf[2]) { bWriteSuccess = FALSE; break; } } //Step 6. invlidate mapping entry and find a free mapping entry if not succeed if (!bWriteSuccess) { DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess BlkNum = %d\n", BlkNum)); // the offset of current mapping entry addr = EFUSE_USAGE_MAP_START+BlkNum; //find a new mapping entry BlkNum = 0xffff; for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) { eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if( (LogicalAddress & 0xff) == 0) { BlkNum = i-EFUSE_USAGE_MAP_START; break; } else if(( (LogicalAddress >> 8) & 0xff) == 0) { if (i != EFUSE_USAGE_MAP_END) { BlkNum = i+1-EFUSE_USAGE_MAP_START; } break; } } DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess new BlkNum = %d\n", BlkNum)); if(BlkNum == 0xffff) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); return FALSE; } //invalidate the original mapping entry if new entry is not found tmpaddr = addr; if(addr % 2 != 0) addr = addr -1; InBuf[0] = addr; InBuf[1] = 2; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); // write the logical address if(tmpaddr%2 != 0) { // Invalidate the high byte for (i=8; i<15; i++) { if( ( (InBuf[2] >> i) & 0x01) == 0) { InBuf[2] |= (0x1 <> i) & 0x01) == 0) { InBuf[2] |= (0x1 <bUseEfuse) return FALSE; for (i = EFUSE_USAGE_MAP_START; i <= EFUSE_USAGE_MAP_END; i+=2) { eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if( (LogicalAddress & 0xff) == 0) { efusefreenum= (UCHAR) (EFUSE_USAGE_MAP_END-i+1); break; } else if(( (LogicalAddress >> 8) & 0xff) == 0) { efusefreenum = (UCHAR) (EFUSE_USAGE_MAP_END-i); break; } if(i == EFUSE_USAGE_MAP_END) efusefreenum = 0; } printk("efuseFreeNumber is %d\n",efusefreenum); return TRUE; } INT set_eFusedump_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg) { USHORT InBuf[3]; INT i=0; if(!pAd->bUseEfuse) return FALSE; for(i =0; i0) { NdisMoveMemory(src, arg, strlen(arg)); } else { NdisMoveMemory(src, "RT30xxEEPROM.bin", BinFileSize); } DBGPRINT(RT_DEBUG_TRACE, ("FileName=%s\n",src)); buffer = kmalloc(MAX_EEPROM_BIN_FILE_SIZE, MEM_ALLOC_FLAG); if(buffer == NULL) { kfree(src); return FALSE; } PDATA=kmalloc(sizeof(USHORT)*8,MEM_ALLOC_FLAG); if(PDATA==NULL) { kfree(src); kfree(buffer); return FALSE; } /* Don't change to uid 0, let the file be opened as the "normal" user */ #if 0 orgfsuid = current->fsuid; orgfsgid = current->fsgid; current->fsuid=current->fsgid = 0; #endif orgfs = get_fs(); set_fs(KERNEL_DS); if (src && *src) { srcf = filp_open(src, O_RDONLY, 0); if (IS_ERR(srcf)) { DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); return FALSE; } else { // The object must have a read method if (srcf->f_op && srcf->f_op->read) { memset(buffer, 0x00, MAX_EEPROM_BIN_FILE_SIZE); while(srcf->f_op->read(srcf, &buffer[i], 1, &srcf->f_pos)==1) { DBGPRINT(RT_DEBUG_TRACE, ("%02X ",buffer[i])); if((i+1)%8==0) DBGPRINT(RT_DEBUG_TRACE, ("\n")); i++; if(i>=MAX_EEPROM_BIN_FILE_SIZE) { DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld reading %s, The file is too large[1024]\n", -PTR_ERR(srcf),src)); kfree(PDATA); kfree(buffer); kfree(src); return FALSE; } } } else { DBGPRINT(RT_DEBUG_ERROR, ("--> Error!! System doest not support read function\n")); kfree(PDATA); kfree(buffer); kfree(src); return FALSE; } } } else { DBGPRINT(RT_DEBUG_ERROR, ("--> Error src or srcf is null\n")); kfree(PDATA); kfree(buffer); return FALSE; } retval=filp_close(srcf,NULL); if (retval) { DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); } set_fs(orgfs); #if 0 current->fsuid = orgfsuid; current->fsgid = orgfsgid; #endif for(j=0;j48*16-3(reserved)=2FC bAllocateNewBlk=TRUE; for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) { //Retrive the logical block nubmer form each logical address pointer //It will access two logical address pointer each time. eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if( (LogicalAddress & 0xff) == 0) {//Not used logical address pointer BlkNum = i-EFUSE_USAGE_MAP_START; break; } else if(( (LogicalAddress >> 8) & 0xff) == 0) {//Not used logical address pointer if (i != EFUSE_USAGE_MAP_END) { BlkNum = i-EFUSE_USAGE_MAP_START+1; } break; } } } else { bAllocateNewBlk=FALSE; BlkNum = EFSROM_AOUT; } DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); if(BlkNum == 0xffff) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); return FALSE; } //Step 1.1.0 //If the block is not existing in mapping table, create one //and write down the 16-bytes data to the new block if(bAllocateNewBlk) { DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk\n")); efuseDataOffset = EFUSE_DATA3; for(i=0; i< 4; i++) { DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk, Data%d=%04x%04x\n",3-i,pData[2*i+1],pData[2*i])); tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; RTMP_IO_WRITE32(pAd, efuseDataOffset,tempbuffer); efuseDataOffset -= 4; } ///////////////////////////////////////////////////////////////// //Step1.1.1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. eFuseCtrlStruc.field.EFSROM_AIN = BlkNum* 0x10 ; //Step1.1.2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. eFuseCtrlStruc.field.EFSROM_MODE = 3; //Step1.1.3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. eFuseCtrlStruc.field.EFSROM_KICK = 1; NdisMoveMemory(&data, &eFuseCtrlStruc, 4); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step1.1.4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It¡¦s done. i = 0; while(i < 100) { RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) break; RTMPusecDelay(2); i++; } } else { //Step1.2. //If the same logical number is existing, check if the writting data and the data //saving in this block are the same. ///////////////////////////////////////////////////////////////// //read current values of 16-byte block RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); //Step1.2.0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; //Step1.2.1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. eFuseCtrlStruc.field.EFSROM_MODE = 0; //Step1.2.2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. eFuseCtrlStruc.field.EFSROM_KICK = 1; NdisMoveMemory(&data, &eFuseCtrlStruc, 4); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step1.2.3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. i = 0; while(i < 100) { RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) break; RTMPusecDelay(2); i++; } //Step1.2.4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) efuseDataOffset = EFUSE_DATA3; for(i=0; i< 4; i++) { RTMP_IO_READ32(pAd, efuseDataOffset, (PUINT32) &buffer[i]); efuseDataOffset -= 4; } //Step1.2.5. Check if the data of efuse and the writing data are the same. for(i =0; i<4; i++) { tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; DBGPRINT(RT_DEBUG_TRACE, ("buffer[%d]=%x,pData[%d]=%x,pData[%d]=%x,tempbuffer=%x\n",i,buffer[i],2*i,pData[2*i],2*i+1,pData[2*i+1],tempbuffer)); if(((buffer[i]&0xffff0000)==(pData[2*i+1]<<16))&&((buffer[i]&0xffff)==pData[2*i])) bNotWrite&=TRUE; else { bNotWrite&=FALSE; break; } } if(!bNotWrite) { printk("The data is not the same\n"); for(i =0; i<8; i++) { addr = BlkNum * 0x10 ; InBuf[0] = addr+2*i; InBuf[1] = 2; InBuf[2] = pData[i]; eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); } } else return TRUE; } //Step 2. Write mapping table addr = EFUSE_USAGE_MAP_START+BlkNum; tmpaddr = addr; if(addr % 2 != 0) addr = addr -1; InBuf[0] = addr; InBuf[1] = 2; //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry tmpOffset = Offset; tmpOffset >>= 4; tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; // write the logical address if(tmpaddr%2 != 0) InBuf[2] = tmpOffset<<8; else InBuf[2] = tmpOffset; eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); //Step 3. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted bWriteSuccess = TRUE; for(i =0; i<8; i++) { addr = BlkNum * 0x10 ; InBuf[0] = addr+2*i; InBuf[1] = 2; InBuf[2] = 0x0; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); DBGPRINT(RT_DEBUG_TRACE, ("addr=%x, buffer[i]=%x,InBuf[2]=%x\n",InBuf[0],pData[i],InBuf[2])); if(pData[i] != InBuf[2]) { bWriteSuccess = FALSE; break; } } //Step 4. invlidate mapping entry and find a free mapping entry if not succeed if (!bWriteSuccess&&Loop<2) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess BlkNum = %d\n", BlkNum)); // the offset of current mapping entry addr = EFUSE_USAGE_MAP_START+BlkNum; //find a new mapping entry BlkNum = 0xffff; for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) { eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if( (LogicalAddress & 0xff) == 0) { BlkNum = i-EFUSE_USAGE_MAP_START; break; } else if(( (LogicalAddress >> 8) & 0xff) == 0) { if (i != EFUSE_USAGE_MAP_END) { BlkNum = i+1-EFUSE_USAGE_MAP_START; } break; } } DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess new BlkNum = %d\n", BlkNum)); if(BlkNum == 0xffff) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin: out of free E-fuse space!!!\n")); return FALSE; } //invalidate the original mapping entry if new entry is not found tmpaddr = addr; if(addr % 2 != 0) addr = addr -1; InBuf[0] = addr; InBuf[1] = 2; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); // write the logical address if(tmpaddr%2 != 0) { // Invalidate the high byte for (i=8; i<15; i++) { if( ( (InBuf[2] >> i) & 0x01) == 0) { InBuf[2] |= (0x1 <> i) & 0x01) == 0) { InBuf[2] |= (0x1 <