diff options
Diffstat (limited to 'drivers/staging/rt2860/common/ee_efuse.c')
-rw-r--r-- | drivers/staging/rt2860/common/ee_efuse.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/drivers/staging/rt2860/common/ee_efuse.c b/drivers/staging/rt2860/common/ee_efuse.c new file mode 100644 index 00000000000..03412f5bc99 --- /dev/null +++ b/drivers/staging/rt2860/common/ee_efuse.c @@ -0,0 +1,344 @@ +/* + ************************************************************************* + * 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 { + u32 EFSROM_AOUT:6; + u32 EFSROM_MODE:2; + u32 EFSROM_LDO_OFF_TIME:6; + u32 EFSROM_LDO_ON_TIME:2; + u32 EFSROM_AIN:10; + u32 RESERVED:4; + u32 EFSROM_KICK:1; + u32 SEL_EFUSE:1; + } field; + u32 word; +} EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; + +/* +======================================================================== + + Routine Description: + + Arguments: + + Return Value: + + Note: + +======================================================================== +*/ +u8 eFuseReadRegisters(struct rt_rtmp_adapter *pAd, + u16 Offset, u16 Length, u16 * pData) +{ + EFUSE_CTRL_STRUC eFuseCtrlStruc; + int i; + u16 efuseDataOffset; + u32 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 (u8)eFuseCtrlStruc.field.EFSROM_AOUT; + +} + +/* +======================================================================== + + Routine Description: + + Arguments: + + Return Value: + + Note: + +======================================================================== +*/ +void eFusePhysicalReadRegisters(struct rt_rtmp_adapter *pAd, + u16 Offset, + u16 Length, u16 * pData) +{ + EFUSE_CTRL_STRUC eFuseCtrlStruc; + int i; + u16 efuseDataOffset; + u32 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(struct rt_rtmp_adapter *pAd, + u16 *lpInBuffer, + unsigned long nInBufferSize, + u16 *lpOutBuffer, unsigned long nOutBufferSize) +{ + u16 *pInBuf = (u16 *) lpInBuffer; + u16 *pOutBuf = (u16 *) lpOutBuffer; + + u16 Offset = pInBuf[0]; /*addr */ + u16 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(struct rt_rtmp_adapter *pAd, char *arg) +{ + u16 i; + u16 LogicalAddress; + u16 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 = (u8)(EFUSE_USAGE_MAP_END - i + 1); + break; + } else if (((LogicalAddress >> 8) & 0xff) == 0) { + efusefreenum = (u8)(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(struct rt_rtmp_adapter *pAd, char *arg) +{ + u16 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(struct rt_rtmp_adapter *pAd, + u16 Offset, u16 * pValue) +{ + eFuseReadRegisters(pAd, Offset, 2, pValue); + return (*pValue); +} + +int RtmpEfuseSupportCheck(struct rt_rtmp_adapter *pAd) +{ + u16 value; + + if (IS_RT30xx(pAd)) { + eFusePhysicalReadRegisters(pAd, EFUSE_TAG, 2, &value); + pAd->EFuseTag = (value & 0xff); + } + return 0; +} + +void eFuseGetFreeBlockCount(struct rt_rtmp_adapter *pAd, u32 *EfuseFreeBlock) +{ + u16 i; + u16 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 = (u8)(EFUSE_USAGE_MAP_END - i + 1); + break; + } else if (((LogicalAddress >> 8) & 0xff) == 0) { + *EfuseFreeBlock = (u8)(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(struct rt_rtmp_adapter *pAd) +{ + u32 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; +} |