convert brcm-2.4 to the new target structure
[openwrt/staging/yousong.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / bcmsrom.c
1 /*
2 * Misc useful routines to access NIC SROM/OTP .
3 *
4 * Copyright 2006, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 * $Id: bcmsrom.c,v 1.1.1.14 2006/04/15 01:28:25 michael Exp $
12 */
13
14 #include <typedefs.h>
15 #include <bcmdefs.h>
16 #include <osl.h>
17 #include <bcmutils.h>
18 #include <bcmsrom.h>
19 #include <bcmdevs.h>
20 #include <bcmendian.h>
21 #include <sbpcmcia.h>
22 #include <pcicfg.h>
23 #include <sbutils.h>
24 #include <bcmnvram.h>
25
26 /* debug/trace */
27 #if defined(WLTEST)
28 #define BS_ERROR(args) printf args
29 #else
30 #define BS_ERROR(args)
31 #endif /* BCMDBG_ERR || WLTEST */
32
33 #define VARS_MAX 4096 /* should be reduced */
34
35 #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
36 #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
37
38 static int initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count);
39 static int initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count);
40 static int initvars_flash_sb(void *sbh, char **vars, uint *count);
41 static int srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count);
42 static int sprom_cmd_pcmcia(osl_t *osh, uint8 cmd);
43 static int sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data);
44 static int sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data);
45 static int sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords,
46 bool check_crc);
47
48 static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count);
49 static int initvars_flash(osl_t *osh, char **vp, uint len, char *devpath);
50
51 /*
52 * Initialize local vars from the right source for this platform.
53 * Return 0 on success, nonzero on error.
54 */
55 int
56 srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, uint *count)
57 {
58 ASSERT(bustype == BUSTYPE(bustype));
59 if (vars == NULL || count == NULL)
60 return (0);
61
62 switch (BUSTYPE(bustype)) {
63 case SB_BUS:
64 case JTAG_BUS:
65 return initvars_flash_sb(sbh, vars, count);
66
67 case PCI_BUS:
68 ASSERT(curmap); /* can not be NULL */
69 return initvars_srom_pci(sbh, curmap, vars, count);
70
71 case PCMCIA_BUS:
72 return initvars_cis_pcmcia(sbh, osh, vars, count);
73
74
75 default:
76 ASSERT(0);
77 }
78 return (-1);
79 }
80
81 /* support only 16-bit word read from srom */
82 int
83 srom_read(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
84 {
85 void *srom;
86 uint i, off, nw;
87
88 ASSERT(bustype == BUSTYPE(bustype));
89
90 /* check input - 16-bit access only */
91 if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
92 return 1;
93
94 off = byteoff / 2;
95 nw = nbytes / 2;
96
97 if (BUSTYPE(bustype) == PCI_BUS) {
98 if (!curmap)
99 return 1;
100 srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET;
101 if (sprom_read_pci(osh, srom, off, buf, nw, FALSE))
102 return 1;
103 } else if (BUSTYPE(bustype) == PCMCIA_BUS) {
104 for (i = 0; i < nw; i++) {
105 if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
106 return 1;
107 }
108 } else {
109 return 1;
110 }
111
112 return 0;
113 }
114
115 /* support only 16-bit word write into srom */
116 int
117 srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
118 {
119 uint16 *srom;
120 uint i, nw, crc_range;
121 uint16 image[SPROM_SIZE];
122 uint8 crc;
123 volatile uint32 val32;
124
125 ASSERT(bustype == BUSTYPE(bustype));
126
127 /* check input - 16-bit access only */
128 if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
129 return 1;
130
131 /* Are we writing the whole thing at once? */
132 if ((byteoff == 0) &&
133 ((nbytes == SPROM_SIZE) ||
134 (nbytes == (SPROM_CRC_RANGE * 2)) ||
135 (nbytes == (SROM4_WORDS * 2)))) {
136 crc_range = nbytes;
137 bcopy((void*)buf, (void*)image, nbytes);
138 nw = nbytes / 2;
139 } else {
140 if ((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS))
141 crc_range = SPROM_SIZE;
142 else
143 crc_range = SPROM_CRC_RANGE * 2; /* Tentative */
144
145 nw = crc_range / 2;
146 /* read first 64 words from srom */
147 if (srom_read(bustype, curmap, osh, 0, crc_range, image))
148 return 1;
149 if (image[SROM4_SIGN] == SROM4_SIGNATURE) {
150 crc_range = SROM4_WORDS;
151 nw = crc_range / 2;
152 if (srom_read(bustype, curmap, osh, 0, crc_range, image))
153 return 1;
154 }
155 /* make changes */
156 bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
157 }
158
159 /* calculate crc */
160 htol16_buf(image, crc_range);
161 crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
162 ltoh16_buf(image, crc_range);
163 image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
164
165 if (BUSTYPE(bustype) == PCI_BUS) {
166 srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET);
167 /* enable writes to the SPROM */
168 val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
169 val32 |= SPROM_WRITEEN;
170 OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
171 bcm_mdelay(WRITE_ENABLE_DELAY);
172 /* write srom */
173 for (i = 0; i < nw; i++) {
174 W_REG(osh, &srom[i], image[i]);
175 bcm_mdelay(WRITE_WORD_DELAY);
176 }
177 /* disable writes to the SPROM */
178 OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 &
179 ~SPROM_WRITEEN);
180 } else if (BUSTYPE(bustype) == PCMCIA_BUS) {
181 /* enable writes to the SPROM */
182 if (sprom_cmd_pcmcia(osh, SROM_WEN))
183 return 1;
184 bcm_mdelay(WRITE_ENABLE_DELAY);
185 /* write srom */
186 for (i = 0; i < nw; i++) {
187 sprom_write_pcmcia(osh, (uint16)(i), image[i]);
188 bcm_mdelay(WRITE_WORD_DELAY);
189 }
190 /* disable writes to the SPROM */
191 if (sprom_cmd_pcmcia(osh, SROM_WDS))
192 return 1;
193 } else {
194 return 1;
195 }
196
197 bcm_mdelay(WRITE_ENABLE_DELAY);
198 return 0;
199 }
200
201
202 static int
203 srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count)
204 {
205 char eabuf[32];
206 char *vp, *base;
207 uint8 *cis, tup, tlen, sromrev = 1;
208 int i, j;
209 uint varsize;
210 bool ag_init = FALSE;
211 uint32 w32;
212
213 ASSERT(vars);
214 ASSERT(count);
215
216 base = vp = MALLOC(osh, VARS_MAX);
217 ASSERT(vp);
218 if (!vp)
219 return -2;
220
221 while (ciscnt--) {
222 cis = *pcis++;
223 i = 0;
224 do {
225 tup = cis[i++];
226 tlen = cis[i++];
227 if ((i + tlen) >= CIS_SIZE)
228 break;
229
230 switch (tup) {
231 case CISTPL_MANFID:
232 vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
233 vp++;
234 vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
235 vp++;
236 break;
237
238 case CISTPL_FUNCE:
239 switch (cis[i]) {
240 case LAN_NID:
241 ASSERT(cis[i + 1] == 6);
242 bcm_ether_ntoa((struct ether_addr *)&cis[i + 2], eabuf);
243 vp += sprintf(vp, "il0macaddr=%s", eabuf);
244 vp++;
245 break;
246 case 1: /* SDIO Extended Data */
247 vp += sprintf(vp, "sdmaxblk=%d",
248 (cis[i + 13] << 8) | cis[i + 12]);
249 vp++;
250 break;
251 }
252 break;
253
254 case CISTPL_CFTABLE:
255 vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
256 vp++;
257 break;
258
259 case CISTPL_BRCM_HNBU:
260 switch (cis[i]) {
261 case HNBU_SROMREV:
262 sromrev = cis[i + 1];
263 break;
264
265 case HNBU_CHIPID:
266 vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) +
267 cis[i + 1]);
268 vp++;
269 vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) +
270 cis[i + 3]);
271 vp++;
272 if (tlen == 7) {
273 vp += sprintf(vp, "chiprev=%d",
274 (cis[i + 6] << 8) + cis[i + 5]);
275 vp++;
276 }
277 break;
278
279 case HNBU_BOARDREV:
280 vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
281 vp++;
282 break;
283
284 case HNBU_AA:
285 vp += sprintf(vp, "aa2g=%d", cis[i + 1]);
286 vp++;
287 break;
288
289 case HNBU_AG:
290 vp += sprintf(vp, "ag0=%d", cis[i + 1]);
291 vp++;
292 ag_init = TRUE;
293 break;
294
295 case HNBU_CC:
296 ASSERT(sromrev == 1);
297 vp += sprintf(vp, "cc=%d", cis[i + 1]);
298 vp++;
299 break;
300
301 case HNBU_PAPARMS:
302 if (tlen == 2) {
303 ASSERT(sromrev == 1);
304 vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 1]);
305 vp++;
306 } else if (tlen >= 9) {
307 if (tlen == 10) {
308 ASSERT(sromrev == 2);
309 vp += sprintf(vp, "opo=%d", cis[i + 9]);
310 vp++;
311 } else
312 ASSERT(tlen == 9);
313
314 for (j = 0; j < 3; j++) {
315 vp += sprintf(vp, "pa0b%d=%d", j,
316 (cis[i + (j * 2) + 2] << 8) +
317 cis[i + (j * 2) + 1]);
318 vp++;
319 }
320 vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
321 vp++;
322 vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 8]);
323 vp++;
324 } else
325 ASSERT(tlen >= 9);
326 break;
327
328 case HNBU_OEM:
329 ASSERT(sromrev == 1);
330 vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
331 cis[i + 1], cis[i + 2],
332 cis[i + 3], cis[i + 4],
333 cis[i + 5], cis[i + 6],
334 cis[i + 7], cis[i + 8]);
335 vp++;
336 break;
337
338 case HNBU_BOARDFLAGS:
339 w32 = (cis[i + 2] << 8) + cis[i + 1];
340 if (tlen == 5)
341 w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16);
342 vp += sprintf(vp, "boardflags=0x%x", w32);
343 vp++;
344 break;
345
346 case HNBU_LEDS:
347 if (cis[i + 1] != 0xff) {
348 vp += sprintf(vp, "ledbh0=%d", cis[i + 1]);
349 vp++;
350 }
351 if (cis[i + 2] != 0xff) {
352 vp += sprintf(vp, "ledbh1=%d", cis[i + 2]);
353 vp++;
354 }
355 if (cis[i + 3] != 0xff) {
356 vp += sprintf(vp, "ledbh2=%d", cis[i + 3]);
357 vp++;
358 }
359 if (cis[i + 4] != 0xff) {
360 vp += sprintf(vp, "ledbh3=%d", cis[i + 4]);
361 vp++;
362 }
363 break;
364
365 case HNBU_CCODE:
366 {
367 char str[3];
368 ASSERT(sromrev > 1);
369 str[0] = cis[i + 1];
370 str[1] = cis[i + 2];
371 str[2] = 0;
372 vp += sprintf(vp, "ccode=%s", str);
373 vp++;
374 vp += sprintf(vp, "cctl=0x%x", cis[i + 3]);
375 vp++;
376 break;
377 }
378
379 case HNBU_CCKPO:
380 ASSERT(sromrev > 2);
381 vp += sprintf(vp, "cckpo=0x%x",
382 (cis[i + 2] << 8) | cis[i + 1]);
383 vp++;
384 break;
385
386 case HNBU_OFDMPO:
387 ASSERT(sromrev > 2);
388 vp += sprintf(vp, "ofdmpo=0x%x",
389 (cis[i + 4] << 24) |
390 (cis[i + 3] << 16) |
391 (cis[i + 2] << 8) |
392 cis[i + 1]);
393 vp++;
394 break;
395 }
396 break;
397
398 }
399 i += tlen;
400 } while (tup != 0xff);
401 }
402
403 /* Set the srom version */
404 vp += sprintf(vp, "sromrev=%d", sromrev);
405 vp++;
406
407 /* if there is no antenna gain field, set default */
408 if (ag_init == FALSE) {
409 ASSERT(sromrev == 1);
410 vp += sprintf(vp, "ag0=%d", 0xff);
411 vp++;
412 }
413
414 /* final nullbyte terminator */
415 *vp++ = '\0';
416 varsize = (uint)(vp - base);
417
418 ASSERT((vp - base) < VARS_MAX);
419
420 if (varsize == VARS_MAX) {
421 *vars = base;
422 } else {
423 vp = MALLOC(osh, varsize);
424 ASSERT(vp);
425 if (vp)
426 bcopy(base, vp, varsize);
427 MFREE(osh, base, VARS_MAX);
428 *vars = vp;
429 if (!vp) {
430 *count = 0;
431 return -2;
432 }
433 }
434 *count = varsize;
435
436 return (0);
437 }
438
439
440 /* set PCMCIA sprom command register */
441 static int
442 sprom_cmd_pcmcia(osl_t *osh, uint8 cmd)
443 {
444 uint8 status = 0;
445 uint wait_cnt = 1000;
446
447 /* write sprom command register */
448 OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
449
450 /* wait status */
451 while (wait_cnt--) {
452 OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
453 if (status & SROM_DONE)
454 return 0;
455 }
456
457 return 1;
458 }
459
460 /* read a word from the PCMCIA srom */
461 static int
462 sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data)
463 {
464 uint8 addr_l, addr_h, data_l, data_h;
465
466 addr_l = (uint8)((addr * 2) & 0xff);
467 addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
468
469 /* set address */
470 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
471 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
472
473 /* do read */
474 if (sprom_cmd_pcmcia(osh, SROM_READ))
475 return 1;
476
477 /* read data */
478 data_h = data_l = 0;
479 OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
480 OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
481
482 *data = (data_h << 8) | data_l;
483 return 0;
484 }
485
486 /* write a word to the PCMCIA srom */
487 static int
488 sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data)
489 {
490 uint8 addr_l, addr_h, data_l, data_h;
491
492 addr_l = (uint8)((addr * 2) & 0xff);
493 addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
494 data_l = (uint8)(data & 0xff);
495 data_h = (uint8)((data >> 8) & 0xff);
496
497 /* set address */
498 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
499 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
500
501 /* write data */
502 OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
503 OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
504
505 /* do write */
506 return sprom_cmd_pcmcia(osh, SROM_WRITE);
507 }
508
509 /*
510 * Read in and validate sprom.
511 * Return 0 on success, nonzero on error.
512 */
513 static int
514 sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc)
515 {
516 int err = 0;
517 uint i;
518
519 /* read the sprom */
520 for (i = 0; i < nwords; i++)
521 buf[i] = R_REG(osh, &sprom[wordoff + i]);
522
523 if (check_crc) {
524 /* fixup the endianness so crc8 will pass */
525 htol16_buf(buf, nwords * 2);
526 if (hndcrc8((uint8*)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE)
527 err = 1;
528 /* now correct the endianness of the byte array */
529 ltoh16_buf(buf, nwords * 2);
530 }
531
532 return err;
533 }
534
535 /*
536 * Create variable table from memory.
537 * Return 0 on success, nonzero on error.
538 */
539 static int
540 initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count)
541 {
542 int c = (int)(end - start);
543
544 /* do it only when there is more than just the null string */
545 if (c > 1) {
546 char *vp = MALLOC(osh, c);
547 ASSERT(vp);
548 if (!vp)
549 return BCME_NOMEM;
550 bcopy(start, vp, c);
551 *vars = vp;
552 *count = c;
553 }
554 else {
555 *vars = NULL;
556 *count = 0;
557 }
558
559 return 0;
560 }
561
562 /*
563 * Find variables with <devpath> from flash. 'base' points to the beginning
564 * of the table upon enter and to the end of the table upon exit when success.
565 * Return 0 on success, nonzero on error.
566 */
567 static int
568 initvars_flash(osl_t *osh, char **base, uint len, char *devpath)
569 {
570 char *vp = *base;
571 char *flash;
572 int err;
573 char *s;
574 uint l, dl, copy_len;
575
576 /* allocate memory and read in flash */
577 if (!(flash = MALLOC(osh, NVRAM_SPACE)))
578 return BCME_NOMEM;
579 if ((err = nvram_getall(flash, NVRAM_SPACE)))
580 goto exit;
581
582 /* grab vars with the <devpath> prefix in name */
583 dl = strlen(devpath);
584 for (s = flash; s && *s; s += l + 1) {
585 l = strlen(s);
586
587 /* skip non-matching variable */
588 if (strncmp(s, devpath, dl))
589 continue;
590
591 /* is there enough room to copy? */
592 copy_len = l - dl + 1;
593 if (len < copy_len) {
594 err = BCME_BUFTOOSHORT;
595 goto exit;
596 }
597
598 /* no prefix, just the name=value */
599 strcpy(vp, &s[dl]);
600 vp += copy_len;
601 len -= copy_len;
602 }
603
604 /* add null string as terminator */
605 if (len < 1) {
606 err = BCME_BUFTOOSHORT;
607 goto exit;
608 }
609 *vp++ = '\0';
610
611 *base = vp;
612
613 exit: MFREE(osh, flash, NVRAM_SPACE);
614 return err;
615 }
616
617 /*
618 * Initialize nonvolatile variable table from flash.
619 * Return 0 on success, nonzero on error.
620 */
621 static int
622 initvars_flash_sb(void *sbh, char **vars, uint *count)
623 {
624 osl_t *osh = sb_osh(sbh);
625 char devpath[SB_DEVPATH_BUFSZ];
626 char *vp, *base;
627 int err;
628
629 ASSERT(vars);
630 ASSERT(count);
631
632 if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
633 return err;
634
635 base = vp = MALLOC(osh, VARS_MAX);
636 ASSERT(vp);
637 if (!vp)
638 return BCME_NOMEM;
639
640 if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
641 goto err;
642
643 err = initvars_table(osh, base, vp, vars, count);
644
645 err: MFREE(osh, base, VARS_MAX);
646 return err;
647 }
648
649 #ifdef WLTEST
650 char mfgsromvars[256];
651 char *defaultsromvars = "il0macaddr=00:11:22:33:44:51\0"
652 "et0macaddr=00:11:22:33:44:52\0"
653 "et1macaddr=00:11:22:33:44:53\0"
654 "boardtype=0xffff\0"
655 "boardrev=0x10\0"
656 "boardflags=8\0"
657 "sromrev=2\0"
658 "aa2g=3";
659 #define MFGSROM_DEFVARSLEN 147 /* default srom len */
660 #endif /* WL_TEST */
661
662 /*
663 * Initialize nonvolatile variable table from sprom.
664 * Return 0 on success, nonzero on error.
665 */
666 static int
667 initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count)
668 {
669 uint16 w, *b;
670 uint8 sromrev = 0;
671 struct ether_addr ea;
672 char eabuf[32];
673 uint32 w32;
674 int woff, i;
675 char *vp, *base;
676 osl_t *osh = sb_osh(sbh);
677 bool flash = FALSE;
678 char name[SB_DEVPATH_BUFSZ+16], *value;
679 char devpath[SB_DEVPATH_BUFSZ];
680 int err;
681
682 /*
683 * Apply CRC over SROM content regardless SROM is present or not,
684 * and use variable <devpath>sromrev's existance in flash to decide
685 * if we should return an error when CRC fails or read SROM variables
686 * from flash.
687 */
688 b = MALLOC(osh, SROM_MAX);
689 ASSERT(b);
690 if (!b)
691 return -2;
692
693 err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b,
694 64, TRUE);
695 if (b[SROM4_SIGN] == SROM4_SIGNATURE) {
696 /* sromrev >= 4, read more */
697 err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, SROM4_WORDS, TRUE);
698 sromrev = b[SROM4_WORDS - 1] & 0xff;
699 } else if (err == 0) {
700 /* srom is good and is rev < 4 */
701 /* top word of sprom contains version and crc8 */
702 sromrev = b[63] & 0xff;
703 /* bcm4401 sroms misprogrammed */
704 if (sromrev == 0x10)
705 sromrev = 1;
706 }
707
708 if (err) {
709 #ifdef WLTEST
710 BS_ERROR(("SROM Crc Error, so see if we could use a default\n"));
711 w32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
712 if (w32 & SPROM_OTPIN_USE) {
713 BS_ERROR(("srom crc failed with OTP, use default vars....\n"));
714 vp = base = mfgsromvars;
715 if (sb_chip(sbh) == BCM4311_CHIP_ID) {
716 BS_ERROR(("setting the devid to be 4311\n"));
717 vp += sprintf(vp, "devid=0x4311");
718 vp++;
719 }
720 bcopy(defaultsromvars, vp, MFGSROM_DEFVARSLEN);
721 vp += MFGSROM_DEFVARSLEN;
722 goto varsdone;
723 } else {
724 BS_ERROR(("srom crc failed with SPROM....\n"));
725 #endif /* WLTEST */
726 if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
727 return err;
728 sprintf(name, "%ssromrev", devpath);
729 if (!(value = getvar(NULL, name)))
730 return (-1);
731 sromrev = (uint8)bcm_strtoul(value, NULL, 0);
732 flash = TRUE;
733 #ifdef WLTEST
734 }
735 #endif /* WLTEST */
736 }
737
738 /* srom version check */
739 if (sromrev > 4)
740 return (-2);
741
742 ASSERT(vars);
743 ASSERT(count);
744
745 base = vp = MALLOC(osh, VARS_MAX);
746 ASSERT(vp);
747 if (!vp)
748 return -2;
749
750 /* read variables from flash */
751 if (flash) {
752 if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
753 goto err;
754 goto varsdone;
755 }
756
757 vp += sprintf(vp, "sromrev=%d", sromrev);
758 vp++;
759
760 if (sromrev >= 4) {
761 uint path, pathbase;
762 const uint pathbases[MAX_PATH] = {SROM4_PATH0, SROM4_PATH1,
763 SROM4_PATH2, SROM4_PATH3};
764
765 vp += sprintf(vp, "boardrev=%d", b[SROM4_BREV]);
766 vp++;
767
768 vp += sprintf(vp, "boardflags=%d", (b[SROM4_BFL1] << 16) | b[SROM4_BFL0]);
769 vp++;
770
771 vp += sprintf(vp, "boardflags2=%d", (b[SROM4_BFL3] << 16) | b[SROM4_BFL2]);
772 vp++;
773
774 /* The macaddr */
775 ea.octet[0] = (b[SROM4_MACHI] >> 8) & 0xff;
776 ea.octet[1] = b[SROM4_MACHI] & 0xff;
777 ea.octet[2] = (b[SROM4_MACMID] >> 8) & 0xff;
778 ea.octet[3] = b[SROM4_MACMID] & 0xff;
779 ea.octet[4] = (b[SROM4_MACLO] >> 8) & 0xff;
780 ea.octet[5] = b[SROM4_MACLO] & 0xff;
781 bcm_ether_ntoa(&ea, eabuf);
782 vp += sprintf(vp, "macaddr=%s", eabuf);
783 vp++;
784
785 w = b[SROM4_CCODE];
786 if (w == 0)
787 vp += sprintf(vp, "ccode=");
788 else
789 vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
790 vp++;
791 vp += sprintf(vp, "regrev=%d", b[SROM4_REGREV]);
792 vp++;
793
794 w = b[SROM4_LEDBH10];
795 if ((w != 0) && (w != 0xffff)) {
796 /* ledbh0 */
797 vp += sprintf(vp, "ledbh0=%d", (w & 0xff));
798 vp++;
799
800 /* ledbh1 */
801 vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff);
802 vp++;
803 }
804 w = b[SROM4_LEDBH32];
805 if ((w != 0) && (w != 0xffff)) {
806 /* ledbh2 */
807 vp += sprintf(vp, "ledbh2=%d", w & 0xff);
808 vp++;
809
810 /* ledbh3 */
811 vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff);
812 vp++;
813 }
814 /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */
815 if (w != 0xffff) {
816 w = b[SROM4_LEDDC];
817 w32 = ((uint32)((unsigned char)(w >> 8) & 0xff) << 24) | /* oncount */
818 ((uint32)((unsigned char)(w & 0xff)) << 8); /* offcount */
819 vp += sprintf(vp, "leddc=%d", w32);
820 vp++;
821 }
822
823 w = b[SROM4_AA];
824 vp += sprintf(vp, "aa2g=%d", w & SROM4_AA2G_MASK);
825 vp++;
826 vp += sprintf(vp, "aa5g=%d", w >> SROM4_AA5G_SHIFT);
827 vp++;
828
829 w = b[SROM4_AG10];
830 vp += sprintf(vp, "ag0=%d", w & 0xff);
831 vp++;
832 vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
833 vp++;
834 w = b[SROM4_AG32];
835 vp += sprintf(vp, "ag2=%d", w & 0xff);
836 vp++;
837 vp += sprintf(vp, "ag3=%d", (w >> 8) & 0xff);
838 vp++;
839
840 /* Fixed power indices when power control is disabled */
841 for (i = 0; i < 2; i++) {
842 w = b[SROM4_TXPID2G + i];
843 vp += sprintf(vp, "txpid2ga%d=%d", 2 * i, w & 0xff);
844 vp++;
845 vp += sprintf(vp, "txpid2ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
846 vp++;
847 w = b[SROM4_TXPID5G + i];
848 vp += sprintf(vp, "txpid5ga%d=%d", 2 * i, w & 0xff);
849 vp++;
850 vp += sprintf(vp, "txpid5ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
851 vp++;
852 w = b[SROM4_TXPID5GL + i];
853 vp += sprintf(vp, "txpid5gla%d=%d", 2 * i, w & 0xff);
854 vp++;
855 vp += sprintf(vp, "txpid5gla%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
856 vp++;
857 w = b[SROM4_TXPID5GH + i];
858 vp += sprintf(vp, "txpid5gha%d=%d", 2 * i, w & 0xff);
859 vp++;
860 vp += sprintf(vp, "txpid5gha%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
861 vp++;
862 }
863
864 /* Per path variables */
865 for (path = 0; path < MAX_PATH; path++) {
866 pathbase = pathbases[path];
867 w = b[pathbase + SROM4_2G_ITT_MAXP];
868 vp += sprintf(vp, "itt2ga%d=%d", path, w >> B2G_ITT_SHIFT);
869 vp++;
870 vp += sprintf(vp, "maxp2ga%d=%d", path, w & B2G_MAXP_MASK);
871 vp++;
872
873 for (i = 0; i < 4; i++) {
874 vp += sprintf(vp, "pa2gw%da%d=%d", i, path,
875 b[pathbase + SROM4_2G_PA + i]);
876 vp++;
877 }
878
879 w = b[pathbase + SROM4_5G_ITT_MAXP];
880 vp += sprintf(vp, "itt5ga%d=%d", path, w >> B5G_ITT_SHIFT);
881 vp++;
882 vp += sprintf(vp, "maxp5ga%d=%d", path, w & B5G_MAXP_MASK);
883 vp++;
884
885 w = b[pathbase + SROM4_5GLH_MAXP];
886 vp += sprintf(vp, "maxp5lga%d=%d", path, w >> B5GL_MAXP_SHIFT);
887 vp++;
888 vp += sprintf(vp, "maxp5gha%d=%d", path, w & B5GH_MAXP_MASK);
889 vp++;
890
891 for (i = 0; i < 4; i++) {
892 vp += sprintf(vp, "pa5gw%da%d=%d", i, path,
893 b[pathbase + SROM4_5G_PA + i]);
894 vp++;
895 vp += sprintf(vp, "pa5glw%da%d=%d", i, path,
896 b[pathbase + SROM4_5GL_PA + i]);
897 vp++;
898 vp += sprintf(vp, "pa5hgw%da%d=%d", i, path,
899 b[pathbase + SROM4_5GH_PA + i]);
900 vp++;
901 }
902 }
903
904 vp += sprintf(vp, "cck2gpo=%d", b[SROM4_2G_CCKPO]);
905 vp++;
906
907 w32 = ((uint32)b[SROM4_2G_OFDMPO + 1] << 16) | b[SROM4_2G_OFDMPO];
908 vp += sprintf(vp, "ofdm2gpo=%d", w32);
909 vp++;
910
911 w32 = ((uint32)b[SROM4_5G_OFDMPO + 1] << 16) | b[SROM4_5G_OFDMPO];
912 vp += sprintf(vp, "ofdm5gpo=%d", w32);
913 vp++;
914
915 w32 = ((uint32)b[SROM4_5GL_OFDMPO + 1] << 16) | b[SROM4_5GL_OFDMPO];
916 vp += sprintf(vp, "ofdm5glpo=%d", w32);
917 vp++;
918
919 w32 = ((uint32)b[SROM4_5GH_OFDMPO + 1] << 16) | b[SROM4_5GH_OFDMPO];
920 vp += sprintf(vp, "ofdm5ghpo=%d", w32);
921 vp++;
922
923 for (i = 0; i < 8; i++) {
924 vp += sprintf(vp, "mcs2gpo%d=%d", i, b[SROM4_2G_MCSPO]);
925 vp++;
926 vp += sprintf(vp, "mcs5gpo%d=%d", i, b[SROM4_5G_MCSPO]);
927 vp++;
928 vp += sprintf(vp, "mcs5glpo%d=%d", i, b[SROM4_5GL_MCSPO]);
929 vp++;
930 vp += sprintf(vp, "mcs5ghpo%d=%d", i, b[SROM4_5GH_MCSPO]);
931 vp++;
932 }
933
934 vp += sprintf(vp, "ccdpo%d=%d", i, b[SROM4_CCDPO]);
935 vp++;
936 vp += sprintf(vp, "stbcpo%d=%d", i, b[SROM4_STBCPO]);
937 vp++;
938 vp += sprintf(vp, "bw40po%d=%d", i, b[SROM4_BW40PO]);
939 vp++;
940 vp += sprintf(vp, "bwduppo%d=%d", i, b[SROM4_BWDUPPO]);
941 vp++;
942
943 goto done;
944 }
945 if (sromrev >= 3) {
946 /* New section takes over the 3th hardware function space */
947
948 /* Words 22+23 are 11a (mid) ofdm power offsets */
949 w32 = ((uint32)b[23] << 16) | b[22];
950 vp += sprintf(vp, "ofdmapo=%d", w32);
951 vp++;
952
953 /* Words 24+25 are 11a (low) ofdm power offsets */
954 w32 = ((uint32)b[25] << 16) | b[24];
955 vp += sprintf(vp, "ofdmalpo=%d", w32);
956 vp++;
957
958 /* Words 26+27 are 11a (high) ofdm power offsets */
959 w32 = ((uint32)b[27] << 16) | b[26];
960 vp += sprintf(vp, "ofdmahpo=%d", w32);
961 vp++;
962
963 /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */
964 w32 = ((uint32)((unsigned char)(b[21] >> 8) & 0xff) << 24) | /* oncount */
965 ((uint32)((unsigned char)(b[21] & 0xff)) << 8); /* offcount */
966 vp += sprintf(vp, "leddc=%d", w32);
967
968 vp++;
969 }
970
971 if (sromrev >= 2) {
972 /* New section takes over the 4th hardware function space */
973
974 /* Word 29 is max power 11a high/low */
975 w = b[29];
976 vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
977 vp++;
978 vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
979 vp++;
980
981 /* Words 30-32 set the 11alow pa settings,
982 * 33-35 are the 11ahigh ones.
983 */
984 for (i = 0; i < 3; i++) {
985 vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
986 vp++;
987 vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
988 vp++;
989 }
990 w = b[59];
991 if (w == 0)
992 vp += sprintf(vp, "ccode=");
993 else
994 vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
995 vp++;
996
997 }
998
999 /* parameter section of sprom starts at byte offset 72 */
1000 woff = 72/2;
1001
1002 /* first 6 bytes are il0macaddr */
1003 ea.octet[0] = (b[woff] >> 8) & 0xff;
1004 ea.octet[1] = b[woff] & 0xff;
1005 ea.octet[2] = (b[woff+1] >> 8) & 0xff;
1006 ea.octet[3] = b[woff+1] & 0xff;
1007 ea.octet[4] = (b[woff+2] >> 8) & 0xff;
1008 ea.octet[5] = b[woff+2] & 0xff;
1009 woff += 3;
1010 bcm_ether_ntoa(&ea, eabuf);
1011 vp += sprintf(vp, "il0macaddr=%s", eabuf);
1012 vp++;
1013
1014 /* next 6 bytes are et0macaddr */
1015 ea.octet[0] = (b[woff] >> 8) & 0xff;
1016 ea.octet[1] = b[woff] & 0xff;
1017 ea.octet[2] = (b[woff+1] >> 8) & 0xff;
1018 ea.octet[3] = b[woff+1] & 0xff;
1019 ea.octet[4] = (b[woff+2] >> 8) & 0xff;
1020 ea.octet[5] = b[woff+2] & 0xff;
1021 woff += 3;
1022 bcm_ether_ntoa(&ea, eabuf);
1023 vp += sprintf(vp, "et0macaddr=%s", eabuf);
1024 vp++;
1025
1026 /* next 6 bytes are et1macaddr */
1027 ea.octet[0] = (b[woff] >> 8) & 0xff;
1028 ea.octet[1] = b[woff] & 0xff;
1029 ea.octet[2] = (b[woff+1] >> 8) & 0xff;
1030 ea.octet[3] = b[woff+1] & 0xff;
1031 ea.octet[4] = (b[woff+2] >> 8) & 0xff;
1032 ea.octet[5] = b[woff+2] & 0xff;
1033 woff += 3;
1034 bcm_ether_ntoa(&ea, eabuf);
1035 vp += sprintf(vp, "et1macaddr=%s", eabuf);
1036 vp++;
1037
1038 /*
1039 * Enet phy settings one or two singles or a dual
1040 * Bits 4-0 : MII address for enet0 (0x1f for not there)
1041 * Bits 9-5 : MII address for enet1 (0x1f for not there)
1042 * Bit 14 : Mdio for enet0
1043 * Bit 15 : Mdio for enet1
1044 */
1045 w = b[woff];
1046 vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
1047 vp++;
1048 vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
1049 vp++;
1050 vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
1051 vp++;
1052 vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
1053 vp++;
1054
1055 /* Word 46 has board rev, antennas 0/1 & Country code/control */
1056 w = b[46];
1057 vp += sprintf(vp, "boardrev=%d", w & 0xff);
1058 vp++;
1059
1060 if (sromrev > 1)
1061 vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
1062 else
1063 vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
1064 vp++;
1065
1066 vp += sprintf(vp, "aa2g=%d", (w >> 12) & 0x3);
1067 vp++;
1068
1069 vp += sprintf(vp, "aa5g=%d", (w >> 14) & 0x3);
1070 vp++;
1071
1072 /* Words 47-49 set the (wl) pa settings */
1073 woff = 47;
1074
1075 for (i = 0; i < 3; i++) {
1076 vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
1077 vp++;
1078 vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
1079 vp++;
1080 }
1081
1082 /*
1083 * Words 50-51 set the customer-configured wl led behavior.
1084 * 8 bits/gpio pin. High bit: activehi=0, activelo=1;
1085 * LED behavior values defined in wlioctl.h .
1086 */
1087 w = b[50];
1088 if ((w != 0) && (w != 0xffff)) {
1089 /* ledbh0 */
1090 vp += sprintf(vp, "ledbh0=%d", (w & 0xff));
1091 vp++;
1092
1093 /* ledbh1 */
1094 vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff);
1095 vp++;
1096 }
1097 w = b[51];
1098 if ((w != 0) && (w != 0xffff)) {
1099 /* ledbh2 */
1100 vp += sprintf(vp, "ledbh2=%d", w & 0xff);
1101 vp++;
1102
1103 /* ledbh */
1104 vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff);
1105 vp++;
1106 }
1107
1108 /* Word 52 is max power 0/1 */
1109 w = b[52];
1110 vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
1111 vp++;
1112 vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
1113 vp++;
1114
1115 /* Word 56 is idle tssi target 0/1 */
1116 w = b[56];
1117 vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
1118 vp++;
1119 vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
1120 vp++;
1121
1122 /* Word 57 is boardflags, if not programmed make it zero */
1123 w32 = (uint32)b[57];
1124 if (w32 == 0xffff) w32 = 0;
1125 if (sromrev > 1) {
1126 /* Word 28 is the high bits of boardflags */
1127 w32 |= (uint32)b[28] << 16;
1128 }
1129 vp += sprintf(vp, "boardflags=%d", w32);
1130 vp++;
1131
1132 /* Word 58 is antenna gain 0/1 */
1133 w = b[58];
1134 vp += sprintf(vp, "ag0=%d", w & 0xff);
1135 vp++;
1136
1137 vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
1138 vp++;
1139
1140 if (sromrev == 1) {
1141 /* set the oem string */
1142 vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
1143 ((b[59] >> 8) & 0xff), (b[59] & 0xff),
1144 ((b[60] >> 8) & 0xff), (b[60] & 0xff),
1145 ((b[61] >> 8) & 0xff), (b[61] & 0xff),
1146 ((b[62] >> 8) & 0xff), (b[62] & 0xff));
1147 vp++;
1148 } else if (sromrev == 2) {
1149 /* Word 60 OFDM tx power offset from CCK level */
1150 /* OFDM Power Offset - opo */
1151 vp += sprintf(vp, "opo=%d", b[60] & 0xff);
1152 vp++;
1153 } else {
1154 /* Word 60: cck power offsets */
1155 vp += sprintf(vp, "cckpo=%d", b[60]);
1156 vp++;
1157
1158 /* Words 61+62: 11g ofdm power offsets */
1159 w32 = ((uint32)b[62] << 16) | b[61];
1160 vp += sprintf(vp, "ofdmgpo=%d", w32);
1161 vp++;
1162 }
1163
1164 /* final nullbyte terminator */
1165 done: *vp++ = '\0';
1166
1167 ASSERT((vp - base) <= VARS_MAX);
1168
1169 varsdone:
1170 err = initvars_table(osh, base, vp, vars, count);
1171
1172 err:
1173 #ifdef WLTEST
1174 if (base != mfgsromvars)
1175 #endif
1176 MFREE(osh, base, VARS_MAX);
1177 MFREE(osh, b, SROM_MAX);
1178 return err;
1179 }
1180
1181 /*
1182 * Read the cis and call parsecis to initialize the vars.
1183 * Return 0 on success, nonzero on error.
1184 */
1185 static int
1186 initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count)
1187 {
1188 uint8 *cis = NULL;
1189 int rc;
1190 uint data_sz;
1191
1192 data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
1193
1194 if ((cis = MALLOC(osh, data_sz)) == NULL)
1195 return (-2);
1196
1197 if (sb_pcmciarev(sbh) == 1) {
1198 if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) {
1199 MFREE(osh, cis, data_sz);
1200 return (-1);
1201 }
1202 /* fix up endianess for 16-bit data vs 8-bit parsing */
1203 ltoh16_buf((uint16 *)cis, data_sz);
1204 } else
1205 OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
1206
1207 rc = srom_parsecis(osh, &cis, 1, vars, count);
1208
1209 MFREE(osh, cis, data_sz);
1210
1211 return (rc);
1212 }
1213