/* ************************************************************************* * 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: ee_efuse.c Abstract: Miniport generic portion header file Revision History: Who When What -------- ---------- ---------------------------------------------- */ #include "../rt_config.h" #define EFUSE_USAGE_MAP_START 0x2d0 #define EFUSE_USAGE_MAP_END 0x2fc #define EFUSE_USAGE_MAP_SIZE 45 #define EFUSE_EEPROM_DEFULT_FILE "RT30xxEEPROM.bin" #define MAX_EEPROM_BIN_FILE_SIZE 1024 #define EFUSE_TAG 0x2fe typedef union _EFUSE_CTRL_STRUC { struct { UINT32 EFSROM_AOUT:6; UINT32 EFSROM_MODE:2; UINT32 EFSROM_LDO_OFF_TIME:6; UINT32 EFSROM_LDO_ON_TIME:2; UINT32 EFSROM_AIN:10; UINT32 RESERVED:4; UINT32 EFSROM_KICK:1; UINT32 SEL_EFUSE:1; } field; UINT32 word; } EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; /* ======================================================================== Routine Description: Arguments: Return Value: 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, &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); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. i = 0; while (i < 500) { //rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4); RTMP_IO_READ32(pAd, EFUSE_CTRL, &eFuseCtrlStruc.word); 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 < Length / 2; i++) *(pData + 2 * i) = 0xffff; } else { //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x590-0x59C) efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC); //data hold 4 bytes data. //In RTMP_IO_READ32 will automatically execute 32-bytes swapping RTMP_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. data = data >> (8 * (Offset & 0x3)); NdisMoveMemory(pData, &data, Length); } return (UCHAR) eFuseCtrlStruc.field.EFSROM_AOUT; } /* ======================================================================== Routine Description: Arguments: Return Value: 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, &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); RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. i = 0; while (i < 500) { RTMP_IO_READ32(pAd, EFUSE_CTRL, &eFuseCtrlStruc.word); 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); data = data >> (8 * (Offset & 0x3)); NdisMoveMemory(pData, &data, Length); } /* ======================================================================== Routine Description: Arguments: Return Value: Note: ======================================================================== */ static 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 < Length; i += 2) { eFusePhysicalReadRegisters(pAd, Offset + i, 2, &pOutBuf[i / 2]); } } /* ======================================================================== Routine Description: Arguments: Return Value: Note: ======================================================================== */ INT set_eFuseGetFreeBlockCount_Proc(IN PRTMP_ADAPTER pAd, IN PSTRING arg) { USHORT i; USHORT LogicalAddress; USHORT efusefreenum = 0; if (!pAd->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 PSTRING arg) { USHORT InBuf[3]; INT i = 0; if (!pAd->bUseEfuse) return FALSE; for (i = 0; i < EFUSE_USAGE_MAP_END / 2; i++) { InBuf[0] = 2 * i; InBuf[1] = 2; InBuf[2] = 0x0; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); if (i % 4 == 0) printk("\nBlock %x:", i / 8); printk("%04x ", InBuf[2]); } return TRUE; } int rtmp_ee_efuse_read16(IN RTMP_ADAPTER * pAd, IN USHORT Offset, OUT USHORT * pValue) { eFuseReadRegisters(pAd, Offset, 2, pValue); return (*pValue); } int RtmpEfuseSupportCheck(IN RTMP_ADAPTER * pAd) { USHORT value; if (IS_RT30xx(pAd)) { eFusePhysicalReadRegisters(pAd, EFUSE_TAG, 2, &value); pAd->EFuseTag = (value & 0xff); } return 0; } VOID eFuseGetFreeBlockCount(IN PRTMP_ADAPTER pAd, PUINT EfuseFreeBlock) { USHORT i; USHORT LogicalAddress; if (!pAd->bUseEfuse) { DBGPRINT(RT_DEBUG_TRACE, ("eFuseGetFreeBlockCount Only supports efuse Mode\n")); return; } for (i = EFUSE_USAGE_MAP_START; i <= EFUSE_USAGE_MAP_END; i += 2) { eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); if ((LogicalAddress & 0xff) == 0) { *EfuseFreeBlock = (UCHAR) (EFUSE_USAGE_MAP_END - i + 1); break; } else if (((LogicalAddress >> 8) & 0xff) == 0) { *EfuseFreeBlock = (UCHAR) (EFUSE_USAGE_MAP_END - i); break; } if (i == EFUSE_USAGE_MAP_END) *EfuseFreeBlock = 0; } DBGPRINT(RT_DEBUG_TRACE, ("eFuseGetFreeBlockCount is 0x%x\n", *EfuseFreeBlock)); } INT eFuse_init(IN PRTMP_ADAPTER pAd) { UINT EfuseFreeBlock = 0; DBGPRINT(RT_DEBUG_ERROR, ("NVM is Efuse and its size =%x[%x-%x] \n", EFUSE_USAGE_MAP_SIZE, EFUSE_USAGE_MAP_START, EFUSE_USAGE_MAP_END)); eFuseGetFreeBlockCount(pAd, &EfuseFreeBlock); return 0; }