d5737d72fcb9d5d12bf21bc184634fe259f72f82
[openwrt.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 */