/* *************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * * (c) Copyright 2002-2004, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. *************************************************************************** Module Name: ee_efuse.c Revision History: Who When What -------- ---------- ---------------------------------------------- */ #ifdef RTMP_EFUSE_SUPPORT #include "rt_config.h" static VOID eFuseWritePhysical( IN PRTMP_ADAPTER pAd, PUSHORT lpInBuffer, ULONG nInBufferSize, PUCHAR lpOutBuffer, ULONG nOutBufferSize); static VOID EFUSE_IO_READ32(PRTMP_ADAPTER pAd, UINT32 reg, UINT32 *value) { #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { #ifdef RTMP_MAC_PCI UINT32 RestoreValue; RTMP_IO_READ32(pAd, MCU_PCIE_REMAP_2, &RestoreValue); RTMP_IO_WRITE32(pAd, MCU_PCIE_REMAP_2, MT_EEF_BASE - 0x70000); RTMP_IO_READ32(pAd, 0x80000 + (reg - MT_EEF_BASE) + 0x70000, value); RTMP_IO_WRITE32(pAd, MCU_PCIE_REMAP_2, RestoreValue); #endif #if defined(RTMP_MAC_USB) || defined(RTMP_MAC_SDIO) RTMP_MCU_IO_READ32(pAd, reg, value); #endif } else #endif /* MT_MAC */ RTMP_IO_READ32(pAd, reg, value); } static VOID EFUSE_IO_WRITE32(PRTMP_ADAPTER pAd, UINT32 reg, UINT32 value) { #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { #ifdef RTMP_MAC_PCI UINT32 RestoreValue; RTMP_IO_READ32(pAd, MCU_PCIE_REMAP_2, &RestoreValue); RTMP_IO_WRITE32(pAd, MCU_PCIE_REMAP_2, MT_EEF_BASE - 0x70000); RTMP_IO_WRITE32(pAd, 0x80000 + (reg - MT_EEF_BASE) + 0x70000, value); RTMP_IO_WRITE32(pAd, MCU_PCIE_REMAP_2, RestoreValue); #endif #if defined(RTMP_MAC_USB) || defined(RTMP_MAC_SDIO) RTMP_MCU_IO_WRITE32(pAd, reg, value); #endif } else #endif /* MT_MAC */ RTMP_IO_WRITE32(pAd, reg, value); } /* ======================================================================== Routine Description: Arguments: Return Value: Note: ======================================================================== */ UCHAR eFuseReadRegisters(PRTMP_ADAPTER pAd, UINT16 Offset, UINT16 Length, UINT16* pData) { EFUSE_CTRL_STRUC eFuseCtrlStruc; INT32 i; UINT32 efuseDataOffset; UINT32 data=0; UINT32 efuse_ctrl_reg = EFUSE_CTRL; int ret; RTMP_SEM_EVENT_WAIT(&(pAd->e2p_read_lock), ret); if(ret != 0) DBGPRINT(RT_DEBUG_ERROR, ("%s:(%d) RTMP_SEM_EVENT_WAIT failed!\n",__FUNCTION__,ret)); #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) efuse_ctrl_reg = EFUSE_CTRL_3290; #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) efuse_ctrl_reg = MT_EFUSE_CTRL; #endif /* MT_MAC */ EFUSE_IO_READ32(pAd, efuse_ctrl_reg, &eFuseCtrlStruc.word); /* 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); EFUSE_IO_WRITE32(pAd, efuse_ctrl_reg, data); /* Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again.*/ i = 0; while(i < 500) { if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) { RTMP_SEM_EVENT_UP(&(pAd->e2p_read_lock)); return 0x3f; } /*rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4);*/ EFUSE_IO_READ32(pAd, efuse_ctrl_reg, &eFuseCtrlStruc.word); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) { RtmpusecDelay(2); 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 < Length / 2; i++) { *(pData +2 * i) = 0xffff; } RTMP_SEM_EVENT_UP(&(pAd->e2p_read_lock)); return 0x3f; } else { #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { if (!eFuseCtrlStruc.field.EFSROM_DOUT_VLD) { for(i = 0; i < Length / 2; i++){ *(pData +2 * i) = 0xffff; } RTMP_SEM_EVENT_UP(&(pAd->e2p_read_lock)); return 0x3f; } } #endif /* MT_MAC */ /*Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x590-0x59C)*/ #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) efuseDataOffset = EFUSE_DATA0_3290 + (Offset & 0xC); else #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) efuseDataOffset = MT_EFUSE_RDATA0 + (Offset & 0xC); else #endif /* MT_MAC */ efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC); /*data hold 4 bytes data.*/ /*In EFUSE_IO_READ32 will automatically execute 32-bytes swapping*/ EFUSE_IO_READ32(pAd, efuseDataOffset, &data); /*Decide the upper 2 bytes or the bottom 2 bytes.*/ /* Little-endian S | S Big-endian*/ /* addr 3 2 1 0 | 0 1 2 3*/ /* Ori-V D C B A | A B C D*/ /*After swapping*/ /* D C B A | D C B A*/ /*Return 2-bytes*/ /*The return byte statrs from S. Therefore, the little-endian will return BA, the Big-endian will return DC.*/ /*For returning the bottom 2 bytes, the Big-endian should shift right 2-bytes.*/ #ifdef RT_BIG_ENDIAN data = data << (8*((Offset & 0x3)^0x2)); #else data = data >> (8*(Offset & 0x3)); #endif /* RT_BIG_ENDIAN */ NdisMoveMemory(pData, &data, Length); } RTMP_SEM_EVENT_UP(&(pAd->e2p_read_lock)); return eFuseCtrlStruc.field.EFSROM_AOUT; } VOID EfusePhysicalReadRegisters(PRTMP_ADAPTER pAd, UINT16 Offset, UINT16 Length, UINT16* pData) { EFUSE_CTRL_STRUC EfuseCtrlStruc; INT32 Index; UINT32 EfuseDataOffset; UINT32 Data; UINT32 EfuseCtrlReg = EFUSE_CTRL; #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) EfuseCtrlReg = EFUSE_CTRL_3290; #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) EfuseCtrlReg = MT_EFUSE_CTRL; #endif /* MT_MAC */ EFUSE_IO_READ32(pAd, EfuseCtrlReg, &EfuseCtrlStruc.word); /*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); EFUSE_IO_WRITE32(pAd, EfuseCtrlReg, Data); /*Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again.*/ Index = 0; while (Index < 500) { if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) return; EFUSE_IO_READ32(pAd, EfuseCtrlReg, &EfuseCtrlStruc.word); if(EfuseCtrlStruc.field.EFSROM_KICK == 0) { RtmpusecDelay(2); break; } RtmpusecDelay(2); Index++; } DBGPRINT(RT_DEBUG_INFO, ("EfuseCtrlStruc.field.EFSROM_AOUT = %x\n", EfuseCtrlStruc.field.EFSROM_AOUT)); DBGPRINT(RT_DEBUG_INFO, ("EfuseCtrlStruc.field.EFSROM_DOUT_VLD = %x\n", EfuseCtrlStruc.field.EFSROM_DOUT_VLD)); /*if EFSROM_AOUT is not found in physical address, write 0xffff*/ if (EfuseCtrlStruc.field.EFSROM_AOUT == 0x3f) { for(Index = 0; Index < Length / 2; Index++) { *(pData + 2 * Index) = 0xffff; } DBGPRINT(RT_DEBUG_ERROR, ("EfuseCtrlStruc.field.EFSROM_AOUT = %x\n", EfuseCtrlStruc.field.EFSROM_AOUT)); return; } else { if (pAd->chipCap.hif_type == HIF_MT) { if (!EfuseCtrlStruc.field.EFSROM_DOUT_VLD) { for(Index = 0; Index < Length / 2; Index++) { *(pData + 2 * Index) = 0xffff; } DBGPRINT(RT_DEBUG_OFF, ("EfuseCtrlStruc.field.EFSROM_DOUT_VLD = %x\n", EfuseCtrlStruc.field.EFSROM_DOUT_VLD)); return; } } } /*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*/ #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) EfuseDataOffset = EFUSE_DATA0_3290 + (Offset & 0xC) ; else #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) EfuseDataOffset = MT_EFUSE_RDATA0 + (Offset & 0xC); else #endif /* MT_MAC */ EfuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; EFUSE_IO_READ32(pAd, EfuseDataOffset , &Data); #ifdef RT_BIG_ENDIAN Data = Data << (8 *((Offset & 0x3)^0x2)); #else Data = Data >> (8 * (Offset & 0x3)); #endif /* RT_BIG_ENDIAN */ NdisMoveMemory(pData, &Data, Length); } /* ======================================================================== Routine Description: Arguments: Return Value: 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*/ INT32 i; for(i = 0; i < Length; i+=2) { EfusePhysicalReadRegisters(pAd, (UINT16)(Offset + i), 2, &pOutBuf[i/2]); } } /* ======================================================================== Routine Description: Arguments: Return Value: Note: ======================================================================== */ NTSTATUS eFuseRead( IN PRTMP_ADAPTER pAd, IN USHORT Offset, OUT PUSHORT pData, IN USHORT Length) { NTSTATUS Status = STATUS_SUCCESS; int i; for(i = 0; i < Length; i+=2) { eFuseReadRegisters(pAd, (UINT16)(Offset+i), 2, &pData[i/2]); } return Status; } /* ======================================================================== Routine Description: Arguments: Return Value: Note: ======================================================================== */ static VOID eFusePhysicalWriteRegisters( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Length, OUT USHORT* pData) { EFUSE_CTRL_STRUC eFuseCtrlStruc; int i; UINT32 efuseDataOffset; UINT32 efuse_rdata = EFUSE_DATA3, efuse_wdata = EFUSE_DATA3; UINT32 data, eFuseDataBuffer[4]; UINT32 efuse_ctrl_reg = EFUSE_CTRL; #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) { efuse_ctrl_reg = EFUSE_CTRL_3290; efuse_rdata = EFUSE_DATA0_3290; efuse_wdata = EFUSE_DATA0_3290; } #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { efuse_ctrl_reg = MT_EFUSE_CTRL; efuse_rdata = MT_EFUSE_RDATA0; efuse_wdata = MT_EFUSE_WDATA0; } #endif /* MT_MAC */ /*Step0. Write 16-byte of data to EFUSE_DATA0-3 (0x590-0x59C), where EFUSE_DATA0 is the LSB DW, EFUSE_DATA3 is the MSB DW.*/ /*read current values of 16-byte block */ EFUSE_IO_READ32(pAd, efuse_ctrl_reg, &eFuseCtrlStruc.word); /*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.*/ 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); EFUSE_IO_WRITE32(pAd, efuse_ctrl_reg, data); /*Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again.*/ i = 0; while(i < 500) { EFUSE_IO_READ32(pAd, efuse_ctrl_reg, &eFuseCtrlStruc.word); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) { RtmpusecDelay(2); break; } RtmpusecDelay(2); i++; } /*Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590)*/ efuseDataOffset = efuse_rdata; for (i = 0; i < 4; i++) { EFUSE_IO_READ32(pAd, efuseDataOffset, (PUINT32) &eFuseDataBuffer[i]); #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) efuseDataOffset += 4; else #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) efuseDataOffset += 4; else #endif /* MT_MAC */ efuseDataOffset -= 4; } /*Update the value, the offset is multiple of 2, length is 2*/ efuseDataOffset = (Offset & 0xc) >> 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_wdata; for(i = 0; i < 4; i++) { EFUSE_IO_WRITE32(pAd, efuseDataOffset, eFuseDataBuffer[i]); #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) efuseDataOffset += 4; else #endif /* defined(RT3290) || defined(RT65xx) || defined(MT7601) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) efuseDataOffset += 4; else #endif /* MT_MAC */ efuseDataOffset -= 4; } /*Step1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment.*/ // TODO: shiang, for below line, windows driver didn't have this read, why we have ?? EFUSE_IO_READ32(pAd, efuse_ctrl_reg, &eFuseCtrlStruc.word); 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); EFUSE_IO_WRITE32(pAd, efuse_ctrl_reg, data); /*Step4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It's done.*/ i = 0; while (i < 500) { EFUSE_IO_READ32(pAd, efuse_ctrl_reg, &eFuseCtrlStruc.word); if(eFuseCtrlStruc.field.EFSROM_KICK == 0) { RtmpusecDelay(2); break; } RtmpusecDelay(2); i++; } } /* ======================================================================== Routine Description: Arguments: Return Value: Note: ======================================================================== */ static NTSTATUS eFuseWriteRegisters( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Length, IN USHORT* pData) { USHORT i,Loop=0, StartBlock=0, EndBlock=0; 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)); /*set start block and end block number, start from tail of mapping table*/ if( (pAd->chipCap.EFUSE_USAGE_MAP_END % 2) != 0) { StartBlock = pAd->chipCap.EFUSE_USAGE_MAP_END-1; } else { StartBlock = pAd->chipCap.EFUSE_USAGE_MAP_END; } if( (pAd->chipCap.EFUSE_USAGE_MAP_START % 2) != 0) { EndBlock = pAd->chipCap.EFUSE_USAGE_MAP_START-1; } else { EndBlock = pAd->chipCap.EFUSE_USAGE_MAP_START; } /*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=StartBlock; i >= EndBlock; 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); /*To avoid the odd byte problem, ex. We read the 21|20 bytes and if 21 is the */ /* end byte. Then, the EFUSE_USAGE_MAP_END which is 21 is not equal to*/ /* i which is 20. Therefore, this 21th byte could be used.*/ /*Otherwise, if 20 is the stop byte, i which is 20 is equal EFUSE_USAGE_MAP_END.*/ /* It means the 21th byte could not be used.*/ if(( (LogicalAddress >> 8) & 0xff) == 0) {/*Not used logical address pointer*/ if (i != pAd->chipCap.EFUSE_USAGE_MAP_END) { BlkNum = i-pAd->chipCap.EFUSE_USAGE_MAP_START+1; break; } } if( (LogicalAddress & 0xff) == 0) {/*Not used logical address pointer*/ if (i != (pAd->chipCap.EFUSE_USAGE_MAP_START-1)) { BlkNum = i-pAd->chipCap.EFUSE_USAGE_MAP_START; 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 { Loop++; /*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 = pAd->chipCap.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)); #if 0 if(BlkNum >= (pAd->chipCap.EFUSE_USAGE_MAP_SIZE-1)) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); return FALSE; } #endif /* the offset of current mapping entry*/ addr = pAd->chipCap.EFUSE_USAGE_MAP_START+BlkNum; /*find a new mapping entry*/ BlkNum = 0xffff; for (i=StartBlock; i >= EndBlock; i-=2) { EfusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if(( (LogicalAddress >> 8) & 0xff) == 0) { if(i != pAd->chipCap.EFUSE_USAGE_MAP_END) { BlkNum = i+1-pAd->chipCap.EFUSE_USAGE_MAP_START; break; } } if( (LogicalAddress & 0xff) == 0) { if(i != (pAd->chipCap.EFUSE_USAGE_MAP_START-1)) { BlkNum = i-pAd->chipCap.EFUSE_USAGE_MAP_START; break; } } } DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess and allocate 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 <>8; pValueX=OddWriteByteBuf; } for(i=0; ibUseEfuse == FALSE) return FALSE; eFuseGetFreeBlockCount(pAd, &free_num); DBGPRINT(RT_DEBUG_OFF, ("efuseFreeNumber = %d\n", free_num)); return TRUE; } INT set_eFusedump_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { USHORT InBuf[3]; INT i = 0; if (pAd->bUseEfuse == FALSE) return FALSE; for (i = 0; i < pAd->chipCap.EFUSE_USAGE_MAP_END/2; i++) { InBuf[0] = (USHORT)(2*i); InBuf[1] = 2; InBuf[2] = 0x0; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); if (i%4 == 0) DBGPRINT(RT_DEBUG_OFF, ("\nBlock %x:", i/8)); DBGPRINT(RT_DEBUG_OFF, ("%04x ", InBuf[2])); } return TRUE; } #if 0 INT set_eFuseLoadFromBin_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { RTMP_STRING *src; RTMP_OS_FD srcf; RTMP_OS_FS_INFO osfsInfo; INT retval, memSize; RTMP_STRING *buffer, *memPtr; INT TotalByte= 0,ReadedByte=0,CompareBuf=1; USHORT *PDATA; USHORT DATA; memSize = 128 + MAX_EEPROM_BIN_FILE_SIZE + sizeof(USHORT) * 8; os_alloc_mem(NULL, (UCHAR **)&memPtr, memSize); if (memPtr == NULL) return FALSE; NdisZeroMemory(memPtr, memSize); src = memPtr; buffer = src + 128; PDATA = (USHORT*)(buffer + MAX_EEPROM_BIN_FILE_SIZE); if(strlen(arg)>0) NdisMoveMemory(src, arg, strlen(arg)); else NdisMoveMemory(src, EEPROM_DEFULT_BIN_FILE, strlen(EEPROM_DEFULT_BIN_FILE)); DBGPRINT(RT_DEBUG_OFF, ("FileName=%s\n",src)); RtmpOSFSInfoChange(&osfsInfo, TRUE); srcf = RtmpOSFileOpen(src, O_RDONLY, 0); if (IS_FILE_OPEN_ERR(srcf)) { DBGPRINT_ERR(("--> Error opening file %s\n", src)); retval = FALSE; goto recoverFS; } else { /* The object must have a read method*/ while(RtmpOSFileRead(srcf, &buffer[TotalByte], 1)==1) { TotalByte++; if(TotalByte>MAX_EEPROM_BIN_FILE_SIZE) { DBGPRINT(RT_DEBUG_ERROR, ("--> Error reading file %s, file size too large[>%d]\n", src, MAX_EEPROM_BIN_FILE_SIZE)); retval = FALSE; goto closeFile; } } retval = RtmpOSFileClose(srcf); if (retval) DBGPRINT(RT_DEBUG_TRACE, ("--> Error closing file %s\n", src)); } RtmpOSFSInfoChange(&osfsInfo, FALSE); for(ReadedByte=0;ReadedByte0) NdisMoveMemory(src, arg, strlen(arg)); else NdisMoveMemory(src, EEPROM_DEFULT_BIN_FILE, strlen(EEPROM_DEFULT_BIN_FILE)); DBGPRINT(RT_DEBUG_OFF, ("FileName=%s\n",src)); RtmpOSFSInfoChange(&osfsInfo, TRUE); srcf = RtmpOSFileOpen(src, O_RDONLY, 0); if (IS_FILE_OPEN_ERR(srcf)) { DBGPRINT_ERR(("--> Error opening file %s\n", src)); retval = FALSE; goto recoverFS; } else { /* The object must have a read method*/ while(RtmpOSFileRead(srcf, &buffer[TotalByte], 1)==1) { TotalByte++; if(TotalByte>MAX_EEPROM_BIN_FILE_SIZE) { DBGPRINT(RT_DEBUG_ERROR, ("--> Error reading file %s, file size too large[>%d]\n", src, MAX_EEPROM_BIN_FILE_SIZE)); retval = FALSE; goto closeFile; } } retval = RtmpOSFileClose(srcf); if (retval) DBGPRINT(RT_DEBUG_TRACE, ("--> Error closing file %s\n", src)); } RtmpOSFSInfoChange(&osfsInfo, FALSE); for ( offset = 0 ; offset < TotalByte ; offset += 16 ) { if ( memcmp( ptr, all_ff, 16 ) ) { DBGPRINT(RT_DEBUG_TRACE, ("offset 0x%04x: ", offset)); for ( index = 0 ; index < 16 ; index += 2 ) { value = *(USHORT *)(ptr + index); //eFuseWrite(pAd, offset + index ,&value, 2); DBGPRINT(RT_DEBUG_TRACE, ("0x%04x ", value)); } DBGPRINT(RT_DEBUG_TRACE, ("\n")); } ptr += 16; } return TRUE; closeFile: if (srcf) if (RtmpOSFileClose(srcf) != 0) retval = FALSE; recoverFS: RtmpOSFSInfoChange(&osfsInfo, FALSE); if (memPtr) /* kfree(memPtr);*/ os_free_mem(NULL, memPtr); return retval; } #endif #if 0 static NTSTATUS eFuseWriteRegistersFromBin( IN PRTMP_ADAPTER pAd, IN USHORT Offset, IN USHORT Length, IN USHORT* pData) { USHORT i,StartBlock=0,EndBlock=0; USHORT eFuseData; USHORT LogicalAddress, BlkNum = 0xffff; UCHAR EFSROM_AOUT,Loop=0; EFUSE_CTRL_STRUC eFuseCtrlStruc; USHORT efuseDataOffset; UINT32 data,tempbuffer; USHORT addr,tmpaddr, InBuf[3], tmpOffset; UINT32 buffer[4]; BOOLEAN bWriteSuccess = TRUE; BOOLEAN bNotWrite=TRUE; BOOLEAN bAllocateNewBlk=TRUE; DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin Offset=%x, pData=%04x:%04x:%04x:%04x\n", Offset, *pData,*(pData+1),*(pData+2),*(pData+3))); /*set start block and end block number, start from tail of mapping table*/ if( (pAd->chipCap.EFUSE_USAGE_MAP_END % 2) != 0) { StartBlock = pAd->chipCap.EFUSE_USAGE_MAP_END-1; } else { StartBlock = pAd->chipCap.EFUSE_USAGE_MAP_END; } if( (pAd->chipCap.EFUSE_USAGE_MAP_START % 2) != 0) { EndBlock = pAd->chipCap.EFUSE_USAGE_MAP_START-1; } else { EndBlock = pAd->chipCap.EFUSE_USAGE_MAP_START; } do { /*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.*/ Loop++; 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*/ bAllocateNewBlk=TRUE; for (i=StartBlock; i>=EndBlock; 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 >> 8) & 0xff) == 0) { if(i != pAd->chipCap.EFUSE_USAGE_MAP_END) { BlkNum = i+1-pAd->chipCap.EFUSE_USAGE_MAP_START; break; } } if( (LogicalAddress & 0xff) == 0) { if(i != (pAd->chipCap.EFUSE_USAGE_MAP_START-1)) { BlkNum = i-pAd->chipCap.EFUSE_USAGE_MAP_START; 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")); #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) efuseDataOffset = EFUSE_DATA0_3290; else #endif 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.*/ RTMP_IO_READ32(pAd, EFUSE_CTRL, &eFuseCtrlStruc.word); 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, &eFuseCtrlStruc.word); /*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 < 500) { 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)*/ #if defined(RT3290) || defined(RT65xx) || defined(MT7601) if (IS_RT3290(pAd) || IS_RT65XX(pAd) || IS_MT7601(pAd)) efuseDataOffset = EFUSE_DATA0_3290; else #endif 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 = pAd->chipCap.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 = pAd->chipCap.EFUSE_USAGE_MAP_START+BlkNum; /*find a new mapping entry*/ BlkNum = 0xffff; for (i=StartBlock; i>=EndBlock; 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 >> 8) & 0xff) == 0) { if(i !=pAd->chipCap.EFUSE_USAGE_MAP_END) { BlkNum = i+1-pAd->chipCap.EFUSE_USAGE_MAP_START; break; } } if( (LogicalAddress & 0xff) == 0) { if(i != (pAd->chipCap.EFUSE_USAGE_MAP_START-1)) { BlkNum = i-pAd->chipCap.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 <EFuseTag = (value & 0xff); } return 0; } #if 0 INT rtmp_ee_write_to_efuse( IN PRTMP_ADAPTER pAd) { INT read_byte = 0, cmp_buf = 1; USHORT data, *pdata; pdata = (USHORT*)(pAd->EEPROMImage + MAX_EEPROM_BIN_FILE_SIZE); for (read_byte = 0; read_byte < MAX_EEPROM_BIN_FILE_SIZE; read_byte++) { DBGPRINT(RT_DEBUG_TRACE, ("%02X ",pAd->EEPROMImage[read_byte] & 0xff)); if ((read_byte+1)%2 == 0) pdata[read_byte/2%8] = ((pAd->EEPROMImage[read_byte] << 8) & 0xff00) | (pAd->EEPROMImage[read_byte-1] & 0xff); if (read_byte%16 == 0) cmp_buf = pAd->EEPROMImage[read_byte] & 0xff; else { cmp_buf &= (pAd->EEPROMImage[read_byte] & 0xff); if ((read_byte+1)%16 == 0) { DBGPRINT(RT_DEBUG_TRACE, ("Result=%02X, blk=%02X\n", cmp_buf, read_byte/16)); if (cmp_buf != 0xff) eFuseWriteRegistersFromBin(pAd, (USHORT)read_byte - 15, 16, pdata); else if(eFuseReadRegisters(pAd, read_byte, 2, (PUSHORT)&data) != 0x3f) eFuseWriteRegistersFromBin(pAd, (USHORT)read_byte - 15, 16, pdata); NdisZeroMemory(pdata, 16); } } } return TRUE; } #else INT rtmp_ee_write_to_efuse( IN PRTMP_ADAPTER pAd) { USHORT length = pAd->chipCap.EEPROM_DEFAULT_BIN_SIZE; UCHAR *ptr = pAd->EEPROMImage; UCHAR index; UCHAR all_ff[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; USHORT offset = 0; USHORT value; for ( offset = 0 ; offset < length ; offset += 16 ) { if ( memcmp( ptr, all_ff, 16 ) ) { DBGPRINT(RT_DEBUG_TRACE, ("offset 0x%04x: ", offset)); for ( index = 0 ; index < 16 ; index += 2 ) { value = le2cpu16(*(USHORT *)(ptr + index)); eFuseWrite(pAd, offset + index ,&value, 2); DBGPRINT(RT_DEBUG_TRACE, ("0x%04x ", value)); } DBGPRINT(RT_DEBUG_TRACE, ("\n")); } ptr += 16; } return TRUE; } #endif VOID eFuseGetFreeBlockCount(IN PRTMP_ADAPTER pAd, PUINT EfuseFreeBlock) { USHORT i=0, StartBlock=0, EndBlock=0; USHORT LogicalAddress; USHORT FirstFreeBlock = 0xffff, LastFreeBlock = 0xffff; #ifndef CAL_FREE_IC_SUPPORT if(!pAd->bUseEfuse) { DBGPRINT(RT_DEBUG_TRACE,("eFuseGetFreeBlockCount Only supports efuse Mode\n")); return ; } #endif /* CAL_FREE_IC_SUPPORT */ *EfuseFreeBlock = 0; /* find first free block*/ if( (pAd->chipCap.EFUSE_USAGE_MAP_START % 2) != 0) { StartBlock = pAd->chipCap.EFUSE_USAGE_MAP_START-1; } else { StartBlock = pAd->chipCap.EFUSE_USAGE_MAP_START; } if( (pAd->chipCap.EFUSE_USAGE_MAP_END % 2) != 0) { EndBlock = pAd->chipCap.EFUSE_USAGE_MAP_END-1; } else { EndBlock = pAd->chipCap.EFUSE_USAGE_MAP_END; } for (i = StartBlock; i <= EndBlock; i+=2) { EfusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if( (LogicalAddress & 0xff) == 0) { if(i != (pAd->chipCap.EFUSE_USAGE_MAP_START-1)) { FirstFreeBlock = i; break; } } if(( (LogicalAddress >> 8) & 0xff) == 0) { if(i != pAd->chipCap.EFUSE_USAGE_MAP_END) { FirstFreeBlock = i+1; break; } } } DBGPRINT(RT_DEBUG_TRACE, ("eFuseGetFreeBlockCount, FirstFreeBlock= 0x%x\n", FirstFreeBlock)); /*if not find, return free block number = 0*/ if(FirstFreeBlock == 0xffff) { *EfuseFreeBlock = 0; return; } #if 0 /* find last free block*/ if( (pAd->pAd->chipCap.EFUSE_USAGE_MAP_END % 2) != 0) { StartBlock = pAd->pAd->chipCap.EFUSE_USAGE_MAP_END-1; } else { StartBlock = pAd->pAd->chipCap.EFUSE_USAGE_MAP_END; } if( (pAd->pAd->chipCap.EFUSE_USAGE_MAP_START % 2) != 0) { EndBlock = pAd->pAd->chipCap.EFUSE_USAGE_MAP_START-1; } else { EndBlock = pAd->pAd->chipCap.EFUSE_USAGE_MAP_START; } #endif for (i = EndBlock; i >= StartBlock; i-=2) { EfusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if(( (LogicalAddress >> 8) & 0xff) == 0) { if(i != pAd->chipCap.EFUSE_USAGE_MAP_END) { LastFreeBlock = i+1; break; } } if( (LogicalAddress & 0xff) == 0) { if(i != (pAd->chipCap.EFUSE_USAGE_MAP_START-1)) { LastFreeBlock = i; break; } } } DBGPRINT(RT_DEBUG_TRACE, ("eFuseGetFreeBlockCount, LastFreeBlock= 0x%x\n", LastFreeBlock)); /*if not find last free block, return free block number = 0, this should not happen since we have checked first free block number previously*/ if(LastFreeBlock == 0xffff) { *EfuseFreeBlock = 0; return; } /* return total free block number, last free block number must >= first free block number*/ if(LastFreeBlock < FirstFreeBlock) { *EfuseFreeBlock = 0; } else { *EfuseFreeBlock = LastFreeBlock - FirstFreeBlock + 1; } DBGPRINT(RT_DEBUG_TRACE,("eFuseGetFreeBlockCount is %d\n",*EfuseFreeBlock)); } INT eFuse_init(RTMP_ADAPTER *pAd) { UINT EfuseFreeBlock=0; #if defined(CAL_FREE_IC_SUPPORT) && !defined(CONFIG_COB_SOLUTION_SUPPORT) BOOLEAN bCalFree; #endif /* defined(CAL_FREE_IC_SUPPORT) && !defined(CONFIG_COB_SOLUTION_SUPPORT) */ /*RT3572 means 3062/3562/3572*/ /*3593 means 3593*/ DBGPRINT(RT_DEBUG_ERROR, ("NVM is Efuse and its size =%x[%x-%x] \n",pAd->chipCap.EFUSE_USAGE_MAP_SIZE,pAd->chipCap.EFUSE_USAGE_MAP_START,pAd->chipCap.EFUSE_USAGE_MAP_END)); eFuseGetFreeBlockCount(pAd, &EfuseFreeBlock); /*If the used block of efuse is less than 5. We assume the default value*/ /* of this efuse is empty and change to the buffer mode in odrder to */ /*bring up interfaces successfully.*/ if (EfuseFreeBlock >= pAd->chipCap.EFUSE_RESERVED_SIZE) { DBGPRINT(RT_DEBUG_OFF, ("NVM is efuse and the information is too less to bring up the interface\n")); DBGPRINT(RT_DEBUG_OFF, ("Load EEPROM buffer from BIN, and force to use BIN buffer mode\n")); pAd->bUseEfuse = FALSE; rtmp_ee_load_from_bin(pAd); /* Forse to use BIN eeprom buffer mode */ RtmpChipOpsEepromHook(pAd, pAd->infType,E2P_BIN_MODE); #if defined(CAL_FREE_IC_SUPPORT) && !defined(CONFIG_COB_SOLUTION_SUPPORT) RTMP_CAL_FREE_IC_CHECK(pAd,bCalFree); if (bCalFree) { DBGPRINT(RT_DEBUG_OFF, ("Cal Free IC!!\n")); RTMP_CAL_FREE_DATA_GET(pAd); } else { DBGPRINT(RT_DEBUG_OFF, ("Non Cal Free IC!!\n")); } #endif /* defined(CAL_FREE_IC_SUPPORT) && !defined(CONFIG_COB_SOLUTION_SUPPORT) */ } else { rtmp_ee_load_from_efuse(pAd); } return 0; } INT efuse_probe(RTMP_ADAPTER *pAd) { UINT32 eFuseCtrl, ctrl_reg; if (WaitForAsicReady(pAd) == FALSE) return -1; pAd->bUseEfuse=FALSE; #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) ctrl_reg = MT_EE_CTRL; else #endif /* MT_MAC */ #ifdef RT65xx // TODO: shiang-6590, find a better naming for EFUSE_CTRL_3290!! if (IS_RT65XX(pAd)) ctrl_reg = EFUSE_CTRL_3290; else #endif /* RT65xx */ #ifdef MT7601 if (IS_MT7601(pAd)) ctrl_reg = EFUSE_CTRL_3290; else #endif /* MT7601 */ #ifdef RT3290 if (IS_RT3290(pAd)) ctrl_reg = EFUSE_CTRL_3290; else #endif /* RT3290 */ ctrl_reg = EFUSE_CTRL; EFUSE_IO_READ32(pAd, ctrl_reg, &eFuseCtrl); DBGPRINT(RT_DEBUG_OFF, ("%s: efuse = %x\n", __func__, eFuseCtrl)); if (pAd->chipCap.hif_type == HIF_MT) { if ((eFuseCtrl & 0x40000000) == 0x40000000) pAd->bUseEfuse = 0; else pAd->bUseEfuse = 1; } else { pAd->bUseEfuse = ( (eFuseCtrl & 0x80000000) == 0x80000000) ? 1 : 0; } return 0; } VOID rtmp_ee_load_from_efuse(RTMP_ADAPTER *pAd) { UINT16 efuse_val=0; UINT free_blk = 0; UINT i; DBGPRINT(RT_DEBUG_OFF,("Load EEPROM buffer from efuse, and change to BIN buffer mode\n")); /* If the number of the used block is less than 5, assume the efuse is not well-calibrated, and force to use buffer mode */ eFuseGetFreeBlockCount(pAd, &free_blk); if (free_blk > (pAd->chipCap.EFUSE_USAGE_MAP_SIZE - 5)) return ; NdisZeroMemory(pAd->EEPROMImage, MAX_EEPROM_BIN_FILE_SIZE); for(i=0; iEEPROMImage[i],&efuse_val,2); } /* Change to BIN eeprom buffer mode */ RtmpChipOpsEepromHook(pAd, pAd->infType,E2P_BIN_MODE); } #ifdef CONFIG_ATE INT Set_LoadEepromBufferFromEfuse_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { /*long bEnable = simple_strtol(arg, 0, 10);*/ LONG res; int bEnable = kstrtol(arg, 10, &res); if (bEnable < 0) return FALSE; else { rtmp_ee_load_from_efuse(pAd); return TRUE; } } INT set_eFuseBufferModeWriteBack_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { int bEnable; LONG res; bEnable = kstrtol(arg, 10, &res); if (bEnable < 0) return FALSE; else { DBGPRINT(RT_DEBUG_TRACE, ("%s::Write EEPROM buffer back to eFuse\n", __FUNCTION__)); Set_EepromBufferWriteBack_Proc(pAd, "1"); return TRUE; } } INT set_BinModeWriteBack_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { LONG res; int bEnable = kstrtol(arg, 10, &res); if (bEnable < 0) return FALSE; else { DBGPRINT(RT_DEBUG_TRACE, ("%s::Write EEPROM buffer back to BIN\n", __FUNCTION__)); Set_EepromBufferWriteBack_Proc(pAd, "4"); return TRUE; } } #endif /* CONFIG_ATE */ #endif /* RTMP_EFUSE_SUPPORT */