Root/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
38typedef struct varbuf
39{
40  char *buf; /* pointer to current position */
41  unsigned int size; /* current (residual) size in bytes */
42} varbuf_t;
43
44static int initvars_srom_sb (sb_t * sbh, osl_t * osh, void *curmap,
45                 char **vars, uint * count);
46static void _initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off,
47                varbuf_t * b);
48static int initvars_srom_pci (sb_t * sbh, void *curmap, char **vars,
49                  uint * count);
50static int initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars,
51                uint * count);
52#if !defined(BCMUSBDEV) && !defined(BCMSDIODEV)
53static int initvars_flash_sb (sb_t * sbh, char **vars, uint * count);
54#endif /* !BCMUSBDEV && !BCMSDIODEV */
55static int sprom_cmd_pcmcia (osl_t * osh, uint8 cmd);
56static int sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data);
57static int sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data);
58static int sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff,
59               uint16 * buf, uint nwords, bool check_crc);
60
61static int initvars_table (osl_t * osh, char *start, char *end, char **vars,
62               uint * count);
63static int initvars_flash (sb_t * sbh, osl_t * osh, char **vp, uint len);
64
65#ifdef BCMUSBDEV
66static int get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
67                   uint boff, uint16 * srom, uint bsz);
68static int set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
69                   uint boff, uint16 * srom, uint bsz);
70static uint srom_size (sb_t * sbh, osl_t * osh);
71#endif /* def BCMUSBDEV */
72
73/* Initialization of varbuf structure */
74static void
75varbuf_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 */
82static int
83varbuf_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 */
120int
121BCMINITFN (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 */
152int
153srom_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 */
223int
224srom_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 */
372static int
373srom_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 */
396static int
397srom_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 */
421static int
422srom_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 */
451static int
452get_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
487out:
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 */
495static int
496set_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
570out:
571  return err;
572}
573#endif /* def BCMUSBDEV */
574
575int
576srom_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 */
978static int
979sprom_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 */
999static int
1000sprom_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 */
1025static int
1026sprom_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 */
1051static int
1052sprom_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*/
1095static int
1096BCMINITFN (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 */
1126static int
1127initvars_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
1178exit: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 */
1187static int
1188initvars_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
1212char mfgsromvars[256];
1213char *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
1226typedef 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
1256static 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
1515static 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
1565static uint
1566mask_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
1578static uint
1579mask_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
1592static bool
1593mask_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
1601static 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
1741static int
1742initvars_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
1871varsdone:
1872  err = initvars_table (osh, base, vp, vars, count);
1873
1874errout:
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 */
1890static int
1891initvars_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
1924static int
1925BCMINITFN (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 */
2059static uint
2060srom_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 */
2105

Archive Download this file



interactive