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