📄 eeprom.c
字号:
/* ************************************************************************* * 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_LEVELVOID 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_LEVELVOID LowerClock( IN PRTMP_ADAPTER pAd, IN UINT32 *x){ *x = *x & ~EESK; RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); RTMPusecDelay(1);}// IRQL = PASSIVE_LEVELUSHORT 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_LEVELVOID 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_LEVELVOID 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_LEVELUSHORT 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;} //ReadEEpromVOID 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<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.#ifdef RT_BIG_ENDIAN data = data << (8*((Offset & 0x3)^0x2)); #else data = data >> (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<Length; i+=2) { eFusePhysicalReadRegisters(pAd,Offset+i, 2, &pOutBuf[i/2]); } }/* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -