d5737d72fcb9d5d12bf21bc184634fe259f72f82
[openwrt/svn-archive/archive.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / bcmsrom.c
1 /*
2 * Routines to access SPROM and to parse SROM/CIS variables.
3 *
4 * Copyright 2007, 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$
12 */
13
14 #include <typedefs.h>
15 #include <bcmdefs.h>
16 #include <osl.h>
17 #include <stdarg.h>
18 #include <sbchipc.h>
19 #include <bcmdevs.h>
20 #include <bcmendian.h>
21 #include <sbpcmcia.h>
22 #include <pcicfg.h>
23 #include <sbconfig.h>
24 #include <sbutils.h>
25 #include <bcmsrom.h>
26 #include <bcmnvram.h>
27 #include "utils.h"
28
29 /* debug/trace */
30 #if defined(WLTEST)
31 #define BS_ERROR(args) printf args
32 #else
33 #define BS_ERROR(args)
34 #endif
35
36 #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
37 #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
38
39 typedef struct varbuf
40 {
41 char *buf; /* pointer to current position */
42 unsigned int size; /* current (residual) size in bytes */
43 } varbuf_t;
44
45 static int initvars_srom_sb (sb_t * sbh, osl_t * osh, void *curmap,
46 char **vars, uint * count);
47 static void _initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off,
48 varbuf_t * b);
49 static int initvars_srom_pci (sb_t * sbh, void *curmap, char **vars,
50 uint * count);
51 static int initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars,
52 uint * count);
53 #if !defined(BCMUSBDEV) && !defined(BCMSDIODEV)
54 static int initvars_flash_sb (sb_t * sbh, char **vars, uint * count);
55 #endif /* !BCMUSBDEV && !BCMSDIODEV */
56 static int sprom_cmd_pcmcia (osl_t * osh, uint8 cmd);
57 static int sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data);
58 static int sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data);
59 static int sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff,
60 uint16 * buf, uint nwords, bool check_crc);
61
62 static int initvars_table (osl_t * osh, char *start, char *end, char **vars,
63 uint * count);
64 static int initvars_flash (sb_t * sbh, osl_t * osh, char **vp, uint len);
65
66 #ifdef BCMUSBDEV
67 static int get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
68 uint boff, uint16 * srom, uint bsz);
69 static int set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
70 uint boff, uint16 * srom, uint bsz);
71 static uint srom_size (sb_t * sbh, osl_t * osh);
72 #endif /* def BCMUSBDEV */
73
74 /* Initialization of varbuf structure */
75 static void
76 varbuf_init (varbuf_t * b, char *buf, uint size)
77 {
78 b->size = size;
79 b->buf = buf;
80 }
81
82 /* append a null terminated var=value string */
83 static int
84 varbuf_append (varbuf_t * b, const char *fmt, ...)
85 {
86 va_list ap;
87 int r;
88
89 if (b->size < 2)
90 return 0;
91
92 va_start (ap, fmt);
93 r = vsnprintf (b->buf, b->size, fmt, ap);
94 va_end (ap);
95
96 /* C99 snprintf behavior returns r >= size on overflow,
97 * others return -1 on overflow.
98 * All return -1 on format error.
99 * We need to leave room for 2 null terminations, one for the current var
100 * string, and one for final null of the var table. So check that the
101 * strlen written, r, leaves room for 2 chars.
102 */
103 if ((r == -1) || (r > (int) (b->size - 2)))
104 {
105 b->size = 0;
106 return 0;
107 }
108
109 /* skip over this string's null termination */
110 r++;
111 b->size -= r;
112 b->buf += r;
113
114 return r;
115 }
116
117 /*
118 * Initialize local vars from the right source for this platform.
119 * Return 0 on success, nonzero on error.
120 */
121 int
122 BCMINITFN (srom_var_init) (sb_t * sbh, uint bustype, void *curmap,
123 osl_t * osh, char **vars, uint * count)
124 {
125 ASSERT (bustype == BUSTYPE (bustype));
126 if (vars == NULL || count == NULL)
127 return (0);
128
129 *vars = NULL;
130 *count = 0;
131
132 switch (BUSTYPE (bustype))
133 {
134 case SB_BUS:
135 case JTAG_BUS:
136 return initvars_srom_sb (sbh, osh, curmap, vars, count);
137
138 case PCI_BUS:
139 ASSERT (curmap); /* can not be NULL */
140 return initvars_srom_pci (sbh, curmap, vars, count);
141
142 case PCMCIA_BUS:
143 return initvars_cis_pcmcia (sbh, osh, vars, count);
144
145
146 default:
147 ASSERT (0);
148 }
149 return (-1);
150 }
151
152 /* support only 16-bit word read from srom */
153 int
154 srom_read (sb_t * sbh, uint bustype, void *curmap, osl_t * osh,
155 uint byteoff, uint nbytes, uint16 * buf)
156 {
157 void *srom;
158 uint i, off, nw;
159
160 ASSERT (bustype == BUSTYPE (bustype));
161
162 /* check input - 16-bit access only */
163 if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
164 return 1;
165
166 off = byteoff / 2;
167 nw = nbytes / 2;
168
169 if (BUSTYPE (bustype) == PCI_BUS)
170 {
171 if (!curmap)
172 return 1;
173 srom = (uchar *) curmap + PCI_BAR0_SPROM_OFFSET;
174 if (sprom_read_pci (osh, srom, off, buf, nw, FALSE))
175 return 1;
176 }
177 else if (BUSTYPE (bustype) == PCMCIA_BUS)
178 {
179 for (i = 0; i < nw; i++)
180 {
181 if (sprom_read_pcmcia
182 (osh, (uint16) (off + i), (uint16 *) (buf + i)))
183 return 1;
184 }
185 }
186 else if (BUSTYPE (bustype) == SB_BUS)
187 {
188 #ifdef BCMUSBDEV
189 if (SPROMBUS == PCMCIA_BUS)
190 {
191 uint origidx;
192 void *regs;
193 int rc;
194 bool wasup;
195
196 origidx = sb_coreidx (sbh);
197 regs = sb_setcore (sbh, SB_PCMCIA, 0);
198 ASSERT (regs != NULL);
199
200 if (!(wasup = sb_iscoreup (sbh)))
201 sb_core_reset (sbh, 0, 0);
202
203 rc = get_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes);
204
205 if (!wasup)
206 sb_core_disable (sbh, 0);
207
208 sb_setcoreidx (sbh, origidx);
209 return rc;
210 }
211 #endif /* def BCMUSBDEV */
212
213 return 1;
214 }
215 else
216 {
217 return 1;
218 }
219
220 return 0;
221 }
222
223 /* support only 16-bit word write into srom */
224 int
225 srom_write (sb_t * sbh, uint bustype, void *curmap, osl_t * osh,
226 uint byteoff, uint nbytes, uint16 * buf)
227 {
228 uint16 *srom;
229 uint i, nw, crc_range;
230 uint16 image[SPROM_SIZE];
231 uint8 crc;
232 volatile uint32 val32;
233
234 ASSERT (bustype == BUSTYPE (bustype));
235
236 /* check input - 16-bit access only */
237 if ((byteoff & 1) || (nbytes & 1))
238 return 1;
239
240 if (byteoff == 0x55aa)
241 {
242 /* Erase request */
243 crc_range = 0;
244 memset ((void *) image, 0xff, nbytes);
245 nw = nbytes / 2;
246 }
247 else if ((byteoff == 0) &&
248 ((nbytes == SPROM_SIZE * 2) ||
249 (nbytes == (SPROM_CRC_RANGE * 2)) ||
250 (nbytes == (SROM4_WORDS * 2))))
251 {
252 /* Are we writing the whole thing at once? */
253 crc_range = nbytes;
254 bcopy ((void *) buf, (void *) image, nbytes);
255 nw = nbytes / 2;
256 }
257 else
258 {
259 if ((byteoff + nbytes) > (SPROM_SIZE * 2))
260 return 1;
261
262 if (BUSTYPE (bustype) == PCMCIA_BUS)
263 {
264 crc_range = SPROM_SIZE * 2;
265 }
266 else
267 {
268 crc_range = SPROM_CRC_RANGE * 2; /* Tentative */
269 }
270
271 nw = crc_range / 2;
272 /* read first 64 words from srom */
273 if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image))
274 return 1;
275 if (image[SROM4_SIGN] == SROM4_SIGNATURE)
276 {
277 nw = SROM4_WORDS;
278 crc_range = nw * 2;
279 if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image))
280 return 1;
281 }
282 /* make changes */
283 bcopy ((void *) buf, (void *) &image[byteoff / 2], nbytes);
284 }
285
286 if (crc_range)
287 {
288 /* calculate crc */
289 htol16_buf (image, crc_range);
290 crc = ~hndcrc8 ((uint8 *) image, crc_range - 1, 0xff);
291 ltoh16_buf (image, crc_range);
292 image[nw - 1] = (crc << 8) | (image[nw - 1] & 0xff);
293 }
294
295 if (BUSTYPE (bustype) == PCI_BUS)
296 {
297 srom = (uint16 *) ((uchar *) curmap + PCI_BAR0_SPROM_OFFSET);
298 /* enable writes to the SPROM */
299 val32 = OSL_PCI_READ_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32));
300 val32 |= SPROM_WRITEEN;
301 OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32);
302 bcm_mdelay (WRITE_ENABLE_DELAY);
303 /* write srom */
304 for (i = 0; i < nw; i++)
305 {
306 W_REG (osh, &srom[i], image[i]);
307 bcm_mdelay (WRITE_WORD_DELAY);
308 }
309 /* disable writes to the SPROM */
310 OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32 &
311 ~SPROM_WRITEEN);
312 }
313 else if (BUSTYPE (bustype) == PCMCIA_BUS)
314 {
315 /* enable writes to the SPROM */
316 if (sprom_cmd_pcmcia (osh, SROM_WEN))
317 return 1;
318 bcm_mdelay (WRITE_ENABLE_DELAY);
319 /* write srom */
320 for (i = 0; i < nw; i++)
321 {
322 sprom_write_pcmcia (osh, (uint16) (i), image[i]);
323 bcm_mdelay (WRITE_WORD_DELAY);
324 }
325 /* disable writes to the SPROM */
326 if (sprom_cmd_pcmcia (osh, SROM_WDS))
327 return 1;
328 }
329 else if (BUSTYPE (bustype) == SB_BUS)
330 {
331 #ifdef BCMUSBDEV
332 if (SPROMBUS == PCMCIA_BUS)
333 {
334 uint origidx;
335 void *regs;
336 int rc;
337 bool wasup;
338
339 origidx = sb_coreidx (sbh);
340 regs = sb_setcore (sbh, SB_PCMCIA, 0);
341 ASSERT (regs != NULL);
342
343 if (!(wasup = sb_iscoreup (sbh)))
344 sb_core_reset (sbh, 0, 0);
345
346 rc = set_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes);
347
348 if (!wasup)
349 sb_core_disable (sbh, 0);
350
351 sb_setcoreidx (sbh, origidx);
352 return rc;
353 }
354 #endif /* def BCMUSBDEV */
355 return 1;
356 }
357 else
358 {
359 return 1;
360 }
361
362 bcm_mdelay (WRITE_ENABLE_DELAY);
363 return 0;
364 }
365
366 #ifdef BCMUSBDEV
367 #define SB_PCMCIA_READ(osh, regs, fcr) \
368 R_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2)
369 #define SB_PCMCIA_WRITE(osh, regs, fcr, v) \
370 W_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2, v)
371
372 /* set PCMCIA srom command register */
373 static int
374 srom_cmd_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint8 cmd)
375 {
376 uint8 status = 0;
377 uint wait_cnt = 0;
378
379 /* write srom command register */
380 SB_PCMCIA_WRITE (osh, pcmregs, SROM_CS, cmd);
381
382 /* wait status */
383 while (++wait_cnt < 1000000)
384 {
385 status = SB_PCMCIA_READ (osh, pcmregs, SROM_CS);
386 if (status & SROM_DONE)
387 return 0;
388 OSL_DELAY (1);
389 }
390
391 BS_ERROR (("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt,
392 status));
393 return 1;
394 }
395
396 /* read a word from the PCMCIA srom over SB */
397 static int
398 srom_read_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 * data)
399 {
400 uint8 addr_l, addr_h, data_l, data_h;
401
402 addr_l = (uint8) ((addr * 2) & 0xff);
403 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
404
405 /* set address */
406 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h);
407 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l);
408
409 /* do read */
410 if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_READ))
411 return 1;
412
413 /* read data */
414 data_h = SB_PCMCIA_READ (osh, pcmregs, SROM_DATAH);
415 data_l = SB_PCMCIA_READ (osh, pcmregs, SROM_DATAL);
416 *data = ((uint16) data_h << 8) | data_l;
417
418 return 0;
419 }
420
421 /* write a word to the PCMCIA srom over SB */
422 static int
423 srom_write_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 data)
424 {
425 uint8 addr_l, addr_h, data_l, data_h;
426 int rc;
427
428 addr_l = (uint8) ((addr * 2) & 0xff);
429 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
430
431 /* set address */
432 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h);
433 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l);
434
435 data_l = (uint8) (data & 0xff);
436 data_h = (uint8) ((data >> 8) & 0xff);
437
438 /* write data */
439 SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAH, data_h);
440 SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAL, data_l);
441
442 /* do write */
443 rc = srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WRITE);
444 OSL_DELAY (20000);
445 return rc;
446 }
447
448 /*
449 * Read the srom for the pcmcia-srom over sb case.
450 * Return 0 on success, nonzero on error.
451 */
452 static int
453 get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
454 uint boff, uint16 * srom, uint bsz)
455 {
456 uint i, nw, woff, wsz;
457 int err = 0;
458
459 /* read must be at word boundary */
460 ASSERT ((boff & 1) == 0 && (bsz & 1) == 0);
461
462 /* read sprom size and validate the parms */
463 if ((nw = srom_size (sbh, osh)) == 0)
464 {
465 BS_ERROR (("get_sb_pcmcia_srom: sprom size unknown\n"));
466 err = -1;
467 goto out;
468 }
469 if (boff + bsz > 2 * nw)
470 {
471 BS_ERROR (("get_sb_pcmcia_srom: sprom size exceeded\n"));
472 err = -2;
473 goto out;
474 }
475
476 /* read in sprom contents */
477 for (woff = boff / 2, wsz = bsz / 2, i = 0;
478 woff < nw && i < wsz; woff++, i++)
479 {
480 if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &srom[i]))
481 {
482 BS_ERROR (("get_sb_pcmcia_srom: sprom read failed\n"));
483 err = -3;
484 goto out;
485 }
486 }
487
488 out:
489 return err;
490 }
491
492 /*
493 * Write the srom for the pcmcia-srom over sb case.
494 * Return 0 on success, nonzero on error.
495 */
496 static int
497 set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
498 uint boff, uint16 * srom, uint bsz)
499 {
500 uint i, nw, woff, wsz;
501 uint16 word;
502 uint8 crc;
503 int err = 0;
504
505 /* write must be at word boundary */
506 ASSERT ((boff & 1) == 0 && (bsz & 1) == 0);
507
508 /* read sprom size and validate the parms */
509 if ((nw = srom_size (sbh, osh)) == 0)
510 {
511 BS_ERROR (("set_sb_pcmcia_srom: sprom size unknown\n"));
512 err = -1;
513 goto out;
514 }
515 if (boff + bsz > 2 * nw)
516 {
517 BS_ERROR (("set_sb_pcmcia_srom: sprom size exceeded\n"));
518 err = -2;
519 goto out;
520 }
521
522 /* enable write */
523 if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WEN))
524 {
525 BS_ERROR (("set_sb_pcmcia_srom: sprom wen failed\n"));
526 err = -3;
527 goto out;
528 }
529
530 /* write buffer to sprom */
531 for (woff = boff / 2, wsz = bsz / 2, i = 0;
532 woff < nw && i < wsz; woff++, i++)
533 {
534 if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) woff, srom[i]))
535 {
536 BS_ERROR (("set_sb_pcmcia_srom: sprom write failed\n"));
537 err = -4;
538 goto out;
539 }
540 }
541
542 /* fix crc */
543 crc = 0xff;
544 for (woff = 0; woff < nw; woff++)
545 {
546 if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &word))
547 {
548 BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc read failed\n"));
549 err = -5;
550 goto out;
551 }
552 word = htol16 (word);
553 crc = hndcrc8 ((uint8 *) & word, woff != nw - 1 ? 2 : 1, crc);
554 }
555 word = (~crc << 8) + (ltoh16 (word) & 0xff);
556 if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) (woff - 1), word))
557 {
558 BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc write failed\n"));
559 err = -6;
560 goto out;
561 }
562
563 /* disable write */
564 if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WDS))
565 {
566 BS_ERROR (("set_sb_pcmcia_srom: sprom wds failed\n"));
567 err = -7;
568 goto out;
569 }
570
571 out:
572 return err;
573 }
574 #endif /* def BCMUSBDEV */
575
576 int
577 srom_parsecis (osl_t * osh, uint8 * pcis[], uint ciscnt, char **vars,
578 uint * count)
579 {
580 char eabuf[32];
581 char *base;
582 varbuf_t b;
583 uint8 *cis, tup, tlen, sromrev = 1;
584 int i, j;
585 uint varsize;
586 bool ag_init = FALSE;
587 uint32 w32;
588 uint funcid;
589 uint cisnum;
590 int32 boardnum = -1;
591
592 ASSERT (vars);
593 ASSERT (count);
594
595 base = MALLOC (osh, MAXSZ_NVRAM_VARS);
596 ASSERT (base);
597 if (!base)
598 return -2;
599
600 varbuf_init (&b, base, MAXSZ_NVRAM_VARS);
601
602 eabuf[0] = '\0';
603 for (cisnum = 0; cisnum < ciscnt; cisnum++)
604 {
605 cis = *pcis++;
606 i = 0;
607 funcid = 0;
608 do
609 {
610 tup = cis[i++];
611 tlen = cis[i++];
612 if ((i + tlen) >= CIS_SIZE)
613 break;
614
615 switch (tup)
616 {
617 case CISTPL_VERS_1:
618 /* assume the strings are good if the version field checks out */
619 if (((cis[i + 1] << 8) + cis[i]) >= 0x0008)
620 {
621 varbuf_append (&b, "manf=%s", &cis[i + 2]);
622 varbuf_append (&b, "productname=%s",
623 &cis[i + 3 + strlen ((char *) &cis[i + 2])]);
624 break;
625 }
626
627 case CISTPL_MANFID:
628 varbuf_append (&b, "manfid=0x%x", (cis[i + 1] << 8) + cis[i]);
629 varbuf_append (&b, "prodid=0x%x",
630 (cis[i + 3] << 8) + cis[i + 2]);
631 break;
632
633 case CISTPL_FUNCID:
634 funcid = cis[i];
635 break;
636
637 case CISTPL_FUNCE:
638 switch (funcid)
639 {
640 default:
641 /* set macaddr if HNBU_MACADDR not seen yet */
642 if (eabuf[0] == '\0' && cis[i] == LAN_NID)
643 {
644 ASSERT (cis[i + 1] == ETHER_ADDR_LEN);
645 bcm_ether_ntoa ((struct ether_addr *) &cis[i + 2],
646 eabuf);
647 }
648 /* set boardnum if HNBU_BOARDNUM not seen yet */
649 if (boardnum == -1)
650 boardnum = (cis[i + 6] << 8) + cis[i + 7];
651 break;
652 }
653 break;
654
655 case CISTPL_CFTABLE:
656 varbuf_append (&b, "regwindowsz=%d",
657 (cis[i + 7] << 8) | cis[i + 6]);
658 break;
659
660 case CISTPL_BRCM_HNBU:
661 switch (cis[i])
662 {
663 case HNBU_SROMREV:
664 sromrev = cis[i + 1];
665 varbuf_append (&b, "sromrev=%d", sromrev);
666 break;
667
668 case HNBU_CHIPID:
669 varbuf_append (&b, "vendid=0x%x", (cis[i + 2] << 8) +
670 cis[i + 1]);
671 varbuf_append (&b, "devid=0x%x", (cis[i + 4] << 8) +
672 cis[i + 3]);
673 if (tlen >= 7)
674 {
675 varbuf_append (&b, "chiprev=%d",
676 (cis[i + 6] << 8) + cis[i + 5]);
677 }
678 if (tlen >= 9)
679 {
680 varbuf_append (&b, "subvendid=0x%x",
681 (cis[i + 8] << 8) + cis[i + 7]);
682 }
683 if (tlen >= 11)
684 {
685 varbuf_append (&b, "subdevid=0x%x",
686 (cis[i + 10] << 8) + cis[i + 9]);
687 /* subdevid doubles for boardtype */
688 varbuf_append (&b, "boardtype=0x%x",
689 (cis[i + 10] << 8) + cis[i + 9]);
690 }
691 break;
692
693 case HNBU_BOARDREV:
694 varbuf_append (&b, "boardrev=0x%x", cis[i + 1]);
695 break;
696
697 case HNBU_AA:
698 varbuf_append (&b, "aa2g=%d", cis[i + 1]);
699 break;
700
701 case HNBU_AG:
702 varbuf_append (&b, "ag0=%d", cis[i + 1]);
703 ag_init = TRUE;
704 break;
705
706 case HNBU_ANT5G:
707 varbuf_append (&b, "aa5g=%d", cis[i + 1]);
708 varbuf_append (&b, "ag1=%d", cis[i + 2]);
709 break;
710
711 case HNBU_CC:
712 ASSERT (sromrev == 1);
713 varbuf_append (&b, "cc=%d", cis[i + 1]);
714 break;
715
716 case HNBU_PAPARMS:
717 if (tlen == 2)
718 {
719 ASSERT (sromrev == 1);
720 varbuf_append (&b, "pa0maxpwr=%d", cis[i + 1]);
721 }
722 else if (tlen >= 9)
723 {
724 if (tlen == 10)
725 {
726 ASSERT (sromrev >= 2);
727 varbuf_append (&b, "opo=%d", cis[i + 9]);
728 }
729 else
730 ASSERT (tlen == 9);
731
732 for (j = 0; j < 3; j++)
733 {
734 varbuf_append (&b, "pa0b%d=%d", j,
735 (cis[i + (j * 2) + 2] << 8) +
736 cis[i + (j * 2) + 1]);
737 }
738 varbuf_append (&b, "pa0itssit=%d", cis[i + 7]);
739 varbuf_append (&b, "pa0maxpwr=%d", cis[i + 8]);
740 }
741 else
742 ASSERT (tlen >= 9);
743 break;
744
745 case HNBU_PAPARMS5G:
746 ASSERT ((sromrev == 2) || (sromrev == 3));
747 for (j = 0; j < 3; j++)
748 {
749 varbuf_append (&b, "pa1b%d=%d", j,
750 (cis[i + (j * 2) + 2] << 8) +
751 cis[i + (j * 2) + 1]);
752 }
753 for (j = 3; j < 6; j++)
754 {
755 varbuf_append (&b, "pa1lob%d=%d", j - 3,
756 (cis[i + (j * 2) + 2] << 8) +
757 cis[i + (j * 2) + 1]);
758 }
759 for (j = 6; j < 9; j++)
760 {
761 varbuf_append (&b, "pa1hib%d=%d", j - 6,
762 (cis[i + (j * 2) + 2] << 8) +
763 cis[i + (j * 2) + 1]);
764 }
765 varbuf_append (&b, "pa1itssit=%d", cis[i + 19]);
766 varbuf_append (&b, "pa1maxpwr=%d", cis[i + 20]);
767 varbuf_append (&b, "pa1lomaxpwr=%d", cis[i + 21]);
768 varbuf_append (&b, "pa1himaxpwr=%d", cis[i + 22]);
769 break;
770
771 case HNBU_OEM:
772 ASSERT (sromrev == 1);
773 varbuf_append (&b, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
774 cis[i + 1], cis[i + 2],
775 cis[i + 3], cis[i + 4],
776 cis[i + 5], cis[i + 6],
777 cis[i + 7], cis[i + 8]);
778 break;
779
780 case HNBU_BOARDFLAGS:
781 w32 = (cis[i + 2] << 8) + cis[i + 1];
782 if (tlen == 5)
783 w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16);
784 varbuf_append (&b, "boardflags=0x%x", w32);
785 break;
786
787 case HNBU_LEDS:
788 if (cis[i + 1] != 0xff)
789 {
790 varbuf_append (&b, "ledbh0=%d", cis[i + 1]);
791 }
792 if (cis[i + 2] != 0xff)
793 {
794 varbuf_append (&b, "ledbh1=%d", cis[i + 2]);
795 }
796 if (cis[i + 3] != 0xff)
797 {
798 varbuf_append (&b, "ledbh2=%d", cis[i + 3]);
799 }
800 if (cis[i + 4] != 0xff)
801 {
802 varbuf_append (&b, "ledbh3=%d", cis[i + 4]);
803 }
804 break;
805
806 case HNBU_CCODE:
807 ASSERT (sromrev > 1);
808 if ((cis[i + 1] == 0) || (cis[i + 2] == 0))
809 varbuf_append (&b, "ccode=");
810 else
811 varbuf_append (&b, "ccode=%c%c", cis[i + 1], cis[i + 2]);
812 varbuf_append (&b, "cctl=0x%x", cis[i + 3]);
813 break;
814
815 case HNBU_CCKPO:
816 ASSERT (sromrev > 2);
817 varbuf_append (&b, "cckpo=0x%x",
818 (cis[i + 2] << 8) | cis[i + 1]);
819 break;
820
821 case HNBU_OFDMPO:
822 ASSERT (sromrev > 2);
823 varbuf_append (&b, "ofdmpo=0x%x",
824 (cis[i + 4] << 24) |
825 (cis[i + 3] << 16) |
826 (cis[i + 2] << 8) | cis[i + 1]);
827 break;
828
829 case HNBU_RDLID:
830 varbuf_append (&b, "rdlid=0x%x",
831 (cis[i + 2] << 8) | cis[i + 1]);
832 break;
833
834 case HNBU_RDLRNDIS:
835 varbuf_append (&b, "rdlrndis=%d", cis[i + 1]);
836 break;
837
838 case HNBU_RDLRWU:
839 varbuf_append (&b, "rdlrwu=%d", cis[i + 1]);
840 break;
841
842 case HNBU_RDLSN:
843 varbuf_append (&b, "rdlsn=%d",
844 (cis[i + 2] << 8) | cis[i + 1]);
845 break;
846
847 case HNBU_XTALFREQ:
848 varbuf_append (&b, "xtalfreq=%d",
849 (cis[i + 4] << 24) |
850 (cis[i + 3] << 16) |
851 (cis[i + 2] << 8) | cis[i + 1]);
852 break;
853
854 case HNBU_RSSISMBXA2G:
855 ASSERT (sromrev == 3);
856 varbuf_append (&b, "rssismf2g=%d", cis[i + 1] & 0xf);
857 varbuf_append (&b, "rssismc2g=%d", (cis[i + 1] >> 4) & 0xf);
858 varbuf_append (&b, "rssisav2g=%d", cis[i + 2] & 0x7);
859 varbuf_append (&b, "bxa2g=%d", (cis[i + 2] >> 3) & 0x3);
860 break;
861
862 case HNBU_RSSISMBXA5G:
863 ASSERT (sromrev == 3);
864 varbuf_append (&b, "rssismf5g=%d", cis[i + 1] & 0xf);
865 varbuf_append (&b, "rssismc5g=%d", (cis[i + 1] >> 4) & 0xf);
866 varbuf_append (&b, "rssisav5g=%d", cis[i + 2] & 0x7);
867 varbuf_append (&b, "bxa5g=%d", (cis[i + 2] >> 3) & 0x3);
868 break;
869
870 case HNBU_TRI2G:
871 ASSERT (sromrev == 3);
872 varbuf_append (&b, "tri2g=%d", cis[i + 1]);
873 break;
874
875 case HNBU_TRI5G:
876 ASSERT (sromrev == 3);
877 varbuf_append (&b, "tri5gl=%d", cis[i + 1]);
878 varbuf_append (&b, "tri5g=%d", cis[i + 2]);
879 varbuf_append (&b, "tri5gh=%d", cis[i + 3]);
880 break;
881
882 case HNBU_RXPO2G:
883 ASSERT (sromrev == 3);
884 varbuf_append (&b, "rxpo2g=%d", cis[i + 1]);
885 break;
886
887 case HNBU_RXPO5G:
888 ASSERT (sromrev == 3);
889 varbuf_append (&b, "rxpo5g=%d", cis[i + 1]);
890 break;
891
892 case HNBU_BOARDNUM:
893 boardnum = (cis[i + 2] << 8) + cis[i + 1];
894 break;
895
896 case HNBU_MACADDR:
897 bcm_ether_ntoa ((struct ether_addr *) &cis[i + 1], eabuf);
898 break;
899
900 case HNBU_BOARDTYPE:
901 varbuf_append (&b, "boardtype=0x%x",
902 (cis[i + 2] << 8) + cis[i + 1]);
903 break;
904
905 #if defined(BCMCCISSR3)
906 case HNBU_SROM3SWRGN:
907 {
908 uint16 srom[35];
909 uint8 srev = cis[i + 1 + 70];
910 ASSERT (srev == 3);
911 /* make tuple value 16-bit aligned and parse it */
912 bcopy (&cis[i + 1], srom, sizeof (srom));
913 _initvars_srom_pci (srev, srom, SROM3_SWRGN_OFF, &b);
914 /* create extra variables */
915 varbuf_append (&b, "vendid=0x%x",
916 (cis[i + 1 + 73] << 8) + cis[i + 1 + 72]);
917 varbuf_append (&b, "devid=0x%x",
918 (cis[i + 1 + 75] << 8) + cis[i + 1 + 74]);
919 varbuf_append (&b, "xtalfreq=%d",
920 (cis[i + 1 + 77] << 8) + cis[i + 1 + 76]);
921 /* 2.4G antenna gain is included in SROM */
922 ag_init = TRUE;
923 /* Ethernet MAC address is included in SROM */
924 eabuf[0] = 0;
925 boardnum = -1;
926 break;
927 }
928 #endif
929 }
930 break;
931 }
932 i += tlen;
933 }
934 while (tup != CISTPL_END);
935 }
936
937 if (boardnum != -1)
938 {
939 varbuf_append (&b, "boardnum=%d", boardnum);
940 }
941
942 if (eabuf[0])
943 {
944 varbuf_append (&b, "macaddr=%s", eabuf);
945 }
946
947 /* if there is no antenna gain field, set default */
948 if (ag_init == FALSE)
949 {
950 varbuf_append (&b, "ag0=%d", 0xff);
951 }
952
953 /* final nullbyte terminator */
954 ASSERT (b.size >= 1);
955 *b.buf++ = '\0';
956 varsize = (uint) (b.buf - base);
957 ASSERT (varsize < MAXSZ_NVRAM_VARS);
958 if (varsize < MAXSZ_NVRAM_VARS)
959 {
960 char *new_buf;
961 new_buf = (char *) MALLOC (osh, varsize);
962 ASSERT (new_buf);
963 if (new_buf)
964 {
965 bcopy (base, new_buf, varsize);
966 MFREE (osh, base, MAXSZ_NVRAM_VARS);
967 base = new_buf;
968 }
969 }
970
971 *vars = base;
972 *count = varsize;
973
974 return (0);
975 }
976
977
978 /* set PCMCIA sprom command register */
979 static int
980 sprom_cmd_pcmcia (osl_t * osh, uint8 cmd)
981 {
982 uint8 status = 0;
983 uint wait_cnt = 1000;
984
985 /* write sprom command register */
986 OSL_PCMCIA_WRITE_ATTR (osh, SROM_CS, &cmd, 1);
987
988 /* wait status */
989 while (wait_cnt--)
990 {
991 OSL_PCMCIA_READ_ATTR (osh, SROM_CS, &status, 1);
992 if (status & SROM_DONE)
993 return 0;
994 }
995
996 return 1;
997 }
998
999 /* read a word from the PCMCIA srom */
1000 static int
1001 sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data)
1002 {
1003 uint8 addr_l, addr_h, data_l, data_h;
1004
1005 addr_l = (uint8) ((addr * 2) & 0xff);
1006 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
1007
1008 /* set address */
1009 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1);
1010 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1);
1011
1012 /* do read */
1013 if (sprom_cmd_pcmcia (osh, SROM_READ))
1014 return 1;
1015
1016 /* read data */
1017 data_h = data_l = 0;
1018 OSL_PCMCIA_READ_ATTR (osh, SROM_DATAH, &data_h, 1);
1019 OSL_PCMCIA_READ_ATTR (osh, SROM_DATAL, &data_l, 1);
1020
1021 *data = (data_h << 8) | data_l;
1022 return 0;
1023 }
1024
1025 /* write a word to the PCMCIA srom */
1026 static int
1027 sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data)
1028 {
1029 uint8 addr_l, addr_h, data_l, data_h;
1030
1031 addr_l = (uint8) ((addr * 2) & 0xff);
1032 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
1033 data_l = (uint8) (data & 0xff);
1034 data_h = (uint8) ((data >> 8) & 0xff);
1035
1036 /* set address */
1037 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1);
1038 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1);
1039
1040 /* write data */
1041 OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAH, &data_h, 1);
1042 OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAL, &data_l, 1);
1043
1044 /* do write */
1045 return sprom_cmd_pcmcia (osh, SROM_WRITE);
1046 }
1047
1048 /*
1049 * Read in and validate sprom.
1050 * Return 0 on success, nonzero on error.
1051 */
1052 static int
1053 sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff, uint16 * buf,
1054 uint nwords, bool check_crc)
1055 {
1056 int err = 0;
1057 uint i;
1058
1059 /* read the sprom */
1060 for (i = 0; i < nwords; i++)
1061 {
1062 #ifdef BCMQT
1063 buf[i] = R_REG (osh, &sprom[wordoff + i]);
1064 #endif
1065 buf[i] = R_REG (osh, &sprom[wordoff + i]);
1066 }
1067
1068 if (check_crc)
1069 {
1070 if (buf[0] == 0xffff)
1071 {
1072 /* The hardware thinks that an srom that starts with 0xffff
1073 * is blank, regardless of the rest of the content, so declare
1074 * it bad.
1075 */
1076 BS_ERROR (("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__,
1077 buf[0]));
1078 return 1;
1079 }
1080
1081 /* fixup the endianness so crc8 will pass */
1082 htol16_buf (buf, nwords * 2);
1083 if (hndcrc8 ((uint8 *) buf, nwords * 2, 0xff) != 0x9f)
1084 err = 1;
1085 /* now correct the endianness of the byte array */
1086 ltoh16_buf (buf, nwords * 2);
1087 }
1088
1089 return err;
1090 }
1091
1092 /*
1093 * Create variable table from memory.
1094 * Return 0 on success, nonzero on error.
1095 */
1096 static int
1097 BCMINITFN (initvars_table) (osl_t * osh, char *start, char *end, char **vars,
1098 uint * count)
1099 {
1100 int c = (int) (end - start);
1101
1102 /* do it only when there is more than just the null string */
1103 if (c > 1)
1104 {
1105 char *vp = MALLOC (osh, c);
1106 ASSERT (vp);
1107 if (!vp)
1108 return BCME_NOMEM;
1109 bcopy (start, vp, c);
1110 *vars = vp;
1111 *count = c;
1112 }
1113 else
1114 {
1115 *vars = NULL;
1116 *count = 0;
1117 }
1118
1119 return 0;
1120 }
1121
1122 /*
1123 * Find variables with <devpath> from flash. 'base' points to the beginning
1124 * of the table upon enter and to the end of the table upon exit when success.
1125 * Return 0 on success, nonzero on error.
1126 */
1127 static int
1128 initvars_flash (sb_t * sbh, osl_t * osh, char **base, uint len)
1129 {
1130 char *vp = *base;
1131 char *flash;
1132 int err;
1133 char *s;
1134 uint l, dl, copy_len;
1135 char devpath[SB_DEVPATH_BUFSZ];
1136
1137 /* allocate memory and read in flash */
1138 if (!(flash = MALLOC (osh, NVRAM_SPACE)))
1139 return BCME_NOMEM;
1140 if ((err = nvram_getall (flash, NVRAM_SPACE)))
1141 goto exit;
1142
1143 sb_devpath (sbh, devpath, sizeof (devpath));
1144
1145 /* grab vars with the <devpath> prefix in name */
1146 dl = strlen (devpath);
1147 for (s = flash; s && *s; s += l + 1)
1148 {
1149 l = strlen (s);
1150
1151 /* skip non-matching variable */
1152 if (strncmp (s, devpath, dl))
1153 continue;
1154
1155 /* is there enough room to copy? */
1156 copy_len = l - dl + 1;
1157 if (len < copy_len)
1158 {
1159 err = BCME_BUFTOOSHORT;
1160 goto exit;
1161 }
1162
1163 /* no prefix, just the name=value */
1164 strncpy (vp, &s[dl], copy_len);
1165 vp += copy_len;
1166 len -= copy_len;
1167 }
1168
1169 /* add null string as terminator */
1170 if (len < 1)
1171 {
1172 err = BCME_BUFTOOSHORT;
1173 goto exit;
1174 }
1175 *vp++ = '\0';
1176
1177 *base = vp;
1178
1179 exit:MFREE (osh, flash, NVRAM_SPACE);
1180 return err;
1181 }
1182
1183 #if !defined(BCMUSBDEV) && !defined(BCMSDIODEV)
1184 /*
1185 * Initialize nonvolatile variable table from flash.
1186 * Return 0 on success, nonzero on error.
1187 */
1188 static int
1189 initvars_flash_sb (sb_t * sbh, char **vars, uint * count)
1190 {
1191 osl_t *osh = sb_osh (sbh);
1192 char *vp, *base;
1193 int err;
1194
1195 ASSERT (vars);
1196 ASSERT (count);
1197
1198 base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS);
1199 ASSERT (vp);
1200 if (!vp)
1201 return BCME_NOMEM;
1202
1203 if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)) == 0)
1204 err = initvars_table (osh, base, vp, vars, count);
1205
1206 MFREE (osh, base, MAXSZ_NVRAM_VARS);
1207
1208 return err;
1209 }
1210 #endif /* !BCMUSBDEV && !BCMSDIODEV */
1211
1212 #ifdef WLTEST
1213 char mfgsromvars[256];
1214 char *defaultsromvars = "il0macaddr=00:11:22:33:44:51\0"
1215 "et0macaddr=00:11:22:33:44:52\0"
1216 "et1macaddr=00:11:22:33:44:53\0"
1217 "boardtype=0xffff\0"
1218 "boardrev=0x10\0" "boardflags=8\0" "sromrev=2\0" "aa2g=3\0" "\0";
1219 #define MFGSROM_DEFVARSLEN 149 /* default srom len */
1220 #endif /* WL_TEST */
1221
1222 /*
1223 * Initialize nonvolatile variable table from sprom.
1224 * Return 0 on success, nonzero on error.
1225 */
1226
1227 typedef struct
1228 {
1229 const char *name;
1230 uint32 revmask;
1231 uint32 flags;
1232 uint16 off;
1233 uint16 mask;
1234 } sromvar_t;
1235
1236 #define SRFL_MORE 1 /* value continues as described by the next entry */
1237 #define SRFL_NOFFS 2 /* value bits can't be all one's */
1238 #define SRFL_PRHEX 4 /* value is in hexdecimal format */
1239 #define SRFL_PRSIGN 8 /* value is in signed decimal format */
1240 #define SRFL_CCODE 0x10 /* value is in country code format */
1241 #define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
1242 #define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
1243
1244 /* Assumptions:
1245 * - Ethernet address spins across 3 consective words
1246 *
1247 * Table rules:
1248 * - Add multiple entries next to each other if a value spins across multiple words
1249 * (even multiple fields in the same word) with each entry except the last having
1250 * it's SRFL_MORE bit set.
1251 * - Ethernet address entry does not follow above rule and must not have SRFL_MORE
1252 * bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
1253 * - The last entry's name field must be NULL to indicate the end of the table. Other
1254 * entries must have non-NULL name.
1255 */
1256
1257 static const sromvar_t pci_sromvars[] = {
1258 {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK},
1259 {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
1260 {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
1261 {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
1262 {"boardflags", 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
1263 {"", 0, 0, SROM_BFL2, 0xffff},
1264 {"boardflags", 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
1265 {"", 0, 0, SROM3_BFL2, 0xffff},
1266 {"boardflags", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, 0xffff},
1267 {"", 0, 0, SROM4_BFL1, 0xffff},
1268 {"boardflags", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, 0xffff},
1269 {"", 0, 0, SROM5_BFL1, 0xffff},
1270 {"boardflags", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, 0xffff},
1271 {"", 0, 0, SROM8_BFL1, 0xffff},
1272 {"boardflags2", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, 0xffff},
1273 {"", 0, 0, SROM4_BFL3, 0xffff},
1274 {"boardflags2", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, 0xffff},
1275 {"", 0, 0, SROM5_BFL3, 0xffff},
1276 {"boardflags2", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, 0xffff},
1277 {"", 0, 0, SROM8_BFL3, 0xffff},
1278 {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
1279 {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
1280 {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff},
1281 {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff},
1282 {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff},
1283 {"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff},
1284 {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
1285 {"regrev", 0x00000008, 0, SROM_OPO, 0xff00},
1286 {"regrev", 0x00000010, 0, SROM4_REGREV, 0xff},
1287 {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xff},
1288 {"regrev", 0xffffff00, 0, SROM8_REGREV, 0xff},
1289 {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff},
1290 {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
1291 {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff},
1292 {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
1293 {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff},
1294 {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
1295 {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff},
1296 {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
1297 {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff},
1298 {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
1299 {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff},
1300 {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
1301 {"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff},
1302 {"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
1303 {"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff},
1304 {"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
1305 {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
1306 {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
1307 {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
1308 {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0xff},
1309 {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff},
1310 {"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
1311 {"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
1312 {"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
1313 {"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
1314 {"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff},
1315 {"opo", 0x0000000c, 0, SROM_OPO, 0xff},
1316 {"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0xff},
1317 {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
1318 {"aa2g", 0x000000f0, 0, SROM4_AA, 0xff},
1319 {"aa2g", 0xffffff00, 0, SROM8_AA, 0xff},
1320 {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
1321 {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00},
1322 {"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00},
1323 {"ag0", 0x0000000e, 0, SROM_AG10, 0xff},
1324 {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00},
1325 {"ag0", 0x000000f0, 0, SROM4_AG10, 0xff},
1326 {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00},
1327 {"ag2", 0x000000f0, 0, SROM4_AG32, 0xff},
1328 {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00},
1329 {"ag0", 0xffffff00, 0, SROM8_AG10, 0xff},
1330 {"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00},
1331 {"ag2", 0xffffff00, 0, SROM8_AG32, 0xff},
1332 {"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00},
1333 {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
1334 {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
1335 {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
1336 {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
1337 {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
1338 {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
1339 {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
1340 {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
1341 {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
1342 {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00},
1343 {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
1344 {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
1345 {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff},
1346 {"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
1347 {"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
1348 {"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
1349 {"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
1350 {"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
1351 {"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
1352 {"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
1353 {"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
1354 {"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
1355 {"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
1356 {"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff},
1357 {"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
1358 {"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff},
1359 {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
1360 {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
1361 {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
1362 {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
1363 {"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
1364 {"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
1365 {"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
1366 {"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
1367 {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
1368 {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
1369 {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
1370 {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
1371 {"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
1372 {"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
1373 {"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
1374 {"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
1375 {"tri2g", 0x00000008, 0, SROM_TRI52G, 0xff},
1376 {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00},
1377 {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0xff},
1378 {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00},
1379 {"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0xff},
1380 {"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00},
1381 {"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0xff},
1382 {"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
1383 {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff},
1384 {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
1385 {"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff},
1386 {"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
1387 {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK},
1388 {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK},
1389 {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK},
1390 {"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK},
1391 {"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK},
1392 {"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK},
1393 {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0xff},
1394 {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
1395 {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff},
1396 {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
1397 {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0xff},
1398 {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
1399 {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff},
1400 {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
1401 {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0xff},
1402 {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
1403 {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff},
1404 {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
1405 {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0xff},
1406 {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
1407 {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff},
1408 {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
1409 {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
1410 {"cck2gpo", 0xffffff00, 0, SROM8_2G_CCKPO, 0xffff},
1411 {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
1412 {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
1413 {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
1414 {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
1415 {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
1416 {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
1417 {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
1418 {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
1419 {"ofdm2gpo", 0xffffff00, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
1420 {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
1421 {"ofdm5gpo", 0xffffff00, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
1422 {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
1423 {"ofdm5glpo", 0xffffff00, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
1424 {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
1425 {"ofdm5ghpo", 0xffffff00, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
1426 {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
1427 {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
1428 {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
1429 {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
1430 {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
1431 {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
1432 {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
1433 {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
1434 {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
1435 {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
1436 {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
1437 {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
1438 {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
1439 {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
1440 {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
1441 {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
1442 {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
1443 {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
1444 {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
1445 {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
1446 {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
1447 {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
1448 {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
1449 {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
1450 {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
1451 {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
1452 {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
1453 {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
1454 {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
1455 {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
1456 {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
1457 {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
1458 {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
1459 {"mcs2gpo0", 0xffffff00, 0, SROM8_2G_MCSPO, 0xffff},
1460 {"mcs2gpo1", 0xffffff00, 0, SROM8_2G_MCSPO + 1, 0xffff},
1461 {"mcs2gpo2", 0xffffff00, 0, SROM8_2G_MCSPO + 2, 0xffff},
1462 {"mcs2gpo3", 0xffffff00, 0, SROM8_2G_MCSPO + 3, 0xffff},
1463 {"mcs2gpo4", 0xffffff00, 0, SROM8_2G_MCSPO + 4, 0xffff},
1464 {"mcs2gpo5", 0xffffff00, 0, SROM8_2G_MCSPO + 5, 0xffff},
1465 {"mcs2gpo6", 0xffffff00, 0, SROM8_2G_MCSPO + 6, 0xffff},
1466 {"mcs2gpo7", 0xffffff00, 0, SROM8_2G_MCSPO + 7, 0xffff},
1467 {"mcs5gpo0", 0xffffff00, 0, SROM8_5G_MCSPO, 0xffff},
1468 {"mcs5gpo1", 0xffffff00, 0, SROM8_5G_MCSPO + 1, 0xffff},
1469 {"mcs5gpo2", 0xffffff00, 0, SROM8_5G_MCSPO + 2, 0xffff},
1470 {"mcs5gpo3", 0xffffff00, 0, SROM8_5G_MCSPO + 3, 0xffff},
1471 {"mcs5gpo4", 0xffffff00, 0, SROM8_5G_MCSPO + 4, 0xffff},
1472 {"mcs5gpo5", 0xffffff00, 0, SROM8_5G_MCSPO + 5, 0xffff},
1473 {"mcs5gpo6", 0xffffff00, 0, SROM8_5G_MCSPO + 6, 0xffff},
1474 {"mcs5gpo7", 0xffffff00, 0, SROM8_5G_MCSPO + 7, 0xffff},
1475 {"mcs5glpo0", 0xffffff00, 0, SROM8_5GL_MCSPO, 0xffff},
1476 {"mcs5glpo1", 0xffffff00, 0, SROM8_5GL_MCSPO + 1, 0xffff},
1477 {"mcs5glpo2", 0xffffff00, 0, SROM8_5GL_MCSPO + 2, 0xffff},
1478 {"mcs5glpo3", 0xffffff00, 0, SROM8_5GL_MCSPO + 3, 0xffff},
1479 {"mcs5glpo4", 0xffffff00, 0, SROM8_5GL_MCSPO + 4, 0xffff},
1480 {"mcs5glpo5", 0xffffff00, 0, SROM8_5GL_MCSPO + 5, 0xffff},
1481 {"mcs5glpo6", 0xffffff00, 0, SROM8_5GL_MCSPO + 6, 0xffff},
1482 {"mcs5glpo7", 0xffffff00, 0, SROM8_5GL_MCSPO + 7, 0xffff},
1483 {"mcs5ghpo0", 0xffffff00, 0, SROM8_5GH_MCSPO, 0xffff},
1484 {"mcs5ghpo1", 0xffffff00, 0, SROM8_5GH_MCSPO + 1, 0xffff},
1485 {"mcs5ghpo2", 0xffffff00, 0, SROM8_5GH_MCSPO + 2, 0xffff},
1486 {"mcs5ghpo3", 0xffffff00, 0, SROM8_5GH_MCSPO + 3, 0xffff},
1487 {"mcs5ghpo4", 0xffffff00, 0, SROM8_5GH_MCSPO + 4, 0xffff},
1488 {"mcs5ghpo5", 0xffffff00, 0, SROM8_5GH_MCSPO + 5, 0xffff},
1489 {"mcs5ghpo6", 0xffffff00, 0, SROM8_5GH_MCSPO + 6, 0xffff},
1490 {"mcs5ghpo7", 0xffffff00, 0, SROM8_5GH_MCSPO + 7, 0xffff},
1491 {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff},
1492 {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff},
1493 {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff},
1494 {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
1495 {"cddpo", 0xffffff00, 0, SROM8_CDDPO, 0xffff},
1496 {"stbcpo", 0xffffff00, 0, SROM8_STBCPO, 0xffff},
1497 {"bw40po", 0xffffff00, 0, SROM8_BW40PO, 0xffff},
1498 {"bwduppo", 0xffffff00, 0, SROM8_BWDUPPO, 0xffff},
1499 {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
1500 {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
1501 {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
1502 {"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
1503 {"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
1504 {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
1505 {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
1506 {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
1507 {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff},
1508 {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff},
1509 {"leddc", 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, 0xffff},
1510 {"leddc", 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, 0xffff},
1511 {"leddc", 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, 0xffff},
1512 {"leddc", 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, 0xffff},
1513 {NULL, 0, 0, 0, 0}
1514 };
1515
1516 static const sromvar_t perpath_pci_sromvars[] = {
1517 {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff},
1518 {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
1519 {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
1520 {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
1521 {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
1522 {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
1523 {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
1524 {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff},
1525 {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff},
1526 {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
1527 {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
1528 {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
1529 {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
1530 {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
1531 {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
1532 {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff},
1533 {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff},
1534 {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff},
1535 {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
1536 {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff},
1537 {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff},
1538 {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff},
1539 {"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff},
1540 {"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
1541 {"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
1542 {"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
1543 {"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
1544 {"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
1545 {"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff},
1546 {"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff},
1547 {"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
1548 {"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
1549 {"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
1550 {"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
1551 {"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
1552 {"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff},
1553 {"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff},
1554 {"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
1555 {"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff},
1556 {"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff},
1557 {NULL, 0, 0, 0, 0}
1558 };
1559
1560 /* Parse SROM and create name=value pairs. 'srom' points to
1561 * the SROM word array. 'off' specifies the offset of the
1562 * first word 'srom' points to, which should be either 0 or
1563 * SROM3_SWRG_OFF (full SROM or software region).
1564 */
1565
1566 static uint
1567 mask_shift (uint16 mask)
1568 {
1569 uint i;
1570 for (i = 0; i < (sizeof (mask) << 3); i++)
1571 {
1572 if (mask & (1 << i))
1573 return i;
1574 }
1575 ASSERT (mask);
1576 return 0;
1577 }
1578
1579 static uint
1580 mask_width (uint16 mask)
1581 {
1582 int i;
1583 for (i = (sizeof (mask) << 3) - 1; i >= 0; i--)
1584 {
1585 if (mask & (1 << i))
1586 return (uint) (i - mask_shift (mask) + 1);
1587 }
1588 ASSERT (mask);
1589 return 0;
1590 }
1591
1592 #ifdef BCMDBG_ASSERT
1593 static bool
1594 mask_valid (uint16 mask)
1595 {
1596 uint shift = mask_shift (mask);
1597 uint width = mask_width (mask);
1598 return mask == ((~0 << shift) & ~(~0 << (shift + width)));
1599 }
1600 #endif
1601
1602 static void
1603 _initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off, varbuf_t * b)
1604 {
1605 uint16 w;
1606 uint32 val;
1607 const sromvar_t *srv;
1608 uint width;
1609 uint flags;
1610 uint32 sr = (1 << sromrev);
1611
1612 varbuf_append (b, "sromrev=%d", sromrev);
1613
1614 for (srv = pci_sromvars; srv->name != NULL; srv++)
1615 {
1616 const char *name;
1617
1618 if ((srv->revmask & sr) == 0)
1619 continue;
1620
1621 if (srv->off < off)
1622 continue;
1623
1624 flags = srv->flags;
1625 name = srv->name;
1626
1627 if (flags & SRFL_ETHADDR)
1628 {
1629 char eabuf[ETHER_ADDR_STR_LEN];
1630 struct ether_addr ea;
1631
1632 ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff;
1633 ea.octet[1] = srom[srv->off - off] & 0xff;
1634 ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff;
1635 ea.octet[3] = srom[srv->off + 1 - off] & 0xff;
1636 ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff;
1637 ea.octet[5] = srom[srv->off + 2 - off] & 0xff;
1638 bcm_ether_ntoa (&ea, eabuf);
1639
1640 varbuf_append (b, "%s=%s", name, eabuf);
1641 }
1642 else
1643 {
1644 ASSERT (mask_valid (srv->mask));
1645 ASSERT (mask_width (srv->mask));
1646
1647 w = srom[srv->off - off];
1648 val = (w & srv->mask) >> mask_shift (srv->mask);
1649 width = mask_width (srv->mask);
1650
1651 while (srv->flags & SRFL_MORE)
1652 {
1653 srv++;
1654 ASSERT (srv->name);
1655
1656 if (srv->off == 0 || srv->off < off)
1657 continue;
1658
1659 ASSERT (mask_valid (srv->mask));
1660 ASSERT (mask_width (srv->mask));
1661
1662 w = srom[srv->off - off];
1663 val += ((w & srv->mask) >> mask_shift (srv->mask)) << width;
1664 width += mask_width (srv->mask);
1665 }
1666
1667 if ((flags & SRFL_NOFFS) && ((int) val == (1 << width) - 1))
1668 continue;
1669
1670 if (flags & SRFL_CCODE)
1671 {
1672 if (val == 0)
1673 varbuf_append (b, "ccode=");
1674 else
1675 varbuf_append (b, "ccode=%c%c", (val >> 8), (val & 0xff));
1676 }
1677 /* LED Powersave duty cycle has to be scaled:
1678 *(oncount >> 24) (offcount >> 8)
1679 */
1680 else if (flags & SRFL_LEDDC)
1681 {
1682 uint32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */
1683 (((val & 0xff)) << 8); /* offcount */
1684 varbuf_append (b, "leddc=%d", w32);
1685 }
1686 else if (flags & SRFL_PRHEX)
1687 varbuf_append (b, "%s=0x%x", name, val);
1688 else if ((flags & SRFL_PRSIGN) && (val & (1 << (width - 1))))
1689 varbuf_append (b, "%s=%d", name, (int) (val | (~0 << width)));
1690 else
1691 varbuf_append (b, "%s=%u", name, val);
1692 }
1693 }
1694
1695 if (sromrev >= 4)
1696 {
1697 /* Do per-path variables */
1698 uint p, pb, psz;
1699
1700 if (sromrev >= 8)
1701 {
1702 pb = SROM8_PATH0;
1703 psz = SROM8_PATH1 - SROM8_PATH0;
1704 }
1705 else
1706 {
1707 pb = SROM4_PATH0;
1708 psz = SROM4_PATH1 - SROM4_PATH0;
1709 }
1710
1711 for (p = 0; p < MAX_PATH; p++)
1712 {
1713 for (srv = perpath_pci_sromvars; srv->name != NULL; srv++)
1714 {
1715 if ((srv->revmask & sr) == 0)
1716 continue;
1717
1718 if (pb + srv->off < off)
1719 continue;
1720
1721 w = srom[pb + srv->off - off];
1722 ASSERT (mask_valid (srv->mask));
1723 val = (w & srv->mask) >> mask_shift (srv->mask);
1724 width = mask_width (srv->mask);
1725
1726 /* Cheating: no per-path var is more than 1 word */
1727
1728 if ((srv->flags & SRFL_NOFFS)
1729 && ((int) val == (1 << width) - 1))
1730 continue;
1731
1732 if (srv->flags & SRFL_PRHEX)
1733 varbuf_append (b, "%s%d=0x%x", srv->name, p, val);
1734 else
1735 varbuf_append (b, "%s%d=%d", srv->name, p, val);
1736 }
1737 pb += psz;
1738 }
1739 }
1740 }
1741
1742 static int
1743 initvars_srom_pci (sb_t * sbh, void *curmap, char **vars, uint * count)
1744 {
1745 uint16 *srom;
1746 uint8 sromrev = 0;
1747 uint32 sr;
1748 varbuf_t b;
1749 char *vp, *base = NULL;
1750 osl_t *osh = sb_osh (sbh);
1751 bool flash = FALSE;
1752 char *value;
1753 int err;
1754
1755 /*
1756 * Apply CRC over SROM content regardless SROM is present or not,
1757 * and use variable <devpath>sromrev's existance in flash to decide
1758 * if we should return an error when CRC fails or read SROM variables
1759 * from flash.
1760 */
1761 srom = MALLOC (osh, SROM_MAX);
1762 ASSERT (srom);
1763 if (!srom)
1764 return -2;
1765
1766 err =
1767 sprom_read_pci (osh, (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET),
1768 0, srom, SROM_WORDS, TRUE);
1769
1770 if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
1771 ((sbh->buscoretype == SB_PCIE) && (sbh->buscorerev >= 6)))
1772 {
1773 /* sromrev >= 4, read more */
1774 err =
1775 sprom_read_pci (osh,
1776 (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET), 0,
1777 srom, SROM4_WORDS, TRUE);
1778 sromrev = srom[SROM4_CRCREV] & 0xff;
1779 }
1780 else if (err == 0)
1781 {
1782 /* srom is good and is rev < 4 */
1783 /* top word of sprom contains version and crc8 */
1784 sromrev = srom[SROM_CRCREV] & 0xff;
1785 /* bcm4401 sroms misprogrammed */
1786 if (sromrev == 0x10)
1787 sromrev = 1;
1788 }
1789
1790 if (err)
1791 {
1792 #ifdef WLTEST
1793 uint32 val;
1794
1795 BS_ERROR (("SROM Crc Error, so see if we could use a default\n"));
1796 val = OSL_PCI_READ_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32));
1797 if (val & SPROM_OTPIN_USE)
1798 {
1799 BS_ERROR (("srom crc failed with OTP, use default vars....\n"));
1800 vp = base = mfgsromvars;
1801 if (sb_chip (sbh) == BCM4311_CHIP_ID)
1802 {
1803 const char *devid = "devid=0x4311";
1804 const size_t devid_strlen = strlen (devid);
1805 BS_ERROR (("setting the devid to be 4311\n"));
1806 bcopy (devid, vp, devid_strlen + 1);
1807 vp += devid_strlen + 1;
1808 }
1809 bcopy (defaultsromvars, vp, MFGSROM_DEFVARSLEN);
1810 vp += MFGSROM_DEFVARSLEN;
1811 goto varsdone;
1812 }
1813 else
1814 {
1815 #endif /* WLTEST */
1816 BS_ERROR (("srom crc failed with SPROM....\n"));
1817 if (!(value = sb_getdevpathvar (sbh, "sromrev")))
1818 {
1819 err = -1;
1820 goto errout;
1821 }
1822 sromrev = (uint8) simple_strtoul (value, NULL, 0);
1823 flash = TRUE;
1824 #ifdef WLTEST
1825 }
1826 #endif /* WLTEST */
1827 }
1828
1829 /* Bitmask for the sromrev */
1830 sr = 1 << sromrev;
1831
1832 /* srom version check
1833 * Current valid versions: 1, 2, 3, 4, 5, 8
1834 */
1835 if ((sr & 0x13e) == 0)
1836 {
1837 err = -2;
1838 goto errout;
1839 }
1840
1841 ASSERT (vars);
1842 ASSERT (count);
1843
1844 base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS);
1845 ASSERT (vp);
1846 if (!vp)
1847 {
1848 err = -2;
1849 goto errout;
1850 }
1851
1852 /* read variables from flash */
1853 if (flash)
1854 {
1855 if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)))
1856 goto errout;
1857 goto varsdone;
1858 }
1859
1860 varbuf_init (&b, base, MAXSZ_NVRAM_VARS);
1861
1862 /* parse SROM into name=value pairs. */
1863 _initvars_srom_pci (sromrev, srom, 0, &b);
1864
1865 /* final nullbyte terminator */
1866 ASSERT (b.size >= 1);
1867 vp = b.buf;
1868 *vp++ = '\0';
1869
1870 ASSERT ((vp - base) <= MAXSZ_NVRAM_VARS);
1871
1872 varsdone:
1873 err = initvars_table (osh, base, vp, vars, count);
1874
1875 errout:
1876 #ifdef WLTEST
1877 if (base && (base != mfgsromvars))
1878 #else
1879 if (base)
1880 #endif
1881 MFREE (osh, base, MAXSZ_NVRAM_VARS);
1882
1883 MFREE (osh, srom, SROM_MAX);
1884 return err;
1885 }
1886
1887 /*
1888 * Read the cis and call parsecis to initialize the vars.
1889 * Return 0 on success, nonzero on error.
1890 */
1891 static int
1892 initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars, uint * count)
1893 {
1894 uint8 *cis = NULL;
1895 int rc;
1896 uint data_sz;
1897
1898 data_sz = (sb_pcmciarev (sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
1899
1900 if ((cis = MALLOC (osh, data_sz)) == NULL)
1901 return (-2);
1902
1903 if (sb_pcmciarev (sbh) == 1)
1904 {
1905 if (srom_read
1906 (sbh, PCMCIA_BUS, (void *) NULL, osh, 0, data_sz, (uint16 *) cis))
1907 {
1908 MFREE (osh, cis, data_sz);
1909 return (-1);
1910 }
1911 /* fix up endianess for 16-bit data vs 8-bit parsing */
1912 htol16_buf ((uint16 *) cis, data_sz);
1913 }
1914 else
1915 OSL_PCMCIA_READ_ATTR (osh, 0, cis, data_sz);
1916
1917 rc = srom_parsecis (osh, &cis, 1, vars, count);
1918
1919 MFREE (osh, cis, data_sz);
1920
1921 return (rc);
1922 }
1923
1924
1925 static int
1926 BCMINITFN (initvars_srom_sb) (sb_t * sbh, osl_t * osh, void *curmap,
1927 char **vars, uint * varsz)
1928 {
1929 #if defined(BCMSDIODEV)
1930 /* CIS is read and supplied by the host */
1931 return BCME_OK;
1932 #elif defined(BCMUSBDEV)
1933 static bool srvars = FALSE; /* Use OTP/SPROM as global variables */
1934
1935 int sel = 0; /* where to read the srom. 0 - nowhere, 1 - otp, 2 - sprom */
1936 uint sz = 0; /* srom size in bytes */
1937 void *oh = NULL;
1938 int rc = BCME_OK;
1939
1940 /* Bail out if we've dealt with OTP/SPROM before! */
1941 if (srvars)
1942 return 0;
1943
1944 #if defined(BCM4328)
1945 if (sbh->chip == BCM4328_CHIP_ID)
1946 {
1947 /* Access the SPROM if it is present */
1948 if ((sz = srom_size (sbh, osh)) != 0)
1949 {
1950 sz <<= 1;
1951 sel = 2;
1952 }
1953 }
1954 #endif
1955 #if defined(BCM4325)
1956 if (sbh->chip == BCM4325_CHIP_ID)
1957 {
1958 uint32 cst = sbh->chipst & CST4325_SPROM_OTP_SEL_MASK;
1959
1960 /* Access OTP if it is present, powered on, and programmed */
1961 if ((oh = otp_init (sbh)) != NULL && (otp_status (oh) & OTPS_GUP_SW))
1962 {
1963 sz = otp_size (oh);
1964 sel = 1;
1965 }
1966 /* Access the SPROM if it is present and allow to be accessed */
1967 else if ((cst == CST4325_OTP_PWRDN || cst == CST4325_SPROM_SEL) &&
1968 (sz = srom_size (sbh, osh)) != 0)
1969 {
1970 sz <<= 1;
1971 sel = 2;
1972 }
1973 }
1974 #endif /* BCM4325 */
1975
1976 /* Read CIS in OTP/SPROM */
1977 if (sel != 0)
1978 {
1979 uint16 *srom;
1980 uint8 *body = NULL;
1981
1982 ASSERT (sz);
1983
1984 /* Allocate memory */
1985 if ((srom = (uint16 *) MALLOC (osh, sz)) == NULL)
1986 return BCME_NOMEM;
1987
1988 /* Read CIS */
1989 switch (sel)
1990 {
1991 case 1:
1992 rc = otp_read_region (oh, OTP_SW_RGN, srom, sz);
1993 body = (uint8 *) srom;
1994 break;
1995 case 2:
1996 rc = srom_read (sbh, SB_BUS, curmap, osh, 0, sz, srom);
1997 /* sprom has 8 byte h/w header */
1998 body = (uint8 *) srom + SBSDIO_SPROM_CIS_OFFSET;
1999 break;
2000 default:
2001 /* impossible to come here */
2002 ASSERT (0);
2003 break;
2004 }
2005
2006 /* Parse CIS */
2007 if (rc == BCME_OK)
2008 {
2009 uint i, tpls = 0xffffffff;
2010 /* # sdiod fns + common + extra */
2011 uint8 *cis[SBSDIO_NUM_FUNCTION + 2];
2012 uint ciss = 0;
2013
2014 /* each word is in host endian */
2015 htol16_buf ((uint8 *) srom, sz);
2016
2017 ASSERT (body);
2018
2019 /* count cis tuple chains */
2020 for (i = 0; i < sz && ciss < ARRAYSIZE (cis) && tpls != 0; i++)
2021 {
2022 cis[ciss++] = &body[i];
2023 for (tpls = 0; i < sz - 1; tpls++)
2024 {
2025 if (body[i++] == CISTPL_END)
2026 break;
2027 i += body[i] + 1;
2028 }
2029 }
2030
2031 /* call parser routine only when there are tuple chains */
2032 if (ciss > 1)
2033 rc = srom_parsecis (osh, cis, ciss, vars, varsz);
2034 }
2035
2036 /* Clean up */
2037 MFREE (osh, srom, sz);
2038
2039 /* Make SROM variables global */
2040 if (rc == BCME_OK)
2041 {
2042 rc = nvram_append ((void *) sbh, *vars, *varsz);
2043 srvars = TRUE;
2044
2045 /* Tell the caller there is no individual SROM variables */
2046 *vars = NULL;
2047 *varsz = 0;
2048 }
2049 }
2050
2051 return rc;
2052 #else /* !BCMUSBDEV && !BCMSDIODEV */
2053 /* Search flash nvram section for srom variables */
2054 return initvars_flash_sb (sbh, vars, varsz);
2055 #endif /* !BCMUSBDEV && !BCMSDIODEV */
2056 }
2057
2058 #ifdef BCMUSBDEV
2059 /* Return sprom size in 16-bit words */
2060 static uint
2061 srom_size (sb_t * sbh, osl_t * osh)
2062 {
2063 uint size = 0;
2064 if (SPROMBUS == PCMCIA_BUS)
2065 {
2066 uint32 origidx;
2067 sdpcmd_regs_t *pcmregs;
2068 bool wasup;
2069
2070 origidx = sb_coreidx (sbh);
2071 pcmregs = sb_setcore (sbh, SB_PCMCIA, 0);
2072 ASSERT (pcmregs);
2073
2074 if (!(wasup = sb_iscoreup (sbh)))
2075 sb_core_reset (sbh, 0, 0);
2076
2077 /* not worry about earlier core revs */
2078 if (sb_corerev (sbh) < 8)
2079 goto done;
2080
2081 /* SPROM is accessible only in PCMCIA mode unless there is SDIO clock */
2082 if (!(R_REG (osh, &pcmregs->corestatus) & CS_PCMCIAMODE))
2083 goto done;
2084
2085 switch (SB_PCMCIA_READ (osh, pcmregs, SROM_INFO) & SRI_SZ_MASK)
2086 {
2087 case 1:
2088 size = 256; /* SROM_INFO == 1 means 4kbit */
2089 break;
2090 case 2:
2091 size = 1024; /* SROM_INFO == 2 means 16kbit */
2092 break;
2093 default:
2094 break;
2095 }
2096
2097 done:
2098 if (!wasup)
2099 sb_core_disable (sbh, 0);
2100
2101 sb_setcoreidx (sbh, origidx);
2102 }
2103 return size;
2104 }
2105 #endif /* def BCMUSBDEV */