Commit | Line | Data |
---|---|---|
91980990 GKH |
1 | /* |
2 | ************************************************************************* | |
3 | * Ralink Tech Inc. | |
4 | * 5F., No.36, Taiyuan St., Jhubei City, | |
5 | * Hsinchu County 302, | |
6 | * Taiwan, R.O.C. | |
7 | * | |
8 | * (c) Copyright 2002-2007, Ralink Technology, Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. * | |
14 | * * | |
15 | * This program is distributed in the hope that it will be useful, * | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
18 | * GNU General Public License for more details. * | |
19 | * * | |
20 | * You should have received a copy of the GNU General Public License * | |
21 | * along with this program; if not, write to the * | |
22 | * Free Software Foundation, Inc., * | |
23 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |
24 | * * | |
25 | ************************************************************************* | |
26 | ||
27 | Module Name: | |
28 | eeprom.c | |
29 | ||
30 | Abstract: | |
31 | ||
32 | Revision History: | |
33 | Who When What | |
34 | -------- ---------- ---------------------------------------------- | |
35 | Name Date Modification logs | |
36 | */ | |
37 | #include "../rt_config.h" | |
38 | ||
39 | // IRQL = PASSIVE_LEVEL | |
40 | VOID RaiseClock( | |
41 | IN PRTMP_ADAPTER pAd, | |
42 | IN UINT32 *x) | |
43 | { | |
44 | *x = *x | EESK; | |
45 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); | |
46 | RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition | |
47 | } | |
48 | ||
49 | // IRQL = PASSIVE_LEVEL | |
50 | VOID LowerClock( | |
51 | IN PRTMP_ADAPTER pAd, | |
52 | IN UINT32 *x) | |
53 | { | |
54 | *x = *x & ~EESK; | |
55 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); | |
56 | RTMPusecDelay(1); | |
57 | } | |
58 | ||
59 | // IRQL = PASSIVE_LEVEL | |
60 | USHORT ShiftInBits( | |
61 | IN PRTMP_ADAPTER pAd) | |
62 | { | |
63 | UINT32 x,i; | |
64 | USHORT data=0; | |
65 | ||
66 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
67 | ||
68 | x &= ~( EEDO | EEDI); | |
69 | ||
70 | for(i=0; i<16; i++) | |
71 | { | |
72 | data = data << 1; | |
73 | RaiseClock(pAd, &x); | |
74 | ||
75 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
37843390 BZ |
76 | |
77 | LowerClock(pAd, &x); /* prevent read failed */ | |
78 | ||
91980990 GKH |
79 | x &= ~(EEDI); |
80 | if(x & EEDO) | |
81 | data |= 1; | |
91980990 GKH |
82 | } |
83 | ||
84 | return data; | |
85 | } | |
86 | ||
87 | // IRQL = PASSIVE_LEVEL | |
88 | VOID ShiftOutBits( | |
89 | IN PRTMP_ADAPTER pAd, | |
90 | IN USHORT data, | |
91 | IN USHORT count) | |
92 | { | |
93 | UINT32 x,mask; | |
94 | ||
95 | mask = 0x01 << (count - 1); | |
96 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
97 | ||
98 | x &= ~(EEDO | EEDI); | |
99 | ||
100 | do | |
101 | { | |
102 | x &= ~EEDI; | |
103 | if(data & mask) x |= EEDI; | |
104 | ||
105 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
106 | ||
107 | RaiseClock(pAd, &x); | |
108 | LowerClock(pAd, &x); | |
109 | ||
110 | mask = mask >> 1; | |
111 | } while(mask); | |
112 | ||
113 | x &= ~EEDI; | |
114 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
115 | } | |
116 | ||
117 | // IRQL = PASSIVE_LEVEL | |
118 | VOID EEpromCleanup( | |
119 | IN PRTMP_ADAPTER pAd) | |
120 | { | |
121 | UINT32 x; | |
122 | ||
123 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
124 | ||
125 | x &= ~(EECS | EEDI); | |
126 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
127 | ||
128 | RaiseClock(pAd, &x); | |
129 | LowerClock(pAd, &x); | |
130 | } | |
131 | ||
132 | VOID EWEN( | |
133 | IN PRTMP_ADAPTER pAd) | |
134 | { | |
135 | UINT32 x; | |
136 | ||
137 | // reset bits and set EECS | |
138 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
139 | x &= ~(EEDI | EEDO | EESK); | |
140 | x |= EECS; | |
141 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
142 | ||
143 | // kick a pulse | |
144 | RaiseClock(pAd, &x); | |
145 | LowerClock(pAd, &x); | |
146 | ||
147 | // output the read_opcode and six pulse in that order | |
148 | ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); | |
149 | ShiftOutBits(pAd, 0, 6); | |
150 | ||
151 | EEpromCleanup(pAd); | |
152 | } | |
153 | ||
154 | VOID EWDS( | |
155 | IN PRTMP_ADAPTER pAd) | |
156 | { | |
157 | UINT32 x; | |
158 | ||
159 | // reset bits and set EECS | |
160 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
161 | x &= ~(EEDI | EEDO | EESK); | |
162 | x |= EECS; | |
163 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
164 | ||
165 | // kick a pulse | |
166 | RaiseClock(pAd, &x); | |
167 | LowerClock(pAd, &x); | |
168 | ||
169 | // output the read_opcode and six pulse in that order | |
170 | ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); | |
171 | ShiftOutBits(pAd, 0, 6); | |
172 | ||
173 | EEpromCleanup(pAd); | |
174 | } | |
175 | ||
176 | // IRQL = PASSIVE_LEVEL | |
177 | USHORT RTMP_EEPROM_READ16( | |
178 | IN PRTMP_ADAPTER pAd, | |
179 | IN USHORT Offset) | |
180 | { | |
181 | UINT32 x; | |
182 | USHORT data; | |
183 | ||
606661ea | 184 | #ifdef RT2870 |
59fe2d89 BZ |
185 | if (pAd->NicConfig2.field.AntDiversity) |
186 | { | |
187 | pAd->EepromAccess = TRUE; | |
188 | } | |
59fe2d89 | 189 | #endif |
91980990 GKH |
190 | Offset /= 2; |
191 | // reset bits and set EECS | |
192 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
193 | x &= ~(EEDI | EEDO | EESK); | |
194 | x |= EECS; | |
195 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
196 | ||
59fe2d89 BZ |
197 | // patch can not access e-Fuse issue |
198 | if (!IS_RT3090(pAd)) | |
199 | { | |
91980990 GKH |
200 | // kick a pulse |
201 | RaiseClock(pAd, &x); | |
202 | LowerClock(pAd, &x); | |
59fe2d89 | 203 | } |
91980990 GKH |
204 | |
205 | // output the read_opcode and register number in that order | |
206 | ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); | |
207 | ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); | |
208 | ||
209 | // Now read the data (16 bits) in from the selected EEPROM word | |
210 | data = ShiftInBits(pAd); | |
211 | ||
212 | EEpromCleanup(pAd); | |
213 | ||
606661ea | 214 | #ifdef RT2870 |
59fe2d89 BZ |
215 | // Antenna and EEPROM access are both using EESK pin, |
216 | // Therefor we should avoid accessing EESK at the same time | |
217 | // Then restore antenna after EEPROM access | |
218 | if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) | |
219 | { | |
220 | pAd->EepromAccess = FALSE; | |
221 | AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); | |
222 | } | |
59fe2d89 | 223 | #endif |
91980990 GKH |
224 | return data; |
225 | } //ReadEEprom | |
226 | ||
227 | VOID RTMP_EEPROM_WRITE16( | |
228 | IN PRTMP_ADAPTER pAd, | |
229 | IN USHORT Offset, | |
230 | IN USHORT Data) | |
231 | { | |
232 | UINT32 x; | |
233 | ||
606661ea | 234 | #ifdef RT2870 |
59fe2d89 BZ |
235 | if (pAd->NicConfig2.field.AntDiversity) |
236 | { | |
237 | pAd->EepromAccess = TRUE; | |
238 | } | |
59fe2d89 | 239 | #endif |
91980990 GKH |
240 | Offset /= 2; |
241 | ||
242 | EWEN(pAd); | |
243 | ||
244 | // reset bits and set EECS | |
245 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
246 | x &= ~(EEDI | EEDO | EESK); | |
247 | x |= EECS; | |
248 | RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); | |
249 | ||
59fe2d89 BZ |
250 | // patch can not access e-Fuse issue |
251 | if (!IS_RT3090(pAd)) | |
252 | { | |
91980990 GKH |
253 | // kick a pulse |
254 | RaiseClock(pAd, &x); | |
255 | LowerClock(pAd, &x); | |
59fe2d89 | 256 | } |
91980990 GKH |
257 | |
258 | // output the read_opcode ,register number and data in that order | |
259 | ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); | |
260 | ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); | |
261 | ShiftOutBits(pAd, Data, 16); // 16-bit access | |
262 | ||
263 | // read DO status | |
264 | RTMP_IO_READ32(pAd, E2PROM_CSR, &x); | |
265 | ||
266 | EEpromCleanup(pAd); | |
267 | ||
268 | RTMPusecDelay(10000); //delay for twp(MAX)=10ms | |
269 | ||
270 | EWDS(pAd); | |
271 | ||
272 | EEpromCleanup(pAd); | |
59fe2d89 | 273 | |
606661ea | 274 | #ifdef RT2870 |
59fe2d89 BZ |
275 | // Antenna and EEPROM access are both using EESK pin, |
276 | // Therefor we should avoid accessing EESK at the same time | |
277 | // Then restore antenna after EEPROM access | |
278 | if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) | |
279 | { | |
280 | pAd->EepromAccess = FALSE; | |
281 | AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); | |
282 | } | |
59fe2d89 BZ |
283 | #endif |
284 | } | |
285 | ||
5cc86f28 | 286 | #ifdef RT2870 |
59fe2d89 BZ |
287 | /* |
288 | ======================================================================== | |
289 | ||
290 | Routine Description: | |
291 | ||
292 | Arguments: | |
293 | ||
294 | Return Value: | |
295 | ||
296 | IRQL = | |
297 | ||
298 | Note: | |
299 | ||
300 | ======================================================================== | |
301 | */ | |
302 | UCHAR eFuseReadRegisters( | |
303 | IN PRTMP_ADAPTER pAd, | |
304 | IN USHORT Offset, | |
305 | IN USHORT Length, | |
306 | OUT USHORT* pData) | |
307 | { | |
308 | EFUSE_CTRL_STRUC eFuseCtrlStruc; | |
309 | int i; | |
310 | USHORT efuseDataOffset; | |
311 | UINT32 data; | |
312 | ||
313 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
314 | ||
315 | //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. | |
316 | //Use the eeprom logical address and covert to address to block number | |
317 | eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; | |
318 | ||
319 | //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 0. | |
320 | eFuseCtrlStruc.field.EFSROM_MODE = 0; | |
321 | ||
322 | //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. | |
323 | eFuseCtrlStruc.field.EFSROM_KICK = 1; | |
324 | ||
325 | NdisMoveMemory(&data, &eFuseCtrlStruc, 4); | |
326 | RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); | |
327 | ||
328 | //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. | |
329 | i = 0; | |
330 | while(i < 100) | |
331 | { | |
332 | //rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4); | |
333 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
334 | if(eFuseCtrlStruc.field.EFSROM_KICK == 0) | |
335 | { | |
336 | break; | |
337 | } | |
338 | RTMPusecDelay(2); | |
339 | i++; | |
340 | } | |
341 | ||
342 | //if EFSROM_AOUT is not found in physical address, write 0xffff | |
343 | if (eFuseCtrlStruc.field.EFSROM_AOUT == 0x3f) | |
344 | { | |
345 | for(i=0; i<Length/2; i++) | |
346 | *(pData+2*i) = 0xffff; | |
347 | } | |
348 | else | |
349 | { | |
350 | //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x590-0x59C) | |
351 | efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; | |
352 | //data hold 4 bytes data. | |
353 | //In RTMP_IO_READ32 will automatically execute 32-bytes swapping | |
354 | RTMP_IO_READ32(pAd, efuseDataOffset, &data); | |
355 | //Decide the upper 2 bytes or the bottom 2 bytes. | |
356 | // Little-endian S | S Big-endian | |
357 | // addr 3 2 1 0 | 0 1 2 3 | |
358 | // Ori-V D C B A | A B C D | |
359 | //After swapping | |
360 | // D C B A | D C B A | |
361 | //Return 2-bytes | |
362 | //The return byte statrs from S. Therefore, the little-endian will return BA, the Big-endian will return DC. | |
363 | //For returning the bottom 2 bytes, the Big-endian should shift right 2-bytes. | |
364 | data = data >> (8*(Offset & 0x3)); | |
365 | ||
366 | NdisMoveMemory(pData, &data, Length); | |
367 | } | |
368 | ||
369 | return (UCHAR) eFuseCtrlStruc.field.EFSROM_AOUT; | |
370 | ||
371 | } | |
372 | ||
373 | /* | |
374 | ======================================================================== | |
375 | ||
376 | Routine Description: | |
377 | ||
378 | Arguments: | |
379 | ||
380 | Return Value: | |
381 | ||
382 | IRQL = | |
383 | ||
384 | Note: | |
385 | ||
386 | ======================================================================== | |
387 | */ | |
388 | VOID eFusePhysicalReadRegisters( | |
389 | IN PRTMP_ADAPTER pAd, | |
390 | IN USHORT Offset, | |
391 | IN USHORT Length, | |
392 | OUT USHORT* pData) | |
393 | { | |
394 | EFUSE_CTRL_STRUC eFuseCtrlStruc; | |
395 | int i; | |
396 | USHORT efuseDataOffset; | |
397 | UINT32 data; | |
398 | ||
399 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
400 | ||
401 | //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. | |
402 | eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; | |
403 | ||
404 | //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. | |
405 | //Read in physical view | |
406 | eFuseCtrlStruc.field.EFSROM_MODE = 1; | |
407 | ||
408 | //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. | |
409 | eFuseCtrlStruc.field.EFSROM_KICK = 1; | |
410 | ||
411 | NdisMoveMemory(&data, &eFuseCtrlStruc, 4); | |
412 | RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); | |
413 | ||
414 | //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. | |
415 | i = 0; | |
416 | while(i < 100) | |
417 | { | |
418 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
419 | if(eFuseCtrlStruc.field.EFSROM_KICK == 0) | |
420 | break; | |
421 | RTMPusecDelay(2); | |
422 | i++; | |
423 | } | |
424 | ||
425 | //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) | |
426 | //Because the size of each EFUSE_DATA is 4 Bytes, the size of address of each is 2 bits. | |
427 | //The previous 2 bits is the EFUSE_DATA number, the last 2 bits is used to decide which bytes | |
428 | //Decide which EFUSE_DATA to read | |
429 | //590:F E D C | |
430 | //594:B A 9 8 | |
431 | //598:7 6 5 4 | |
432 | //59C:3 2 1 0 | |
433 | efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; | |
434 | ||
435 | RTMP_IO_READ32(pAd, efuseDataOffset, &data); | |
436 | ||
437 | data = data >> (8*(Offset & 0x3)); | |
438 | ||
439 | NdisMoveMemory(pData, &data, Length); | |
440 | ||
441 | } | |
442 | ||
443 | /* | |
444 | ======================================================================== | |
445 | ||
446 | Routine Description: | |
447 | ||
448 | Arguments: | |
449 | ||
450 | Return Value: | |
451 | ||
452 | IRQL = | |
453 | ||
454 | Note: | |
455 | ||
456 | ======================================================================== | |
457 | */ | |
458 | VOID eFuseReadPhysical( | |
459 | IN PRTMP_ADAPTER pAd, | |
460 | IN PUSHORT lpInBuffer, | |
461 | IN ULONG nInBufferSize, | |
462 | OUT PUSHORT lpOutBuffer, | |
463 | IN ULONG nOutBufferSize | |
464 | ) | |
465 | { | |
466 | USHORT* pInBuf = (USHORT*)lpInBuffer; | |
467 | USHORT* pOutBuf = (USHORT*)lpOutBuffer; | |
468 | ||
469 | USHORT Offset = pInBuf[0]; //addr | |
470 | USHORT Length = pInBuf[1]; //length | |
471 | int i; | |
472 | ||
473 | for(i=0; i<Length; i+=2) | |
474 | { | |
475 | eFusePhysicalReadRegisters(pAd,Offset+i, 2, &pOutBuf[i/2]); | |
476 | } | |
477 | } | |
478 | ||
479 | /* | |
480 | ======================================================================== | |
481 | ||
482 | Routine Description: | |
483 | ||
484 | Arguments: | |
485 | ||
486 | Return Value: | |
487 | ||
488 | IRQL = | |
489 | ||
490 | Note: | |
491 | ||
492 | ======================================================================== | |
493 | */ | |
494 | NTSTATUS eFuseRead( | |
495 | IN PRTMP_ADAPTER pAd, | |
496 | IN USHORT Offset, | |
497 | OUT PUCHAR pData, | |
498 | IN USHORT Length) | |
499 | { | |
500 | USHORT* pOutBuf = (USHORT*)pData; | |
501 | NTSTATUS Status = STATUS_SUCCESS; | |
502 | UCHAR EFSROM_AOUT; | |
503 | int i; | |
504 | ||
505 | for(i=0; i<Length; i+=2) | |
506 | { | |
507 | EFSROM_AOUT = eFuseReadRegisters(pAd, Offset+i, 2, &pOutBuf[i/2]); | |
508 | } | |
509 | return Status; | |
510 | } | |
511 | ||
512 | /* | |
513 | ======================================================================== | |
514 | ||
515 | Routine Description: | |
516 | ||
517 | Arguments: | |
518 | ||
519 | Return Value: | |
520 | ||
521 | IRQL = | |
522 | ||
523 | Note: | |
524 | ||
525 | ======================================================================== | |
526 | */ | |
527 | VOID eFusePhysicalWriteRegisters( | |
528 | IN PRTMP_ADAPTER pAd, | |
529 | IN USHORT Offset, | |
530 | IN USHORT Length, | |
531 | OUT USHORT* pData) | |
532 | { | |
533 | EFUSE_CTRL_STRUC eFuseCtrlStruc; | |
534 | int i; | |
535 | USHORT efuseDataOffset; | |
536 | UINT32 data, eFuseDataBuffer[4]; | |
537 | ||
538 | //Step0. Write 16-byte of data to EFUSE_DATA0-3 (0x590-0x59C), where EFUSE_DATA0 is the LSB DW, EFUSE_DATA3 is the MSB DW. | |
539 | ||
540 | ///////////////////////////////////////////////////////////////// | |
541 | //read current values of 16-byte block | |
542 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
543 | ||
544 | //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. | |
545 | eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; | |
546 | ||
547 | //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. | |
548 | eFuseCtrlStruc.field.EFSROM_MODE = 1; | |
549 | ||
550 | //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. | |
551 | eFuseCtrlStruc.field.EFSROM_KICK = 1; | |
552 | ||
553 | NdisMoveMemory(&data, &eFuseCtrlStruc, 4); | |
554 | RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); | |
555 | ||
556 | //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. | |
557 | i = 0; | |
558 | while(i < 100) | |
559 | { | |
560 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
561 | ||
562 | if(eFuseCtrlStruc.field.EFSROM_KICK == 0) | |
563 | break; | |
564 | RTMPusecDelay(2); | |
565 | i++; | |
566 | } | |
567 | ||
568 | //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) | |
569 | efuseDataOffset = EFUSE_DATA3; | |
570 | for(i=0; i< 4; i++) | |
571 | { | |
572 | RTMP_IO_READ32(pAd, efuseDataOffset, (PUINT32) &eFuseDataBuffer[i]); | |
573 | efuseDataOffset -= 4; | |
574 | } | |
575 | ||
576 | //Update the value, the offset is multiple of 2, length is 2 | |
577 | efuseDataOffset = (Offset & 0xc) >> 2; | |
578 | data = pData[0] & 0xffff; | |
579 | //The offset should be 0x***10 or 0x***00 | |
580 | if((Offset % 4) != 0) | |
581 | { | |
582 | eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff) | (data << 16); | |
583 | } | |
584 | else | |
585 | { | |
586 | eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff0000) | data; | |
587 | } | |
588 | ||
589 | efuseDataOffset = EFUSE_DATA3; | |
590 | for(i=0; i< 4; i++) | |
591 | { | |
592 | RTMP_IO_WRITE32(pAd, efuseDataOffset, eFuseDataBuffer[i]); | |
593 | efuseDataOffset -= 4; | |
594 | } | |
595 | ///////////////////////////////////////////////////////////////// | |
596 | ||
597 | //Step1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. | |
598 | eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; | |
599 | ||
600 | //Step2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. | |
601 | eFuseCtrlStruc.field.EFSROM_MODE = 3; | |
602 | ||
603 | //Step3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. | |
604 | eFuseCtrlStruc.field.EFSROM_KICK = 1; | |
605 | ||
606 | NdisMoveMemory(&data, &eFuseCtrlStruc, 4); | |
607 | RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); | |
608 | ||
609 | //Step4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It��s done. | |
610 | i = 0; | |
611 | while(i < 100) | |
612 | { | |
613 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
614 | ||
615 | if(eFuseCtrlStruc.field.EFSROM_KICK == 0) | |
616 | break; | |
617 | ||
618 | RTMPusecDelay(2); | |
619 | i++; | |
620 | } | |
621 | } | |
622 | ||
623 | /* | |
624 | ======================================================================== | |
625 | ||
626 | Routine Description: | |
627 | ||
628 | Arguments: | |
629 | ||
630 | Return Value: | |
631 | ||
632 | IRQL = | |
633 | ||
634 | Note: | |
635 | ||
636 | ======================================================================== | |
637 | */ | |
638 | NTSTATUS eFuseWriteRegisters( | |
639 | IN PRTMP_ADAPTER pAd, | |
640 | IN USHORT Offset, | |
641 | IN USHORT Length, | |
642 | IN USHORT* pData) | |
643 | { | |
644 | USHORT i; | |
645 | USHORT eFuseData; | |
646 | USHORT LogicalAddress, BlkNum = 0xffff; | |
647 | UCHAR EFSROM_AOUT; | |
648 | ||
649 | USHORT addr,tmpaddr, InBuf[3], tmpOffset; | |
650 | USHORT buffer[8]; | |
651 | BOOLEAN bWriteSuccess = TRUE; | |
652 | ||
653 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters Offset=%x, pData=%x\n", Offset, *pData)); | |
654 | ||
655 | //Step 0. find the entry in the mapping table | |
656 | //The address of EEPROM is 2-bytes alignment. | |
657 | //The last bit is used for alignment, so it must be 0. | |
658 | tmpOffset = Offset & 0xfffe; | |
659 | EFSROM_AOUT = eFuseReadRegisters(pAd, tmpOffset, 2, &eFuseData); | |
660 | ||
661 | if( EFSROM_AOUT == 0x3f) | |
662 | { //find available logical address pointer | |
663 | //the logical address does not exist, find an empty one | |
664 | //from the first address of block 45=16*45=0x2d0 to the last address of block 47 | |
665 | //==>48*16-3(reserved)=2FC | |
666 | for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) | |
667 | { | |
668 | //Retrive the logical block nubmer form each logical address pointer | |
669 | //It will access two logical address pointer each time. | |
670 | eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); | |
671 | if( (LogicalAddress & 0xff) == 0) | |
672 | {//Not used logical address pointer | |
673 | BlkNum = i-EFUSE_USAGE_MAP_START; | |
674 | break; | |
675 | } | |
676 | else if(( (LogicalAddress >> 8) & 0xff) == 0) | |
677 | {//Not used logical address pointer | |
678 | if (i != EFUSE_USAGE_MAP_END) | |
679 | { | |
680 | BlkNum = i-EFUSE_USAGE_MAP_START+1; | |
681 | } | |
682 | break; | |
683 | } | |
684 | } | |
685 | } | |
686 | else | |
687 | { | |
688 | BlkNum = EFSROM_AOUT; | |
689 | } | |
690 | ||
691 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); | |
692 | ||
693 | if(BlkNum == 0xffff) | |
694 | { | |
695 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); | |
696 | return FALSE; | |
697 | } | |
698 | ||
699 | //Step 1. Save data of this block which is pointed by the avaible logical address pointer | |
700 | // read and save the original block data | |
701 | for(i =0; i<8; i++) | |
702 | { | |
703 | addr = BlkNum * 0x10 ; | |
704 | ||
705 | InBuf[0] = addr+2*i; | |
706 | InBuf[1] = 2; | |
707 | InBuf[2] = 0x0; | |
708 | ||
709 | eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); | |
710 | ||
711 | buffer[i] = InBuf[2]; | |
712 | } | |
713 | ||
714 | //Step 2. Update the data in buffer, and write the data to Efuse | |
715 | buffer[ (Offset >> 1) % 8] = pData[0]; | |
716 | ||
717 | do | |
718 | { | |
719 | //Step 3. Write the data to Efuse | |
720 | if(!bWriteSuccess) | |
721 | { | |
722 | for(i =0; i<8; i++) | |
723 | { | |
724 | addr = BlkNum * 0x10 ; | |
725 | ||
726 | InBuf[0] = addr+2*i; | |
727 | InBuf[1] = 2; | |
728 | InBuf[2] = buffer[i]; | |
729 | ||
730 | eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); | |
731 | } | |
732 | } | |
733 | else | |
734 | { | |
735 | addr = BlkNum * 0x10 ; | |
736 | ||
737 | InBuf[0] = addr+(Offset % 16); | |
738 | InBuf[1] = 2; | |
739 | InBuf[2] = pData[0]; | |
740 | ||
741 | eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); | |
742 | } | |
743 | ||
744 | //Step 4. Write mapping table | |
745 | addr = EFUSE_USAGE_MAP_START+BlkNum; | |
746 | ||
747 | tmpaddr = addr; | |
748 | ||
749 | if(addr % 2 != 0) | |
750 | addr = addr -1; | |
751 | InBuf[0] = addr; | |
752 | InBuf[1] = 2; | |
753 | ||
754 | //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry | |
755 | tmpOffset = Offset; | |
756 | tmpOffset >>= 4; | |
757 | tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; | |
758 | tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; | |
759 | ||
760 | // write the logical address | |
761 | if(tmpaddr%2 != 0) | |
762 | InBuf[2] = tmpOffset<<8; | |
763 | else | |
764 | InBuf[2] = tmpOffset; | |
765 | ||
766 | eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); | |
767 | ||
768 | //Step 5. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted | |
769 | bWriteSuccess = TRUE; | |
770 | for(i =0; i<8; i++) | |
771 | { | |
772 | addr = BlkNum * 0x10 ; | |
773 | ||
774 | InBuf[0] = addr+2*i; | |
775 | InBuf[1] = 2; | |
776 | InBuf[2] = 0x0; | |
777 | ||
778 | eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); | |
779 | ||
780 | if(buffer[i] != InBuf[2]) | |
781 | { | |
782 | bWriteSuccess = FALSE; | |
783 | break; | |
784 | } | |
785 | } | |
786 | ||
787 | //Step 6. invlidate mapping entry and find a free mapping entry if not succeed | |
788 | if (!bWriteSuccess) | |
789 | { | |
790 | DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess BlkNum = %d\n", BlkNum)); | |
791 | ||
792 | // the offset of current mapping entry | |
793 | addr = EFUSE_USAGE_MAP_START+BlkNum; | |
794 | ||
795 | //find a new mapping entry | |
796 | BlkNum = 0xffff; | |
797 | for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) | |
798 | { | |
799 | eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); | |
800 | if( (LogicalAddress & 0xff) == 0) | |
801 | { | |
802 | BlkNum = i-EFUSE_USAGE_MAP_START; | |
803 | break; | |
804 | } | |
805 | else if(( (LogicalAddress >> 8) & 0xff) == 0) | |
806 | { | |
807 | if (i != EFUSE_USAGE_MAP_END) | |
808 | { | |
809 | BlkNum = i+1-EFUSE_USAGE_MAP_START; | |
810 | } | |
811 | break; | |
812 | } | |
813 | } | |
814 | DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess new BlkNum = %d\n", BlkNum)); | |
815 | if(BlkNum == 0xffff) | |
816 | { | |
817 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); | |
818 | return FALSE; | |
819 | } | |
820 | ||
821 | //invalidate the original mapping entry if new entry is not found | |
822 | tmpaddr = addr; | |
823 | ||
824 | if(addr % 2 != 0) | |
825 | addr = addr -1; | |
826 | InBuf[0] = addr; | |
827 | InBuf[1] = 2; | |
828 | ||
829 | eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); | |
830 | ||
831 | // write the logical address | |
832 | if(tmpaddr%2 != 0) | |
833 | { | |
834 | // Invalidate the high byte | |
835 | for (i=8; i<15; i++) | |
836 | { | |
837 | if( ( (InBuf[2] >> i) & 0x01) == 0) | |
838 | { | |
839 | InBuf[2] |= (0x1 <<i); | |
840 | break; | |
841 | } | |
842 | } | |
843 | } | |
844 | else | |
845 | { | |
846 | // invalidate the low byte | |
847 | for (i=0; i<8; i++) | |
848 | { | |
849 | if( ( (InBuf[2] >> i) & 0x01) == 0) | |
850 | { | |
851 | InBuf[2] |= (0x1 <<i); | |
852 | break; | |
853 | } | |
854 | } | |
855 | } | |
856 | eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 0); | |
857 | } | |
858 | } | |
859 | while(!bWriteSuccess); | |
860 | ||
861 | return TRUE; | |
862 | } | |
863 | ||
864 | /* | |
865 | ======================================================================== | |
866 | ||
867 | Routine Description: | |
868 | ||
869 | Arguments: | |
870 | ||
871 | Return Value: | |
872 | ||
873 | IRQL = | |
874 | ||
875 | Note: | |
876 | ||
877 | ======================================================================== | |
878 | */ | |
879 | VOID eFuseWritePhysical( | |
880 | IN PRTMP_ADAPTER pAd, | |
881 | PUSHORT lpInBuffer, | |
882 | ULONG nInBufferSize, | |
883 | PUCHAR lpOutBuffer, | |
884 | ULONG nOutBufferSize | |
885 | ) | |
886 | { | |
887 | USHORT* pInBuf = (USHORT*)lpInBuffer; | |
888 | int i; | |
889 | //USHORT* pOutBuf = (USHORT*)ioBuffer; | |
890 | ||
891 | USHORT Offset = pInBuf[0]; //addr | |
892 | USHORT Length = pInBuf[1]; //length | |
893 | USHORT* pValueX = &pInBuf[2]; //value ... | |
894 | // Little-endian S | S Big-endian | |
895 | // addr 3 2 1 0 | 0 1 2 3 | |
896 | // Ori-V D C B A | A B C D | |
897 | //After swapping | |
898 | // D C B A | D C B A | |
899 | //Both the little and big-endian use the same sequence to write data. | |
900 | //Therefore, we only need swap data when read the data. | |
901 | for(i=0; i<Length; i+=2) | |
902 | { | |
903 | eFusePhysicalWriteRegisters(pAd, Offset+i, 2, &pValueX[i/2]); | |
904 | } | |
905 | } | |
906 | ||
907 | ||
908 | /* | |
909 | ======================================================================== | |
910 | ||
911 | Routine Description: | |
912 | ||
913 | Arguments: | |
914 | ||
915 | Return Value: | |
916 | ||
917 | IRQL = | |
918 | ||
919 | Note: | |
920 | ||
921 | ======================================================================== | |
922 | */ | |
923 | NTSTATUS eFuseWrite( | |
924 | IN PRTMP_ADAPTER pAd, | |
925 | IN USHORT Offset, | |
926 | IN PUCHAR pData, | |
927 | IN USHORT length) | |
928 | { | |
929 | int i; | |
930 | ||
931 | USHORT* pValueX = (PUSHORT) pData; //value ... | |
932 | //The input value=3070 will be stored as following | |
933 | // Little-endian S | S Big-endian | |
934 | // addr 1 0 | 0 1 | |
935 | // Ori-V 30 70 | 30 70 | |
936 | //After swapping | |
937 | // 30 70 | 70 30 | |
938 | //Casting | |
939 | // 3070 | 7030 (x) | |
940 | //The swapping should be removed for big-endian | |
941 | for(i=0; i<length; i+=2) | |
942 | { | |
943 | eFuseWriteRegisters(pAd, Offset+i, 2, &pValueX[i/2]); | |
944 | } | |
945 | ||
946 | return TRUE; | |
947 | } | |
948 | ||
949 | /* | |
950 | ======================================================================== | |
951 | ||
952 | Routine Description: | |
953 | ||
954 | Arguments: | |
955 | ||
956 | Return Value: | |
957 | ||
958 | IRQL = | |
959 | ||
960 | Note: | |
961 | ||
962 | ======================================================================== | |
963 | */ | |
964 | INT set_eFuseGetFreeBlockCount_Proc( | |
965 | IN PRTMP_ADAPTER pAd, | |
966 | IN PUCHAR arg) | |
967 | { | |
968 | USHORT i; | |
969 | USHORT LogicalAddress; | |
970 | USHORT efusefreenum=0; | |
971 | if(!pAd->bUseEfuse) | |
972 | return FALSE; | |
973 | for (i = EFUSE_USAGE_MAP_START; i <= EFUSE_USAGE_MAP_END; i+=2) | |
974 | { | |
975 | eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); | |
976 | if( (LogicalAddress & 0xff) == 0) | |
977 | { | |
978 | efusefreenum= (UCHAR) (EFUSE_USAGE_MAP_END-i+1); | |
979 | break; | |
980 | } | |
981 | else if(( (LogicalAddress >> 8) & 0xff) == 0) | |
982 | { | |
983 | efusefreenum = (UCHAR) (EFUSE_USAGE_MAP_END-i); | |
984 | break; | |
985 | } | |
986 | ||
987 | if(i == EFUSE_USAGE_MAP_END) | |
988 | efusefreenum = 0; | |
989 | } | |
990 | printk("efuseFreeNumber is %d\n",efusefreenum); | |
991 | return TRUE; | |
992 | } | |
993 | INT set_eFusedump_Proc( | |
994 | IN PRTMP_ADAPTER pAd, | |
995 | IN PUCHAR arg) | |
996 | { | |
997 | USHORT InBuf[3]; | |
998 | INT i=0; | |
999 | if(!pAd->bUseEfuse) | |
1000 | return FALSE; | |
1001 | for(i =0; i<EFUSE_USAGE_MAP_END/2; i++) | |
1002 | { | |
1003 | InBuf[0] = 2*i; | |
1004 | InBuf[1] = 2; | |
1005 | InBuf[2] = 0x0; | |
1006 | ||
1007 | eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); | |
1008 | if(i%4==0) | |
1009 | printk("\nBlock %x:",i/8); | |
1010 | printk("%04x ",InBuf[2]); | |
1011 | } | |
1012 | return TRUE; | |
1013 | } | |
1014 | INT set_eFuseLoadFromBin_Proc( | |
1015 | IN PRTMP_ADAPTER pAd, | |
1016 | IN PUCHAR arg) | |
1017 | { | |
1018 | CHAR *src; | |
1019 | struct file *srcf; | |
0b2e3aef | 1020 | INT retval; |
59fe2d89 BZ |
1021 | mm_segment_t orgfs; |
1022 | UCHAR *buffer; | |
1023 | UCHAR BinFileSize=0; | |
1024 | INT i = 0,j=0,k=1; | |
1025 | USHORT *PDATA; | |
1026 | USHORT DATA; | |
1027 | BinFileSize=strlen("RT30xxEEPROM.bin"); | |
1028 | src = kmalloc(128, MEM_ALLOC_FLAG); | |
1029 | NdisZeroMemory(src, 128); | |
1030 | ||
1031 | if(strlen(arg)>0) | |
1032 | { | |
1033 | ||
1034 | NdisMoveMemory(src, arg, strlen(arg)); | |
1035 | } | |
1036 | ||
1037 | else | |
1038 | { | |
1039 | ||
1040 | NdisMoveMemory(src, "RT30xxEEPROM.bin", BinFileSize); | |
1041 | } | |
1042 | ||
1043 | DBGPRINT(RT_DEBUG_TRACE, ("FileName=%s\n",src)); | |
1044 | buffer = kmalloc(MAX_EEPROM_BIN_FILE_SIZE, MEM_ALLOC_FLAG); | |
1045 | ||
1046 | if(buffer == NULL) | |
1047 | { | |
1048 | kfree(src); | |
1049 | return FALSE; | |
1050 | } | |
1051 | PDATA=kmalloc(sizeof(USHORT)*8,MEM_ALLOC_FLAG); | |
1052 | ||
1053 | if(PDATA==NULL) | |
1054 | { | |
1055 | kfree(src); | |
1056 | ||
1057 | kfree(buffer); | |
1058 | return FALSE; | |
1059 | } | |
0b2e3aef | 1060 | |
59fe2d89 BZ |
1061 | orgfs = get_fs(); |
1062 | set_fs(KERNEL_DS); | |
1063 | ||
1064 | if (src && *src) | |
1065 | { | |
1066 | srcf = filp_open(src, O_RDONLY, 0); | |
1067 | if (IS_ERR(srcf)) | |
1068 | { | |
1069 | DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); | |
1070 | return FALSE; | |
1071 | } | |
1072 | else | |
1073 | { | |
1074 | // The object must have a read method | |
1075 | if (srcf->f_op && srcf->f_op->read) | |
1076 | { | |
1077 | memset(buffer, 0x00, MAX_EEPROM_BIN_FILE_SIZE); | |
1078 | while(srcf->f_op->read(srcf, &buffer[i], 1, &srcf->f_pos)==1) | |
1079 | { | |
1080 | DBGPRINT(RT_DEBUG_TRACE, ("%02X ",buffer[i])); | |
1081 | if((i+1)%8==0) | |
1082 | DBGPRINT(RT_DEBUG_TRACE, ("\n")); | |
1083 | i++; | |
1084 | if(i>=MAX_EEPROM_BIN_FILE_SIZE) | |
1085 | { | |
1086 | DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld reading %s, The file is too large[1024]\n", -PTR_ERR(srcf),src)); | |
1087 | kfree(PDATA); | |
1088 | kfree(buffer); | |
1089 | kfree(src); | |
1090 | return FALSE; | |
1091 | } | |
1092 | } | |
1093 | } | |
1094 | else | |
1095 | { | |
1096 | DBGPRINT(RT_DEBUG_ERROR, ("--> Error!! System doest not support read function\n")); | |
1097 | kfree(PDATA); | |
1098 | kfree(buffer); | |
1099 | kfree(src); | |
1100 | return FALSE; | |
1101 | } | |
1102 | } | |
1103 | ||
1104 | ||
1105 | } | |
1106 | else | |
1107 | { | |
1108 | DBGPRINT(RT_DEBUG_ERROR, ("--> Error src or srcf is null\n")); | |
1109 | kfree(PDATA); | |
1110 | kfree(buffer); | |
1111 | return FALSE; | |
1112 | ||
1113 | } | |
1114 | ||
1115 | ||
1116 | retval=filp_close(srcf,NULL); | |
1117 | ||
1118 | if (retval) | |
1119 | { | |
1120 | DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); | |
1121 | } | |
1122 | set_fs(orgfs); | |
0b2e3aef | 1123 | |
59fe2d89 BZ |
1124 | for(j=0;j<i;j++) |
1125 | { | |
1126 | DBGPRINT(RT_DEBUG_TRACE, ("%02X ",buffer[j])); | |
1127 | if((j+1)%2==0) | |
1128 | PDATA[j/2%8]=((buffer[j]<<8)&0xff00)|(buffer[j-1]&0xff); | |
1129 | if(j%16==0) | |
1130 | { | |
1131 | k=buffer[j]; | |
1132 | } | |
1133 | else | |
1134 | { | |
1135 | k&=buffer[j]; | |
1136 | if((j+1)%16==0) | |
1137 | { | |
1138 | ||
1139 | DBGPRINT(RT_DEBUG_TRACE, (" result=%02X,blk=%02x\n",k,j/16)); | |
1140 | ||
1141 | if(k!=0xff) | |
1142 | eFuseWriteRegistersFromBin(pAd,(USHORT)j-15, 16, PDATA); | |
1143 | else | |
1144 | { | |
1145 | if(eFuseReadRegisters(pAd,j, 2,(PUSHORT)&DATA)!=0x3f) | |
1146 | eFuseWriteRegistersFromBin(pAd,(USHORT)j-15, 16, PDATA); | |
1147 | } | |
1148 | /* | |
1149 | for(l=0;l<8;l++) | |
1150 | printk("%04x ",PDATA[l]); | |
1151 | printk("\n"); | |
1152 | */ | |
1153 | NdisZeroMemory(PDATA,16); | |
1154 | ||
1155 | ||
1156 | } | |
1157 | } | |
1158 | ||
1159 | ||
1160 | } | |
1161 | ||
1162 | ||
1163 | kfree(PDATA); | |
1164 | kfree(buffer); | |
1165 | kfree(src); | |
1166 | return TRUE; | |
1167 | } | |
1168 | NTSTATUS eFuseWriteRegistersFromBin( | |
1169 | IN PRTMP_ADAPTER pAd, | |
1170 | IN USHORT Offset, | |
1171 | IN USHORT Length, | |
1172 | IN USHORT* pData) | |
1173 | { | |
1174 | USHORT i; | |
1175 | USHORT eFuseData; | |
1176 | USHORT LogicalAddress, BlkNum = 0xffff; | |
1177 | UCHAR EFSROM_AOUT,Loop=0; | |
1178 | EFUSE_CTRL_STRUC eFuseCtrlStruc; | |
1179 | USHORT efuseDataOffset; | |
1180 | UINT32 data,tempbuffer; | |
1181 | USHORT addr,tmpaddr, InBuf[3], tmpOffset; | |
1182 | UINT32 buffer[4]; | |
1183 | BOOLEAN bWriteSuccess = TRUE; | |
1184 | BOOLEAN bNotWrite=TRUE; | |
1185 | BOOLEAN bAllocateNewBlk=TRUE; | |
1186 | ||
1187 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin Offset=%x, pData=%04x:%04x:%04x:%04x\n", Offset, *pData,*(pData+1),*(pData+2),*(pData+3))); | |
1188 | ||
1189 | do | |
1190 | { | |
1191 | //Step 0. find the entry in the mapping table | |
1192 | //The address of EEPROM is 2-bytes alignment. | |
1193 | //The last bit is used for alignment, so it must be 0. | |
1194 | Loop++; | |
1195 | tmpOffset = Offset & 0xfffe; | |
1196 | EFSROM_AOUT = eFuseReadRegisters(pAd, tmpOffset, 2, &eFuseData); | |
1197 | ||
1198 | if( EFSROM_AOUT == 0x3f) | |
1199 | { //find available logical address pointer | |
1200 | //the logical address does not exist, find an empty one | |
1201 | //from the first address of block 45=16*45=0x2d0 to the last address of block 47 | |
1202 | //==>48*16-3(reserved)=2FC | |
1203 | bAllocateNewBlk=TRUE; | |
1204 | for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) | |
1205 | { | |
1206 | //Retrive the logical block nubmer form each logical address pointer | |
1207 | //It will access two logical address pointer each time. | |
1208 | eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); | |
1209 | if( (LogicalAddress & 0xff) == 0) | |
1210 | {//Not used logical address pointer | |
1211 | BlkNum = i-EFUSE_USAGE_MAP_START; | |
1212 | break; | |
1213 | } | |
1214 | else if(( (LogicalAddress >> 8) & 0xff) == 0) | |
1215 | {//Not used logical address pointer | |
1216 | if (i != EFUSE_USAGE_MAP_END) | |
1217 | { | |
1218 | BlkNum = i-EFUSE_USAGE_MAP_START+1; | |
1219 | } | |
1220 | break; | |
1221 | } | |
1222 | } | |
1223 | } | |
1224 | else | |
1225 | { | |
1226 | bAllocateNewBlk=FALSE; | |
1227 | BlkNum = EFSROM_AOUT; | |
1228 | } | |
1229 | ||
1230 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); | |
1231 | ||
1232 | if(BlkNum == 0xffff) | |
1233 | { | |
1234 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); | |
1235 | return FALSE; | |
1236 | } | |
1237 | //Step 1.1.0 | |
1238 | //If the block is not existing in mapping table, create one | |
1239 | //and write down the 16-bytes data to the new block | |
1240 | if(bAllocateNewBlk) | |
1241 | { | |
1242 | DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk\n")); | |
1243 | efuseDataOffset = EFUSE_DATA3; | |
1244 | for(i=0; i< 4; i++) | |
1245 | { | |
1246 | DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk, Data%d=%04x%04x\n",3-i,pData[2*i+1],pData[2*i])); | |
1247 | tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; | |
1248 | ||
1249 | ||
1250 | RTMP_IO_WRITE32(pAd, efuseDataOffset,tempbuffer); | |
1251 | efuseDataOffset -= 4; | |
1252 | ||
1253 | } | |
1254 | ///////////////////////////////////////////////////////////////// | |
1255 | ||
1256 | //Step1.1.1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. | |
1257 | eFuseCtrlStruc.field.EFSROM_AIN = BlkNum* 0x10 ; | |
1258 | ||
1259 | //Step1.1.2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. | |
1260 | eFuseCtrlStruc.field.EFSROM_MODE = 3; | |
1261 | ||
1262 | //Step1.1.3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. | |
1263 | eFuseCtrlStruc.field.EFSROM_KICK = 1; | |
1264 | ||
1265 | NdisMoveMemory(&data, &eFuseCtrlStruc, 4); | |
1266 | ||
1267 | RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); | |
1268 | ||
1269 | //Step1.1.4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It��s done. | |
1270 | i = 0; | |
1271 | while(i < 100) | |
1272 | { | |
1273 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
1274 | ||
1275 | if(eFuseCtrlStruc.field.EFSROM_KICK == 0) | |
1276 | break; | |
1277 | ||
1278 | RTMPusecDelay(2); | |
1279 | i++; | |
1280 | } | |
1281 | ||
1282 | } | |
1283 | else | |
1284 | { //Step1.2. | |
1285 | //If the same logical number is existing, check if the writting data and the data | |
1286 | //saving in this block are the same. | |
1287 | ///////////////////////////////////////////////////////////////// | |
1288 | //read current values of 16-byte block | |
1289 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
1290 | ||
1291 | //Step1.2.0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. | |
1292 | eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; | |
1293 | ||
1294 | //Step1.2.1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. | |
1295 | eFuseCtrlStruc.field.EFSROM_MODE = 0; | |
1296 | ||
1297 | //Step1.2.2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. | |
1298 | eFuseCtrlStruc.field.EFSROM_KICK = 1; | |
1299 | ||
1300 | NdisMoveMemory(&data, &eFuseCtrlStruc, 4); | |
1301 | RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); | |
1302 | ||
1303 | //Step1.2.3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. | |
1304 | i = 0; | |
1305 | while(i < 100) | |
1306 | { | |
1307 | RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); | |
1308 | ||
1309 | if(eFuseCtrlStruc.field.EFSROM_KICK == 0) | |
1310 | break; | |
1311 | RTMPusecDelay(2); | |
1312 | i++; | |
1313 | } | |
1314 | ||
1315 | //Step1.2.4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) | |
1316 | efuseDataOffset = EFUSE_DATA3; | |
1317 | for(i=0; i< 4; i++) | |
1318 | { | |
1319 | RTMP_IO_READ32(pAd, efuseDataOffset, (PUINT32) &buffer[i]); | |
1320 | efuseDataOffset -= 4; | |
1321 | } | |
1322 | //Step1.2.5. Check if the data of efuse and the writing data are the same. | |
1323 | for(i =0; i<4; i++) | |
1324 | { | |
1325 | tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; | |
1326 | DBGPRINT(RT_DEBUG_TRACE, ("buffer[%d]=%x,pData[%d]=%x,pData[%d]=%x,tempbuffer=%x\n",i,buffer[i],2*i,pData[2*i],2*i+1,pData[2*i+1],tempbuffer)); | |
1327 | ||
1328 | if(((buffer[i]&0xffff0000)==(pData[2*i+1]<<16))&&((buffer[i]&0xffff)==pData[2*i])) | |
1329 | bNotWrite&=TRUE; | |
1330 | else | |
1331 | { | |
1332 | bNotWrite&=FALSE; | |
1333 | break; | |
1334 | } | |
1335 | } | |
1336 | if(!bNotWrite) | |
1337 | { | |
1338 | printk("The data is not the same\n"); | |
1339 | ||
1340 | for(i =0; i<8; i++) | |
1341 | { | |
1342 | addr = BlkNum * 0x10 ; | |
1343 | ||
1344 | InBuf[0] = addr+2*i; | |
1345 | InBuf[1] = 2; | |
1346 | InBuf[2] = pData[i]; | |
1347 | ||
1348 | eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); | |
1349 | } | |
1350 | ||
1351 | } | |
1352 | else | |
1353 | return TRUE; | |
1354 | } | |
1355 | ||
1356 | ||
1357 | ||
1358 | //Step 2. Write mapping table | |
1359 | addr = EFUSE_USAGE_MAP_START+BlkNum; | |
1360 | ||
1361 | tmpaddr = addr; | |
1362 | ||
1363 | if(addr % 2 != 0) | |
1364 | addr = addr -1; | |
1365 | InBuf[0] = addr; | |
1366 | InBuf[1] = 2; | |
1367 | ||
1368 | //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry | |
1369 | tmpOffset = Offset; | |
1370 | tmpOffset >>= 4; | |
1371 | tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; | |
1372 | tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; | |
1373 | ||
1374 | // write the logical address | |
1375 | if(tmpaddr%2 != 0) | |
1376 | InBuf[2] = tmpOffset<<8; | |
1377 | else | |
1378 | InBuf[2] = tmpOffset; | |
1379 | ||
1380 | eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); | |
1381 | ||
1382 | //Step 3. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted | |
1383 | bWriteSuccess = TRUE; | |
1384 | for(i =0; i<8; i++) | |
1385 | { | |
1386 | addr = BlkNum * 0x10 ; | |
1387 | ||
1388 | InBuf[0] = addr+2*i; | |
1389 | InBuf[1] = 2; | |
1390 | InBuf[2] = 0x0; | |
1391 | ||
1392 | eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); | |
1393 | DBGPRINT(RT_DEBUG_TRACE, ("addr=%x, buffer[i]=%x,InBuf[2]=%x\n",InBuf[0],pData[i],InBuf[2])); | |
1394 | if(pData[i] != InBuf[2]) | |
1395 | { | |
1396 | bWriteSuccess = FALSE; | |
1397 | break; | |
1398 | } | |
1399 | } | |
1400 | ||
1401 | //Step 4. invlidate mapping entry and find a free mapping entry if not succeed | |
1402 | ||
1403 | if (!bWriteSuccess&&Loop<2) | |
1404 | { | |
1405 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess BlkNum = %d\n", BlkNum)); | |
1406 | ||
1407 | // the offset of current mapping entry | |
1408 | addr = EFUSE_USAGE_MAP_START+BlkNum; | |
1409 | ||
1410 | //find a new mapping entry | |
1411 | BlkNum = 0xffff; | |
1412 | for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) | |
1413 | { | |
1414 | eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); | |
1415 | if( (LogicalAddress & 0xff) == 0) | |
1416 | { | |
1417 | BlkNum = i-EFUSE_USAGE_MAP_START; | |
1418 | break; | |
1419 | } | |
1420 | else if(( (LogicalAddress >> 8) & 0xff) == 0) | |
1421 | { | |
1422 | if (i != EFUSE_USAGE_MAP_END) | |
1423 | { | |
1424 | BlkNum = i+1-EFUSE_USAGE_MAP_START; | |
1425 | } | |
1426 | break; | |
1427 | } | |
1428 | } | |
1429 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess new BlkNum = %d\n", BlkNum)); | |
1430 | if(BlkNum == 0xffff) | |
1431 | { | |
1432 | DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin: out of free E-fuse space!!!\n")); | |
1433 | return FALSE; | |
1434 | } | |
1435 | ||
1436 | //invalidate the original mapping entry if new entry is not found | |
1437 | tmpaddr = addr; | |
1438 | ||
1439 | if(addr % 2 != 0) | |
1440 | addr = addr -1; | |
1441 | InBuf[0] = addr; | |
1442 | InBuf[1] = 2; | |
1443 | ||
1444 | eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); | |
1445 | ||
1446 | // write the logical address | |
1447 | if(tmpaddr%2 != 0) | |
1448 | { | |
1449 | // Invalidate the high byte | |
1450 | for (i=8; i<15; i++) | |
1451 | { | |
1452 | if( ( (InBuf[2] >> i) & 0x01) == 0) | |
1453 | { | |
1454 | InBuf[2] |= (0x1 <<i); | |
1455 | break; | |
1456 | } | |
1457 | } | |
1458 | } | |
1459 | else | |
1460 | { | |
1461 | // invalidate the low byte | |
1462 | for (i=0; i<8; i++) | |
1463 | { | |
1464 | if( ( (InBuf[2] >> i) & 0x01) == 0) | |
1465 | { | |
1466 | InBuf[2] |= (0x1 <<i); | |
1467 | break; | |
1468 | } | |
1469 | } | |
1470 | } | |
1471 | eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 0); | |
1472 | } | |
1473 | ||
1474 | } | |
1475 | while(!bWriteSuccess&&Loop<2); | |
1476 | ||
1477 | return TRUE; | |
91980990 | 1478 | } |
5cc86f28 | 1479 | #endif |