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