aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/rt2860/common/ee_efuse.c
blob: fed0ba45227125a360224897138e03a102bb15a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
 *************************************************************************
 * 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(KERN_DEBUG "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;

	printk(KERN_DEBUG "Block 0: ");

	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 && i % 4 == 0) {
			printk(KERN_CONT "\n");
			printk(KERN_DEBUG "Block %x:", i / 8);
		}
		printk(KERN_CONT "%04x ", InBuf[2]);
	}
	printk(KERN_CONT "\n");

	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;
}