2 * Misc useful routines to access NIC SROM/OTP .
4 * Copyright 2004, 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.
21 #include <bcmendian.h>
31 #if defined(CONFIG_BCMUSBDEV)
34 #include <sbsdpcmdev.h>
40 #include <proto/ethernet.h> /* for sprom content groking */
44 #define BS_ERROR(args) printf args
46 #define BS_ERROR(args)
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 */
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
,
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
);
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 */
83 varbuf_init(varbuf_t
*b
, char *buf
, uint size
)
89 /* append a null terminated var=value string */
91 varbuf_append(varbuf_t
*b
, const char *fmt
, ...)
100 r
= vsnprintf(b
->buf
, b
->size
, fmt
, 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))) {
115 /* skip over this string's null termination */
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
)
138 switch (BUSTYPE(bustype
)) {
141 return initvars_srom_sb(sbh
, osh
, curmap
, vars
, count
);
144 ASSERT(curmap
); /* can not be NULL */
145 return initvars_srom_pci(sbh
, curmap
, vars
, count
);
148 return initvars_cis_pcmcia(sbh
, osh
, vars
, count
);
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
)
165 ASSERT(bustype
== BUSTYPE(bustype
));
167 /* check input - 16-bit access only */
168 if (byteoff
& 1 || nbytes
& 1 || (byteoff
+ nbytes
) > (SPROM_SIZE
* 2))
174 if (BUSTYPE(bustype
) == PCI_BUS
) {
177 srom
= (uchar
*)curmap
+ PCI_BAR0_SPROM_OFFSET
;
178 if (sprom_read_pci(osh
, srom
, off
, buf
, nw
, FALSE
))
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
)))
185 } else if (BUSTYPE(bustype
) == SB_BUS
) {
187 if (SPROMBUS
== PCMCIA_BUS
) {
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
);
203 sb_core_disable(sbh
, 0);
205 sb_setcoreidx(sbh
, origidx
);
208 #endif /* def BCMUSBDEV */
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
)
224 uint i
, nw
, crc_range
;
225 uint16 image
[SPROM_SIZE
];
227 volatile uint32 val32
;
229 ASSERT(bustype
== BUSTYPE(bustype
));
231 /* check input - 16-bit access only */
232 if ((byteoff
& 1) || (nbytes
& 1))
235 if (byteoff
== 0x55aa) {
238 memset((void *)image
, 0xff, nbytes
);
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? */
246 bcopy((void *)buf
, (void *)image
, nbytes
);
249 if ((byteoff
+ nbytes
) > (SPROM_SIZE
* 2))
252 if (BUSTYPE(bustype
) == PCMCIA_BUS
) {
253 crc_range
= SPROM_SIZE
* 2;
256 crc_range
= SPROM_CRC_RANGE
* 2; /* Tentative */
260 /* read first 64 words from srom */
261 if (srom_read(sbh
, bustype
, curmap
, osh
, 0, crc_range
, image
))
263 if (image
[SROM4_SIGN
] == SROM4_SIGNATURE
) {
266 if (srom_read(sbh
, bustype
, curmap
, osh
, 0, crc_range
, image
))
270 bcopy((void *)buf
, (void *)&image
[byteoff
/ 2], nbytes
);
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
);
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
&
296 } else if (BUSTYPE(bustype
) == PCMCIA_BUS
) {
297 /* enable writes to the SPROM */
298 if (sprom_cmd_pcmcia(osh
, SROM_WEN
))
300 bcm_mdelay(WRITE_ENABLE_DELAY
);
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
))
309 } else if (BUSTYPE(bustype
) == SB_BUS
) {
311 if (SPROMBUS
== PCMCIA_BUS
) {
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
);
327 sb_core_disable(sbh
, 0);
329 sb_setcoreidx(sbh
, origidx
);
332 #endif /* def BCMUSBDEV */
338 bcm_mdelay(WRITE_ENABLE_DELAY
);
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 */
350 srom_cmd_sb_pcmcia(osl_t
*osh
, uint8
*pcmregs
, uint8 cmd
)
355 /* write srom command register */
356 SB_PCMCIA_WRITE(osh
, pcmregs
, SROM_CS
, cmd
);
359 while (++wait_cnt
< 1000000) {
360 status
= SB_PCMCIA_READ(osh
, pcmregs
, SROM_CS
);
361 if (status
& SROM_DONE
)
366 BS_ERROR(("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt
, status
));
370 /* read a word from the PCMCIA srom over SB */
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);
380 SB_PCMCIA_WRITE(osh
, pcmregs
, SROM_ADDRH
, addr_h
);
381 SB_PCMCIA_WRITE(osh
, pcmregs
, SROM_ADDRL
, addr_l
);
384 if (srom_cmd_sb_pcmcia(osh
, pcmregs
, SROM_READ
))
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
;
395 /* write a word to the PCMCIA srom over SB */
397 srom_write_sb_pcmcia(osl_t
*osh
, uint8
*pcmregs
, uint16 addr
, uint16 data
)
399 uint8 addr_l
, addr_h
, data_l
, data_h
;
402 addr_l
= (uint8
)((addr
* 2) & 0xff);
403 addr_h
= (uint8
)(((addr
* 2) >> 8) & 0xff);
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);
413 SB_PCMCIA_WRITE(osh
, pcmregs
, SROM_DATAH
, data_h
);
414 SB_PCMCIA_WRITE(osh
, pcmregs
, SROM_DATAL
, data_l
);
417 rc
= srom_cmd_sb_pcmcia(osh
, pcmregs
, SROM_WRITE
);
423 * Read the srom for the pcmcia-srom over sb case.
424 * Return 0 on success, nonzero on error.
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
;
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"));
442 if (boff
+ bsz
> 2 * nw
) {
443 BS_ERROR(("get_sb_pcmcia_srom: sprom size exceeded\n"));
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"));
463 * Write the srom for the pcmcia-srom over sb case.
464 * Return 0 on success, nonzero on error.
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
;
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"));
484 if (boff
+ bsz
> 2 * nw
) {
485 BS_ERROR(("set_sb_pcmcia_srom: sprom size exceeded\n"));
491 if (srom_cmd_sb_pcmcia(osh
, pcmregs
, SROM_WEN
)) {
492 BS_ERROR(("set_sb_pcmcia_srom: sprom wen failed\n"));
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"));
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"));
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"));
526 if (srom_cmd_sb_pcmcia(osh
, pcmregs
, SROM_WDS
)) {
527 BS_ERROR(("set_sb_pcmcia_srom: sprom wds failed\n"));
535 #endif /* def BCMUSBDEV */
538 srom_parsecis(osl_t
*osh
, uint8
*pcis
[], uint ciscnt
, char **vars
, uint
*count
)
543 uint8
*cis
, tup
, tlen
, sromrev
= 1;
546 bool ag_init
= FALSE
;
555 base
= MALLOC(osh
, MAXSZ_NVRAM_VARS
);
560 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
563 for (cisnum
= 0; cisnum
< ciscnt
; cisnum
++) {
570 if ((i
+ tlen
) >= CIS_SIZE
)
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])]);
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]);
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],
601 /* set boardnum if HNBU_BOARDNUM not seen yet */
603 boardnum
= (cis
[i
+ 6] << 8) + cis
[i
+ 7];
609 varbuf_append(&b
, "regwindowsz=%d", (cis
[i
+ 7] << 8) | cis
[i
+ 6]);
612 case CISTPL_BRCM_HNBU
:
615 sromrev
= cis
[i
+ 1];
616 varbuf_append(&b
, "sromrev=%d", sromrev
);
620 varbuf_append(&b
, "vendid=0x%x", (cis
[i
+ 2] << 8) +
622 varbuf_append(&b
, "devid=0x%x", (cis
[i
+ 4] << 8) +
625 varbuf_append(&b
, "chiprev=%d",
626 (cis
[i
+ 6] << 8) + cis
[i
+ 5]);
629 varbuf_append(&b
, "subvendid=0x%x",
630 (cis
[i
+ 8] << 8) + cis
[i
+ 7]);
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]);
642 varbuf_append(&b
, "boardrev=0x%x", cis
[i
+ 1]);
646 varbuf_append(&b
, "aa2g=%d", cis
[i
+ 1]);
650 varbuf_append(&b
, "ag0=%d", cis
[i
+ 1]);
655 varbuf_append(&b
, "aa5g=%d", cis
[i
+ 1]);
656 varbuf_append(&b
, "ag1=%d", cis
[i
+ 2]);
660 ASSERT(sromrev
== 1);
661 varbuf_append(&b
, "cc=%d", cis
[i
+ 1]);
666 ASSERT(sromrev
== 1);
667 varbuf_append(&b
, "pa0maxpwr=%d", cis
[i
+ 1]);
668 } else if (tlen
>= 9) {
670 ASSERT(sromrev
>= 2);
671 varbuf_append(&b
, "opo=%d", cis
[i
+ 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]);
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]);
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]);
718 case HNBU_BOARDFLAGS
:
719 w32
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
721 w32
|= (cis
[i
+ 4] << 24) + (cis
[i
+ 3] << 16);
722 varbuf_append(&b
, "boardflags=0x%x", w32
);
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]);
742 if ((cis
[i
+ 1] == 0) || (cis
[i
+ 2] == 0))
743 varbuf_append(&b
, "ccode=");
745 varbuf_append(&b
, "ccode=%c%c",
746 cis
[i
+ 1], cis
[i
+ 2]);
747 varbuf_append(&b
, "cctl=0x%x", cis
[i
+ 3]);
752 varbuf_append(&b
, "cckpo=0x%x",
753 (cis
[i
+ 2] << 8) | cis
[i
+ 1]);
758 varbuf_append(&b
, "ofdmpo=0x%x",
766 varbuf_append(&b
, "rdlid=0x%x",
767 (cis
[i
+ 2] << 8) | cis
[i
+ 1]);
771 varbuf_append(&b
, "rdlrndis=%d", cis
[i
+ 1]);
775 varbuf_append(&b
, "rdlrwu=%d", cis
[i
+ 1]);
779 varbuf_append(&b
, "rdlsn=%d",
780 (cis
[i
+ 2] << 8) | cis
[i
+ 1]);
784 varbuf_append(&b
, "xtalfreq=%d",
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);
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);
808 ASSERT(sromrev
== 3);
809 varbuf_append(&b
, "tri2g=%d", cis
[i
+ 1]);
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]);
820 ASSERT(sromrev
== 3);
821 varbuf_append(&b
, "rxpo2g=%d", cis
[i
+ 1]);
825 ASSERT(sromrev
== 3);
826 varbuf_append(&b
, "rxpo5g=%d", cis
[i
+ 1]);
830 boardnum
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
834 bcm_ether_ntoa((struct ether_addr
*)&cis
[i
+ 1],
839 varbuf_append(&b
, "boardtype=0x%x",
840 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
843 #if defined(CONFIG_BCMCCISSR3)
844 case HNBU_SROM3SWRGN
: {
846 uint8 srev
= cis
[i
+ 1 + 70];
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 */
860 /* Ethernet MAC address is included in SROM */
870 } while (tup
!= CISTPL_END
);
873 if (boardnum
!= -1) {
874 varbuf_append(&b
, "boardnum=%d", boardnum
);
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 */
889 varsize
= (uint
)(b
.buf
- base
);
890 ASSERT(varsize
< MAXSZ_NVRAM_VARS
);
891 if (varsize
< MAXSZ_NVRAM_VARS
) {
893 new_buf
= (char*)MALLOC(osh
, varsize
);
896 bcopy(base
, new_buf
, varsize
);
897 MFREE(osh
, base
, MAXSZ_NVRAM_VARS
);
909 /* set PCMCIA sprom command register */
911 sprom_cmd_pcmcia(osl_t
*osh
, uint8 cmd
)
914 uint wait_cnt
= 1000;
916 /* write sprom command register */
917 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_CS
, &cmd
, 1);
921 OSL_PCMCIA_READ_ATTR(osh
, SROM_CS
, &status
, 1);
922 if (status
& SROM_DONE
)
929 /* read a word from the PCMCIA srom */
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);
939 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRH
, &addr_h
, 1);
940 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRL
, &addr_l
, 1);
943 if (sprom_cmd_pcmcia(osh
, SROM_READ
))
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
;
955 /* write a word to the PCMCIA srom */
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);
967 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRH
, &addr_h
, 1);
968 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRL
, &addr_l
, 1);
971 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_DATAH
, &data_h
, 1);
972 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_DATAL
, &data_l
, 1);
975 return sprom_cmd_pcmcia(osh
, SROM_WRITE
);
979 * Read in and validate sprom.
980 * Return 0 on success, nonzero on error.
983 sprom_read_pci(osl_t
*osh
, uint16
*sprom
, uint wordoff
, uint16
*buf
, uint nwords
, bool check_crc
)
989 for (i
= 0; i
< nwords
; i
++) {
991 buf
[i
] = R_REG(osh
, &sprom
[wordoff
+ i
]);
993 buf
[i
] = R_REG(osh
, &sprom
[wordoff
+ i
]);
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
1002 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__
, buf
[0]));
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
)
1010 /* now correct the endianness of the byte array */
1011 ltoh16_buf(buf
, nwords
* 2);
1018 * Create variable table from memory.
1019 * Return 0 on success, nonzero on error.
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 */
1028 char *vp
= MALLOC(osh
, c
);
1032 bcopy(start
, vp
, c
);
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.
1050 initvars_flash(sb_t
*sbh
, osl_t
*osh
, char **base
, uint len
)
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
)))
1062 if ((err
= nvram_getall(flash
, NVRAM_SPACE
)))
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) {
1072 /* skip non-matching variable */
1073 if (strncmp(s
, devpath
, dl
))
1076 /* is there enough room to copy? */
1077 copy_len
= l
- dl
+ 1;
1078 if (len
< copy_len
) {
1079 err
= BCME_BUFTOOSHORT
;
1083 /* no prefix, just the name=value */
1084 strncpy(vp
, &s
[dl
], copy_len
);
1089 /* add null string as terminator */
1091 err
= BCME_BUFTOOSHORT
;
1098 exit
: MFREE(osh
, flash
, NVRAM_SPACE
);
1102 #if !defined(CONFIG_BCMUSBDEV) && !defined(CONFIG_BCMSDIODEV)
1104 * Initialize nonvolatile variable table from flash.
1105 * Return 0 on success, nonzero on error.
1108 initvars_flash_sb(sb_t
*sbh
, char **vars
, uint
*count
)
1110 osl_t
*osh
= sb_osh(sbh
);
1117 base
= vp
= MALLOC(osh
, MAXSZ_NVRAM_VARS
);
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
);
1129 #endif /* !BCMUSBDEV && !BCMSDIODEV */
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"
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.
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 */
1167 * - Ethernet address spins across 3 consective words
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},
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},
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).
1489 mask_shift(uint16 mask
)
1492 for (i
= 0; i
< (sizeof(mask
) << 3); i
++) {
1493 if (mask
& (1 << i
))
1501 mask_width(uint16 mask
)
1504 for (i
= (sizeof(mask
) << 3) - 1; i
>= 0; i
--) {
1505 if (mask
& (1 << i
))
1506 return (uint
)(i
- mask_shift(mask
) + 1);
1512 #ifdef BCMDBG_ASSERT
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
)));
1523 _initvars_srom_pci(uint8 sromrev
, uint16
*srom
, uint off
, varbuf_t
*b
)
1527 const sromvar_t
*srv
;
1530 uint32 sr
= (1 << sromrev
);
1532 varbuf_append(b
, "sromrev=%d", sromrev
);
1534 for (srv
= pci_sromvars
; srv
->name
!= NULL
; srv
++) {
1537 if ((srv
->revmask
& sr
) == 0)
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
);
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
) {
1572 if (srv
->off
== 0 || srv
->off
< off
)
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))
1586 if (flags
& SRFL_CCODE
) {
1588 varbuf_append(b
, "ccode=");
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
)));
1605 varbuf_append(b
, "%s=%u", name
, val
);
1610 /* Do per-path variables */
1615 psz
= SROM8_PATH1
- SROM8_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)
1626 if (pb
+ srv
->off
< off
)
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))
1639 if (srv
->flags
& SRFL_PRHEX
)
1640 varbuf_append(b
, "%s%d=0x%x", srv
->name
, p
, val
);
1642 varbuf_append(b
, "%s%d=%d", srv
->name
, p
, val
);
1650 initvars_srom_pci(sb_t
*sbh
, void *curmap
, char **vars
, uint
*count
)
1656 char *vp
, *base
= NULL
;
1657 osl_t
*osh
= sb_osh(sbh
);
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
1668 srom
= MALLOC(osh
, SROM_MAX
);
1673 err
= sprom_read_pci(osh
, (void *)((int8
*)curmap
+ PCI_BAR0_SPROM_OFFSET
), 0, srom
,
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)
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
;
1712 BS_ERROR(("srom crc failed with SPROM....\n"));
1713 if (!(value
= sb_getdevpathvar(sbh
, "sromrev"))) {
1717 sromrev
= (uint8
)bcm_strtoul(value
, NULL
, 0);
1724 /* Bitmask for the sromrev */
1727 /* srom version check
1728 * Current valid versions: 1, 2, 3, 4, 5, 8
1730 if ((sr
& 0x13e) == 0) {
1738 base
= vp
= MALLOC(osh
, MAXSZ_NVRAM_VARS
);
1745 /* read variables from flash */
1747 if ((err
= initvars_flash(sbh
, osh
, &vp
, MAXSZ_NVRAM_VARS
)))
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);
1762 ASSERT((vp
- base
) <= MAXSZ_NVRAM_VARS
);
1765 err
= initvars_table(osh
, base
, vp
, vars
, count
);
1769 if (base
&& (base
!= mfgsromvars
))
1773 MFREE(osh
, base
, MAXSZ_NVRAM_VARS
);
1775 MFREE(osh
, srom
, SROM_MAX
);
1780 * Read the cis and call parsecis to initialize the vars.
1781 * Return 0 on success, nonzero on error.
1784 initvars_cis_pcmcia(sb_t
*sbh
, osl_t
*osh
, char **vars
, uint
*count
)
1790 data_sz
= (sb_pcmciarev(sbh
) == 1) ? (SPROM_SIZE
* 2) : CIS_SIZE
;
1792 if ((cis
= MALLOC(osh
, data_sz
)) == NULL
)
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
);
1800 /* fix up endianess for 16-bit data vs 8-bit parsing */
1801 htol16_buf((uint16
*)cis
, data_sz
);
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
);
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 */
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 */
1827 /* Bail out if we've dealt with OTP/SPROM before! */
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) {
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
)) {
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) {
1856 #endif /* BCM4325 */
1858 /* Read CIS in OTP/SPROM */
1865 /* Allocate memory */
1866 if ((srom
= (uint16
*)MALLOC(osh
, sz
)) == NULL
)
1872 rc
= otp_read_region(oh
, OTP_SW_RGN
, srom
, sz
);
1873 body
= (uint8
*)srom
;
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
;
1881 /* impossible to come here */
1887 if (rc
== BCME_OK
) {
1888 uint i
, tpls
= 0xffffffff;
1889 /* # sdiod fns + common + extra */
1890 uint8
*cis
[SBSDIO_NUM_FUNCTION
+ 2];
1893 /* each word is in host endian */
1894 htol16_buf((uint8
*)srom
, sz
);
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
)
1908 /* call parser routine only when there are tuple chains */
1910 rc
= srom_parsecis(osh
, cis
, ciss
, vars
, varsz
);
1914 MFREE(osh
, srom
, sz
);
1916 /* Make SROM variables global */
1917 if (rc
== BCME_OK
) {
1918 rc
= nvram_append((void *)sbh
, *vars
, *varsz
);
1921 /* Tell the caller there is no individual SROM variables */
1928 #else /* !BCMUSBDEV && !BCMSDIODEV */
1929 /* Search flash nvram section for srom variables */
1930 return initvars_flash_sb(sbh
, vars
, varsz
);
1931 #endif /* !BCMUSBDEV && !BCMSDIODEV */
1935 /* Return sprom size in 16-bit words */
1937 srom_size(sb_t
*sbh
, osl_t
*osh
)
1940 if (SPROMBUS
== PCMCIA_BUS
) {
1942 sdpcmd_regs_t
*pcmregs
;
1945 origidx
= sb_coreidx(sbh
);
1946 pcmregs
= sb_setcore(sbh
, SB_PCMCIA
, 0);
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)
1956 /* SPROM is accessible only in PCMCIA mode unless there is SDIO clock */
1957 if (!(R_REG(osh
, &pcmregs
->corestatus
) & CS_PCMCIAMODE
))
1960 switch (SB_PCMCIA_READ(osh
, pcmregs
, SROM_INFO
) & SRI_SZ_MASK
) {
1962 size
= 256; /* SROM_INFO == 1 means 4kbit */
1965 size
= 1024; /* SROM_INFO == 2 means 16kbit */
1973 sb_core_disable(sbh
, 0);
1975 sb_setcoreidx(sbh
, origidx
);
1979 #endif /* def BCMUSBDEV */