2 * Routines to access SPROM and to parse SROM/CIS variables.
4 * Copyright 2007, Broadcom Corporation
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.
19 #include <bcmendian.h>
30 #define BS_ERROR(args) printf args
32 #define BS_ERROR(args)
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 */
40 char *buf; /* pointer to current position */
41 unsigned int size; /* current (residual) size in bytes */
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,
48 static int initvars_srom_pci (sb_t * sbh, void *curmap, char **vars,
50 static int initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars,
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);
61 static int initvars_table (osl_t * osh, char *start, char *end, char **vars,
63 static int initvars_flash (sb_t * sbh, osl_t * osh, char **vp, uint len);
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 */
73 /* Initialization of varbuf structure */
75 varbuf_init (varbuf_t * b, char *buf, uint size)
81 /* append a null terminated var=value string */
83 varbuf_append (varbuf_t * b, const char *fmt, ...)
92 r = vsnprintf (b->buf, b->size, fmt, ap);
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.
102 if ((r == -1) || (r > (int) (b->size - 2)))
108 /* skip over this string's null termination */
117 * Initialize local vars from the right source for this platform.
118 * Return 0 on success, nonzero on error.
121 BCMINITFN (srom_var_init) (sb_t * sbh, uint bustype, void *curmap,
122 osl_t * osh, char **vars, uint * count)
124 ASSERT (bustype == BUSTYPE (bustype));
125 if (vars == NULL || count == NULL)
131 switch (BUSTYPE (bustype))
135 return initvars_srom_sb (sbh, osh, curmap, vars, count);
138 ASSERT (curmap); /* can not be NULL */
139 return initvars_srom_pci (sbh, curmap, vars, count);
142 return initvars_cis_pcmcia (sbh, osh, vars, count);
151 /* support only 16-bit word read from srom */
153 srom_read (sb_t * sbh, uint bustype, void *curmap, osl_t * osh,
154 uint byteoff, uint nbytes, uint16 * buf)
159 ASSERT (bustype == BUSTYPE (bustype));
161 /* check input - 16-bit access only */
162 if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
168 if (BUSTYPE (bustype) == PCI_BUS)
172 srom = (uchar *) curmap + PCI_BAR0_SPROM_OFFSET;
173 if (sprom_read_pci (osh, srom, off, buf, nw, FALSE))
176 else if (BUSTYPE (bustype) == PCMCIA_BUS)
178 for (i = 0; i < nw; i++)
180 if (sprom_read_pcmcia
181 (osh, (uint16) (off + i), (uint16 *) (buf + i)))
185 else if (BUSTYPE (bustype) == SB_BUS)
188 if (SPROMBUS == PCMCIA_BUS)
195 origidx = sb_coreidx (sbh);
196 regs = sb_setcore (sbh, SB_PCMCIA, 0);
197 ASSERT (regs != NULL);
199 if (!(wasup = sb_iscoreup (sbh)))
200 sb_core_reset (sbh, 0, 0);
202 rc = get_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes);
205 sb_core_disable (sbh, 0);
207 sb_setcoreidx (sbh, origidx);
210 #endif /* def BCMUSBDEV */
222 /* support only 16-bit word write into srom */
224 srom_write (sb_t * sbh, uint bustype, void *curmap, osl_t * osh,
225 uint byteoff, uint nbytes, uint16 * buf)
228 uint i, nw, crc_range;
229 uint16 image[SPROM_SIZE];
231 volatile uint32 val32;
233 ASSERT (bustype == BUSTYPE (bustype));
235 /* check input - 16-bit access only */
236 if ((byteoff & 1) || (nbytes & 1))
239 if (byteoff == 0x55aa)
243 memset ((void *) image, 0xff, nbytes);
246 else if ((byteoff == 0) &&
247 ((nbytes == SPROM_SIZE * 2) ||
248 (nbytes == (SPROM_CRC_RANGE * 2)) ||
249 (nbytes == (SROM4_WORDS * 2))))
251 /* Are we writing the whole thing at once? */
253 bcopy ((void *) buf, (void *) image, nbytes);
258 if ((byteoff + nbytes) > (SPROM_SIZE * 2))
261 if (BUSTYPE (bustype) == PCMCIA_BUS)
263 crc_range = SPROM_SIZE * 2;
267 crc_range = SPROM_CRC_RANGE * 2; /* Tentative */
271 /* read first 64 words from srom */
272 if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image))
274 if (image[SROM4_SIGN] == SROM4_SIGNATURE)
278 if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image))
282 bcopy ((void *) buf, (void *) &image[byteoff / 2], nbytes);
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);
294 if (BUSTYPE (bustype) == PCI_BUS)
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);
303 for (i = 0; i < nw; i++)
305 W_REG (osh, &srom[i], image[i]);
306 bcm_mdelay (WRITE_WORD_DELAY);
308 /* disable writes to the SPROM */
309 OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32 &
312 else if (BUSTYPE (bustype) == PCMCIA_BUS)
314 /* enable writes to the SPROM */
315 if (sprom_cmd_pcmcia (osh, SROM_WEN))
317 bcm_mdelay (WRITE_ENABLE_DELAY);
319 for (i = 0; i < nw; i++)
321 sprom_write_pcmcia (osh, (uint16) (i), image[i]);
322 bcm_mdelay (WRITE_WORD_DELAY);
324 /* disable writes to the SPROM */
325 if (sprom_cmd_pcmcia (osh, SROM_WDS))
328 else if (BUSTYPE (bustype) == SB_BUS)
331 if (SPROMBUS == PCMCIA_BUS)
338 origidx = sb_coreidx (sbh);
339 regs = sb_setcore (sbh, SB_PCMCIA, 0);
340 ASSERT (regs != NULL);
342 if (!(wasup = sb_iscoreup (sbh)))
343 sb_core_reset (sbh, 0, 0);
345 rc = set_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes);
348 sb_core_disable (sbh, 0);
350 sb_setcoreidx (sbh, origidx);
353 #endif /* def BCMUSBDEV */
361 bcm_mdelay (WRITE_ENABLE_DELAY);
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)
371 /* set PCMCIA srom command register */
373 srom_cmd_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint8 cmd)
378 /* write srom command register */
379 SB_PCMCIA_WRITE (osh, pcmregs, SROM_CS, cmd);
382 while (++wait_cnt < 1000000)
384 status = SB_PCMCIA_READ (osh, pcmregs, SROM_CS);
385 if (status & SROM_DONE)
390 BS_ERROR (("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt,
395 /* read a word from the PCMCIA srom over SB */
397 srom_read_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 * data)
399 uint8 addr_l, addr_h, data_l, data_h;
401 addr_l = (uint8) ((addr * 2) & 0xff);
402 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
405 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h);
406 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l);
409 if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_READ))
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;
420 /* write a word to the PCMCIA srom over SB */
422 srom_write_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 data)
424 uint8 addr_l, addr_h, data_l, data_h;
427 addr_l = (uint8) ((addr * 2) & 0xff);
428 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
431 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h);
432 SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l);
434 data_l = (uint8) (data & 0xff);
435 data_h = (uint8) ((data >> 8) & 0xff);
438 SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAH, data_h);
439 SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAL, data_l);
442 rc = srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WRITE);
448 * Read the srom for the pcmcia-srom over sb case.
449 * Return 0 on success, nonzero on error.
452 get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
453 uint boff, uint16 * srom, uint bsz)
455 uint i, nw, woff, wsz;
458 /* read must be at word boundary */
459 ASSERT ((boff & 1) == 0 && (bsz & 1) == 0);
461 /* read sprom size and validate the parms */
462 if ((nw = srom_size (sbh, osh)) == 0)
464 BS_ERROR (("get_sb_pcmcia_srom: sprom size unknown\n"));
468 if (boff + bsz > 2 * nw)
470 BS_ERROR (("get_sb_pcmcia_srom: sprom size exceeded\n"));
475 /* read in sprom contents */
476 for (woff = boff / 2, wsz = bsz / 2, i = 0;
477 woff < nw && i < wsz; woff++, i++)
479 if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &srom[i]))
481 BS_ERROR (("get_sb_pcmcia_srom: sprom read failed\n"));
492 * Write the srom for the pcmcia-srom over sb case.
493 * Return 0 on success, nonzero on error.
496 set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
497 uint boff, uint16 * srom, uint bsz)
499 uint i, nw, woff, wsz;
504 /* write must be at word boundary */
505 ASSERT ((boff & 1) == 0 && (bsz & 1) == 0);
507 /* read sprom size and validate the parms */
508 if ((nw = srom_size (sbh, osh)) == 0)
510 BS_ERROR (("set_sb_pcmcia_srom: sprom size unknown\n"));
514 if (boff + bsz > 2 * nw)
516 BS_ERROR (("set_sb_pcmcia_srom: sprom size exceeded\n"));
522 if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WEN))
524 BS_ERROR (("set_sb_pcmcia_srom: sprom wen failed\n"));
529 /* write buffer to sprom */
530 for (woff = boff / 2, wsz = bsz / 2, i = 0;
531 woff < nw && i < wsz; woff++, i++)
533 if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) woff, srom[i]))
535 BS_ERROR (("set_sb_pcmcia_srom: sprom write failed\n"));
543 for (woff = 0; woff < nw; woff++)
545 if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &word))
547 BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc read failed\n"));
551 word = htol16 (word);
552 crc = hndcrc8 ((uint8 *) & word, woff != nw - 1 ? 2 : 1, crc);
554 word = (~crc << 8) + (ltoh16 (word) & 0xff);
555 if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) (woff - 1), word))
557 BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc write failed\n"));
563 if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WDS))
565 BS_ERROR (("set_sb_pcmcia_srom: sprom wds failed\n"));
573 #endif /* def BCMUSBDEV */
576 srom_parsecis (osl_t * osh, uint8 * pcis[], uint ciscnt, char **vars,
582 uint8 *cis, tup, tlen, sromrev = 1;
585 bool ag_init = FALSE;
594 base = MALLOC (osh, MAXSZ_NVRAM_VARS);
599 varbuf_init (&b, base, MAXSZ_NVRAM_VARS);
602 for (cisnum = 0; cisnum < ciscnt; cisnum++)
611 if ((i + tlen) >= CIS_SIZE)
617 /* assume the strings are good if the version field checks out */
618 if (((cis[i + 1] << 8) + cis[i]) >= 0x0008)
620 varbuf_append (&b, "manf=%s", &cis[i + 2]);
621 varbuf_append (&b, "productname=%s",
622 &cis[i + 3 + strlen ((char *) &cis[i + 2])]);
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]);
640 /* set macaddr if HNBU_MACADDR not seen yet */
641 if (eabuf[0] == '\0' && cis[i] == LAN_NID)
643 ASSERT (cis[i + 1] == ETHER_ADDR_LEN);
644 bcm_ether_ntoa ((struct ether_addr *) &cis[i + 2],
647 /* set boardnum if HNBU_BOARDNUM not seen yet */
649 boardnum = (cis[i + 6] << 8) + cis[i + 7];
655 varbuf_append (&b, "regwindowsz=%d",
656 (cis[i + 7] << 8) | cis[i + 6]);
659 case CISTPL_BRCM_HNBU:
663 sromrev = cis[i + 1];
664 varbuf_append (&b, "sromrev=%d", sromrev);
668 varbuf_append (&b, "vendid=0x%x", (cis[i + 2] << 8) +
670 varbuf_append (&b, "devid=0x%x", (cis[i + 4] << 8) +
674 varbuf_append (&b, "chiprev=%d",
675 (cis[i + 6] << 8) + cis[i + 5]);
679 varbuf_append (&b, "subvendid=0x%x",
680 (cis[i + 8] << 8) + cis[i + 7]);
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]);
693 varbuf_append (&b, "boardrev=0x%x", cis[i + 1]);
697 varbuf_append (&b, "aa2g=%d", cis[i + 1]);
701 varbuf_append (&b, "ag0=%d", cis[i + 1]);
706 varbuf_append (&b, "aa5g=%d", cis[i + 1]);
707 varbuf_append (&b, "ag1=%d", cis[i + 2]);
711 ASSERT (sromrev == 1);
712 varbuf_append (&b, "cc=%d", cis[i + 1]);
718 ASSERT (sromrev == 1);
719 varbuf_append (&b, "pa0maxpwr=%d", cis[i + 1]);
725 ASSERT (sromrev >= 2);
726 varbuf_append (&b, "opo=%d", cis[i + 9]);
731 for (j = 0; j < 3; j++)
733 varbuf_append (&b, "pa0b%d=%d", j,
734 (cis[i + (j * 2) + 2] << 8) +
735 cis[i + (j * 2) + 1]);
737 varbuf_append (&b, "pa0itssit=%d", cis[i + 7]);
738 varbuf_append (&b, "pa0maxpwr=%d", cis[i + 8]);
745 ASSERT ((sromrev == 2) || (sromrev == 3));
746 for (j = 0; j < 3; j++)
748 varbuf_append (&b, "pa1b%d=%d", j,
749 (cis[i + (j * 2) + 2] << 8) +
750 cis[i + (j * 2) + 1]);
752 for (j = 3; j < 6; j++)
754 varbuf_append (&b, "pa1lob%d=%d", j - 3,
755 (cis[i + (j * 2) + 2] << 8) +
756 cis[i + (j * 2) + 1]);
758 for (j = 6; j < 9; j++)
760 varbuf_append (&b, "pa1hib%d=%d", j - 6,
761 (cis[i + (j * 2) + 2] << 8) +
762 cis[i + (j * 2) + 1]);
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]);
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]);
779 case HNBU_BOARDFLAGS:
780 w32 = (cis[i + 2] << 8) + cis[i + 1];
782 w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16);
783 varbuf_append (&b, "boardflags=0x%x", w32);
787 if (cis[i + 1] != 0xff)
789 varbuf_append (&b, "ledbh0=%d", cis[i + 1]);
791 if (cis[i + 2] != 0xff)
793 varbuf_append (&b, "ledbh1=%d", cis[i + 2]);
795 if (cis[i + 3] != 0xff)
797 varbuf_append (&b, "ledbh2=%d", cis[i + 3]);
799 if (cis[i + 4] != 0xff)
801 varbuf_append (&b, "ledbh3=%d", cis[i + 4]);
806 ASSERT (sromrev > 1);
807 if ((cis[i + 1] == 0) || (cis[i + 2] == 0))
808 varbuf_append (&b, "ccode=");
810 varbuf_append (&b, "ccode=%c%c", cis[i + 1], cis[i + 2]);
811 varbuf_append (&b, "cctl=0x%x", cis[i + 3]);
815 ASSERT (sromrev > 2);
816 varbuf_append (&b, "cckpo=0x%x",
817 (cis[i + 2] << 8) | cis[i + 1]);
821 ASSERT (sromrev > 2);
822 varbuf_append (&b, "ofdmpo=0x%x",
825 (cis[i + 2] << 8) | cis[i + 1]);
829 varbuf_append (&b, "rdlid=0x%x",
830 (cis[i + 2] << 8) | cis[i + 1]);
834 varbuf_append (&b, "rdlrndis=%d", cis[i + 1]);
838 varbuf_append (&b, "rdlrwu=%d", cis[i + 1]);
842 varbuf_append (&b, "rdlsn=%d",
843 (cis[i + 2] << 8) | cis[i + 1]);
847 varbuf_append (&b, "xtalfreq=%d",
850 (cis[i + 2] << 8) | cis[i + 1]);
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);
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);
870 ASSERT (sromrev == 3);
871 varbuf_append (&b, "tri2g=%d", cis[i + 1]);
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]);
882 ASSERT (sromrev == 3);
883 varbuf_append (&b, "rxpo2g=%d", cis[i + 1]);
887 ASSERT (sromrev == 3);
888 varbuf_append (&b, "rxpo5g=%d", cis[i + 1]);
892 boardnum = (cis[i + 2] << 8) + cis[i + 1];
896 bcm_ether_ntoa ((struct ether_addr *) &cis[i + 1], eabuf);
900 varbuf_append (&b, "boardtype=0x%x",
901 (cis[i + 2] << 8) + cis[i + 1]);
904 #if defined(BCMCCISSR3)
905 case HNBU_SROM3SWRGN:
908 uint8 srev = cis[i + 1 + 70];
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 */
922 /* Ethernet MAC address is included in SROM */
933 while (tup != CISTPL_END);
938 varbuf_append (&b, "boardnum=%d", boardnum);
943 varbuf_append (&b, "macaddr=%s", eabuf);
946 /* if there is no antenna gain field, set default */
947 if (ag_init == FALSE)
949 varbuf_append (&b, "ag0=%d", 0xff);
952 /* final nullbyte terminator */
953 ASSERT (b.size >= 1);
955 varsize = (uint) (b.buf - base);
956 ASSERT (varsize < MAXSZ_NVRAM_VARS);
957 if (varsize < MAXSZ_NVRAM_VARS)
960 new_buf = (char *) MALLOC (osh, varsize);
964 bcopy (base, new_buf, varsize);
965 MFREE (osh, base, MAXSZ_NVRAM_VARS);
977 /* set PCMCIA sprom command register */
979 sprom_cmd_pcmcia (osl_t * osh, uint8 cmd)
982 uint wait_cnt = 1000;
984 /* write sprom command register */
985 OSL_PCMCIA_WRITE_ATTR (osh, SROM_CS, &cmd, 1);
990 OSL_PCMCIA_READ_ATTR (osh, SROM_CS, &status, 1);
991 if (status & SROM_DONE)
998 /* read a word from the PCMCIA srom */
1000 sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data)
1002 uint8 addr_l, addr_h, data_l, data_h;
1004 addr_l = (uint8) ((addr * 2) & 0xff);
1005 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
1008 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1);
1009 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1);
1012 if (sprom_cmd_pcmcia (osh, SROM_READ))
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);
1020 *data = (data_h << 8) | data_l;
1024 /* write a word to the PCMCIA srom */
1026 sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data)
1028 uint8 addr_l, addr_h, data_l, data_h;
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);
1036 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1);
1037 OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1);
1040 OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAH, &data_h, 1);
1041 OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAL, &data_l, 1);
1044 return sprom_cmd_pcmcia (osh, SROM_WRITE);
1048 * Read in and validate sprom.
1049 * Return 0 on success, nonzero on error.
1052 sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff, uint16 * buf,
1053 uint nwords, bool check_crc)
1058 /* read the sprom */
1059 for (i = 0; i < nwords; i++)
1062 buf[i] = R_REG (osh, &sprom[wordoff + i]);
1064 buf[i] = R_REG (osh, &sprom[wordoff + i]);
1069 if (buf[0] == 0xffff)
1071 /* The hardware thinks that an srom that starts with 0xffff
1072 * is blank, regardless of the rest of the content, so declare
1075 BS_ERROR (("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__,
1080 /* fixup the endianness so crc8 will pass */
1081 htol16_buf (buf, nwords * 2);
1082 if (hndcrc8 ((uint8 *) buf, nwords * 2, 0xff) != 0x9f)
1084 /* now correct the endianness of the byte array */
1085 ltoh16_buf (buf, nwords * 2);
1092 * Create variable table from memory.
1093 * Return 0 on success, nonzero on error.
1096 BCMINITFN (initvars_table) (osl_t * osh, char *start, char *end, char **vars,
1099 int c = (int) (end - start);
1101 /* do it only when there is more than just the null string */
1104 char *vp = MALLOC (osh, c);
1108 bcopy (start, vp, c);
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.
1127 initvars_flash (sb_t * sbh, osl_t * osh, char **base, uint len)
1133 uint l, dl, copy_len;
1134 char devpath[SB_DEVPATH_BUFSZ];
1136 /* allocate memory and read in flash */
1137 if (!(flash = MALLOC (osh, NVRAM_SPACE)))
1139 if ((err = nvram_getall (flash, NVRAM_SPACE)))
1142 sb_devpath (sbh, devpath, sizeof (devpath));
1144 /* grab vars with the <devpath> prefix in name */
1145 dl = strlen (devpath);
1146 for (s = flash; s && *s; s += l + 1)
1150 /* skip non-matching variable */
1151 if (strncmp (s, devpath, dl))
1154 /* is there enough room to copy? */
1155 copy_len = l - dl + 1;
1158 err = BCME_BUFTOOSHORT;
1162 /* no prefix, just the name=value */
1163 strncpy (vp, &s[dl], copy_len);
1168 /* add null string as terminator */
1171 err = BCME_BUFTOOSHORT;
1178 exit:MFREE (osh, flash, NVRAM_SPACE);
1182 #if !defined(BCMUSBDEV) && !defined(BCMSDIODEV)
1184 * Initialize nonvolatile variable table from flash.
1185 * Return 0 on success, nonzero on error.
1188 initvars_flash_sb (sb_t * sbh, char **vars, uint * count)
1190 osl_t *osh = sb_osh (sbh);
1197 base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS);
1202 if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)) == 0)
1203 err = initvars_table (osh, base, vp, vars, count);
1205 MFREE (osh, base, MAXSZ_NVRAM_VARS);
1209 #endif /* !BCMUSBDEV && !BCMSDIODEV */
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 */
1222 * Initialize nonvolatile variable table from sprom.
1223 * Return 0 on success, nonzero on error.
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 */
1244 * - Ethernet address spins across 3 consective words
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.
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},
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},
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).
1566 mask_shift (uint16 mask)
1569 for (i = 0; i < (sizeof (mask) << 3); i++)
1571 if (mask & (1 << i))
1579 mask_width (uint16 mask)
1582 for (i = (sizeof (mask) << 3) - 1; i >= 0; i--)
1584 if (mask & (1 << i))
1585 return (uint) (i - mask_shift (mask) + 1);
1591 #ifdef BCMDBG_ASSERT
1593 mask_valid (uint16 mask)
1595 uint shift = mask_shift (mask);
1596 uint width = mask_width (mask);
1597 return mask == ((~0 << shift) & ~(~0 << (shift + width)));
1602 _initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off, varbuf_t * b)
1606 const sromvar_t *srv;
1609 uint32 sr = (1 << sromrev);
1611 varbuf_append (b, "sromrev=%d", sromrev);
1613 for (srv = pci_sromvars; srv->name != NULL; srv++)
1617 if ((srv->revmask & sr) == 0)
1626 if (flags & SRFL_ETHADDR)
1628 char eabuf[ETHER_ADDR_STR_LEN];
1629 struct ether_addr ea;
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);
1639 varbuf_append (b, "%s=%s", name, eabuf);
1643 ASSERT (mask_valid (srv->mask));
1644 ASSERT (mask_width (srv->mask));
1646 w = srom[srv->off - off];
1647 val = (w & srv->mask) >> mask_shift (srv->mask);
1648 width = mask_width (srv->mask);
1650 while (srv->flags & SRFL_MORE)
1655 if (srv->off == 0 || srv->off < off)
1658 ASSERT (mask_valid (srv->mask));
1659 ASSERT (mask_width (srv->mask));
1661 w = srom[srv->off - off];
1662 val += ((w & srv->mask) >> mask_shift (srv->mask)) << width;
1663 width += mask_width (srv->mask);
1666 if ((flags & SRFL_NOFFS) && ((int) val == (1 << width) - 1))
1669 if (flags & SRFL_CCODE)
1672 varbuf_append (b, "ccode=");
1674 varbuf_append (b, "ccode=%c%c", (val >> 8), (val & 0xff));
1676 /* LED Powersave duty cycle has to be scaled:
1677 *(oncount >> 24) (offcount >> 8)
1679 else if (flags & SRFL_LEDDC)
1681 uint32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */
1682 (((val & 0xff)) << 8); /* offcount */
1683 varbuf_append (b, "leddc=%d", w32);
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)));
1690 varbuf_append (b, "%s=%u", name, val);
1696 /* Do per-path variables */
1702 psz = SROM8_PATH1 - SROM8_PATH0;
1707 psz = SROM4_PATH1 - SROM4_PATH0;
1710 for (p = 0; p < MAX_PATH; p++)
1712 for (srv = perpath_pci_sromvars; srv->name != NULL; srv++)
1714 if ((srv->revmask & sr) == 0)
1717 if (pb + srv->off < off)
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);
1725 /* Cheating: no per-path var is more than 1 word */
1727 if ((srv->flags & SRFL_NOFFS)
1728 && ((int) val == (1 << width) - 1))
1731 if (srv->flags & SRFL_PRHEX)
1732 varbuf_append (b, "%s%d=0x%x", srv->name, p, val);
1734 varbuf_append (b, "%s%d=%d", srv->name, p, val);
1742 initvars_srom_pci (sb_t * sbh, void *curmap, char **vars, uint * count)
1748 char *vp, *base = NULL;
1749 osl_t *osh = sb_osh (sbh);
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
1760 srom = MALLOC (osh, SROM_MAX);
1766 sprom_read_pci (osh, (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET),
1767 0, srom, SROM_WORDS, TRUE);
1769 if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
1770 ((sbh->buscoretype == SB_PCIE) && (sbh->buscorerev >= 6)))
1772 /* sromrev >= 4, read more */
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;
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)
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)
1798 BS_ERROR (("srom crc failed with OTP, use default vars....\n"));
1799 vp = base = mfgsromvars;
1800 if (sb_chip (sbh) == BCM4311_CHIP_ID)
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;
1808 bcopy (defaultsromvars, vp, MFGSROM_DEFVARSLEN);
1809 vp += MFGSROM_DEFVARSLEN;
1815 BS_ERROR (("srom crc failed with SPROM....\n"));
1816 if (!(value = sb_getdevpathvar (sbh, "sromrev")))
1821 sromrev = (uint8) simple_strtoul (value, NULL, 0);
1828 /* Bitmask for the sromrev */
1831 /* srom version check
1832 * Current valid versions: 1, 2, 3, 4, 5, 8
1834 if ((sr & 0x13e) == 0)
1843 base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS);
1851 /* read variables from flash */
1854 if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)))
1859 varbuf_init (&b, base, MAXSZ_NVRAM_VARS);
1861 /* parse SROM into name=value pairs. */
1862 _initvars_srom_pci (sromrev, srom, 0, &b);
1864 /* final nullbyte terminator */
1865 ASSERT (b.size >= 1);
1869 ASSERT ((vp - base) <= MAXSZ_NVRAM_VARS);
1872 err = initvars_table (osh, base, vp, vars, count);
1876 if (base && (base != mfgsromvars))
1880 MFREE (osh, base, MAXSZ_NVRAM_VARS);
1882 MFREE (osh, srom, SROM_MAX);
1887 * Read the cis and call parsecis to initialize the vars.
1888 * Return 0 on success, nonzero on error.
1891 initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars, uint * count)
1897 data_sz = (sb_pcmciarev (sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
1899 if ((cis = MALLOC (osh, data_sz)) == NULL)
1902 if (sb_pcmciarev (sbh) == 1)
1905 (sbh, PCMCIA_BUS, (void *) NULL, osh, 0, data_sz, (uint16 *) cis))
1907 MFREE (osh, cis, data_sz);
1910 /* fix up endianess for 16-bit data vs 8-bit parsing */
1911 htol16_buf ((uint16 *) cis, data_sz);
1914 OSL_PCMCIA_READ_ATTR (osh, 0, cis, data_sz);
1916 rc = srom_parsecis (osh, &cis, 1, vars, count);
1918 MFREE (osh, cis, data_sz);
1925 BCMINITFN (initvars_srom_sb) (sb_t * sbh, osl_t * osh, void *curmap,
1926 char **vars, uint * varsz)
1928 #if defined(BCMSDIODEV)
1929 /* CIS is read and supplied by the host */
1931 #elif defined(BCMUSBDEV)
1932 static bool srvars = FALSE; /* Use OTP/SPROM as global variables */
1934 int sel = 0; /* where to read the srom. 0 - nowhere, 1 - otp, 2 - sprom */
1935 uint sz = 0; /* srom size in bytes */
1939 /* Bail out if we've dealt with OTP/SPROM before! */
1943 #if defined(BCM4328)
1944 if (sbh->chip == BCM4328_CHIP_ID)
1946 /* Access the SPROM if it is present */
1947 if ((sz = srom_size (sbh, osh)) != 0)
1954 #if defined(BCM4325)
1955 if (sbh->chip == BCM4325_CHIP_ID)
1957 uint32 cst = sbh->chipst & CST4325_SPROM_OTP_SEL_MASK;
1959 /* Access OTP if it is present, powered on, and programmed */
1960 if ((oh = otp_init (sbh)) != NULL && (otp_status (oh) & OTPS_GUP_SW))
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)
1973 #endif /* BCM4325 */
1975 /* Read CIS in OTP/SPROM */
1983 /* Allocate memory */
1984 if ((srom = (uint16 *) MALLOC (osh, sz)) == NULL)
1991 rc = otp_read_region (oh, OTP_SW_RGN, srom, sz);
1992 body = (uint8 *) srom;
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;
2000 /* impossible to come here */
2008 uint i, tpls = 0xffffffff;
2009 /* # sdiod fns + common + extra */
2010 uint8 *cis[SBSDIO_NUM_FUNCTION + 2];
2013 /* each word is in host endian */
2014 htol16_buf ((uint8 *) srom, sz);
2018 /* count cis tuple chains */
2019 for (i = 0; i < sz && ciss < ARRAYSIZE (cis) && tpls != 0; i++)
2021 cis[ciss++] = &body[i];
2022 for (tpls = 0; i < sz - 1; tpls++)
2024 if (body[i++] == CISTPL_END)
2030 /* call parser routine only when there are tuple chains */
2032 rc = srom_parsecis (osh, cis, ciss, vars, varsz);
2036 MFREE (osh, srom, sz);
2038 /* Make SROM variables global */
2041 rc = nvram_append ((void *) sbh, *vars, *varsz);
2044 /* Tell the caller there is no individual SROM variables */
2051 #else /* !BCMUSBDEV && !BCMSDIODEV */
2052 /* Search flash nvram section for srom variables */
2053 return initvars_flash_sb (sbh, vars, varsz);
2054 #endif /* !BCMUSBDEV && !BCMSDIODEV */
2058 /* Return sprom size in 16-bit words */
2060 srom_size (sb_t * sbh, osl_t * osh)
2063 if (SPROMBUS == PCMCIA_BUS)
2066 sdpcmd_regs_t *pcmregs;
2069 origidx = sb_coreidx (sbh);
2070 pcmregs = sb_setcore (sbh, SB_PCMCIA, 0);
2073 if (!(wasup = sb_iscoreup (sbh)))
2074 sb_core_reset (sbh, 0, 0);
2076 /* not worry about earlier core revs */
2077 if (sb_corerev (sbh) < 8)
2080 /* SPROM is accessible only in PCMCIA mode unless there is SDIO clock */
2081 if (!(R_REG (osh, &pcmregs->corestatus) & CS_PCMCIAMODE))
2084 switch (SB_PCMCIA_READ (osh, pcmregs, SROM_INFO) & SRI_SZ_MASK)
2087 size = 256; /* SROM_INFO == 1 means 4kbit */
2090 size = 1024; /* SROM_INFO == 2 means 16kbit */
2098 sb_core_disable (sbh, 0);
2100 sb_setcoreidx (sbh, origidx);
2104 #endif /* def BCMUSBDEV */