aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/rt2860/common/ee_efuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/rt2860/common/ee_efuse.c')
-rw-r--r--drivers/staging/rt2860/common/ee_efuse.c344
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 000000000000..03412f5bc990
--- /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;
+}