2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include <bcmendian.h>
29 #include <bcmsrom_tbl.h>
41 #include <sbsdpcmdev.h>
44 #include <proto/ethernet.h> /* for sprom content groking */
46 #define BS_ERROR(args)
48 #define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
49 (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
50 ((uint8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
51 ((uint8 *)curmap + PCI_BAR0_SPROM_OFFSET))
54 #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
55 #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
58 typedef struct varbuf {
59 char *base; /* pointer to buffer base */
60 char *buf; /* pointer to current position */
61 unsigned int size; /* current (residual) size in bytes */
66 #define SROM_CIS_SINGLE 1
68 static int initvars_srom_si(si_t *sih, osl_t *osh, void *curmap, char **vars,
70 static void _initvars_srom_pci(uint8 sromrev, uint16 *srom, uint off,
72 static int initvars_srom_pci(si_t *sih, void *curmap, char **vars,
74 static int initvars_flash_si(si_t *sih, char **vars, uint *count);
76 static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count);
77 static int sprom_cmd_sdio(osl_t *osh, uint8 cmd);
78 static int sprom_read_sdio(osl_t *osh, uint16 addr, uint16 *data);
80 static int sprom_read_pci(osl_t *osh, si_t *sih, uint16 *sprom, uint wordoff,
81 uint16 *buf, uint nwords, bool check_crc);
82 #if defined(BCMNVRAMR)
83 static int otp_read_pci(osl_t *osh, si_t *sih, uint16 *buf, uint bufsz);
85 static uint16 srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, uint32 cmd,
86 uint wordoff, uint16 data);
88 static int initvars_table(osl_t *osh, char *start, char *end, char **vars,
90 static int initvars_flash(si_t *sih, osl_t *osh, char **vp, uint len);
92 /* Initialization of varbuf structure */
93 static void BCMATTACHFN(varbuf_init) (varbuf_t *b, char *buf, uint size)
96 b->base = b->buf = buf;
99 /* append a null terminated var=value string */
100 static int BCMATTACHFN(varbuf_append) (varbuf_t *b, const char *fmt, ...)
111 r = vsnprintf(b->buf, b->size, fmt, ap);
114 /* C99 snprintf behavior returns r >= size on overflow,
115 * others return -1 on overflow.
116 * All return -1 on format error.
117 * We need to leave room for 2 null terminations, one for the current var
118 * string, and one for final null of the var table. So check that the
119 * strlen written, r, leaves room for 2 chars.
121 if ((r == -1) || (r > (int)(b->size - 2))) {
126 /* Remove any earlier occurrence of the same variable */
127 s = strchr(b->buf, '=');
129 len = (size_t) (s - b->buf);
130 for (s = b->base; s < b->buf;) {
131 if ((bcmp(s, b->buf, len) == 0) && s[len] == '=') {
133 memmove(s, (s + len),
134 ((b->buf + r + 1) - (s + len)));
136 b->size += (unsigned int)len;
145 /* skip over this string's null termination */
154 * Initialize local vars from the right source for this platform.
155 * Return 0 on success, nonzero on error.
158 BCMATTACHFN(srom_var_init) (si_t *sih, uint bustype, void *curmap, osl_t *osh,
159 char **vars, uint *count) {
164 ASSERT(bustype == BUSTYPE(bustype));
165 if (vars == NULL || count == NULL)
171 switch (BUSTYPE(bustype)) {
174 return initvars_srom_si(sih, osh, curmap, vars, count);
177 ASSERT(curmap != NULL);
181 return initvars_srom_pci(sih, curmap, vars, count);
185 return initvars_cis_sdio(osh, vars, count);
194 /* support only 16-bit word read from srom */
196 srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
197 uint byteoff, uint nbytes, uint16 *buf, bool check_crc)
204 ASSERT(bustype == BUSTYPE(bustype));
206 /* check input - 16-bit access only */
207 if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > SROM_MAX)
213 if (BUSTYPE(bustype) == PCI_BUS) {
217 if (si_is_sprom_available(sih)) {
220 srom = (uint16 *) SROM_OFFSET(sih);
225 (osh, sih, srom, off, buf, nw, check_crc))
228 #if defined(BCMNVRAMR)
230 if (otp_read_pci(osh, sih, buf, SROM_MAX))
235 } else if (BUSTYPE(bustype) == SDIO_BUS) {
238 for (i = 0; i < nw; i++) {
240 (osh, (uint16) (off + i), (uint16 *) (buf + i)))
244 } else if (BUSTYPE(bustype) == SI_BUS) {
253 static const char BCMATTACHDATA(vstr_manf)[] = "manf=%s";
254 static const char BCMATTACHDATA(vstr_productname)[] = "productname=%s";
255 static const char BCMATTACHDATA(vstr_manfid)[] = "manfid=0x%x";
256 static const char BCMATTACHDATA(vstr_prodid)[] = "prodid=0x%x";
258 static const char BCMATTACHDATA(vstr_sdmaxspeed)[] = "sdmaxspeed=%d";
259 static const char BCMATTACHDATA(vstr_sdmaxblk)[][13] =
261 "sdmaxblk0=%d", "sdmaxblk1=%d", "sdmaxblk2=%d"};
263 static const char BCMATTACHDATA(vstr_regwindowsz)[] = "regwindowsz=%d";
264 static const char BCMATTACHDATA(vstr_sromrev)[] = "sromrev=%d";
265 static const char BCMATTACHDATA(vstr_chiprev)[] = "chiprev=%d";
266 static const char BCMATTACHDATA(vstr_subvendid)[] = "subvendid=0x%x";
267 static const char BCMATTACHDATA(vstr_subdevid)[] = "subdevid=0x%x";
268 static const char BCMATTACHDATA(vstr_boardrev)[] = "boardrev=0x%x";
269 static const char BCMATTACHDATA(vstr_aa2g)[] = "aa2g=0x%x";
270 static const char BCMATTACHDATA(vstr_aa5g)[] = "aa5g=0x%x";
271 static const char BCMATTACHDATA(vstr_ag)[] = "ag%d=0x%x";
272 static const char BCMATTACHDATA(vstr_cc)[] = "cc=%d";
273 static const char BCMATTACHDATA(vstr_opo)[] = "opo=%d";
274 static const char BCMATTACHDATA(vstr_pa0b)[][9] =
276 "pa0b0=%d", "pa0b1=%d", "pa0b2=%d"};
278 static const char BCMATTACHDATA(vstr_pa0itssit)[] = "pa0itssit=%d";
279 static const char BCMATTACHDATA(vstr_pa0maxpwr)[] = "pa0maxpwr=%d";
280 static const char BCMATTACHDATA(vstr_pa1b)[][9] =
282 "pa1b0=%d", "pa1b1=%d", "pa1b2=%d"};
284 static const char BCMATTACHDATA(vstr_pa1lob)[][11] =
286 "pa1lob0=%d", "pa1lob1=%d", "pa1lob2=%d"};
288 static const char BCMATTACHDATA(vstr_pa1hib)[][11] =
290 "pa1hib0=%d", "pa1hib1=%d", "pa1hib2=%d"};
292 static const char BCMATTACHDATA(vstr_pa1itssit)[] = "pa1itssit=%d";
293 static const char BCMATTACHDATA(vstr_pa1maxpwr)[] = "pa1maxpwr=%d";
294 static const char BCMATTACHDATA(vstr_pa1lomaxpwr)[] = "pa1lomaxpwr=%d";
295 static const char BCMATTACHDATA(vstr_pa1himaxpwr)[] = "pa1himaxpwr=%d";
296 static const char BCMATTACHDATA(vstr_oem)[] =
297 "oem=%02x%02x%02x%02x%02x%02x%02x%02x";
298 static const char BCMATTACHDATA(vstr_boardflags)[] = "boardflags=0x%x";
299 static const char BCMATTACHDATA(vstr_boardflags2)[] = "boardflags2=0x%x";
300 static const char BCMATTACHDATA(vstr_ledbh)[] = "ledbh%d=0x%x";
301 static const char BCMATTACHDATA(vstr_noccode)[] = "ccode=0x0";
302 static const char BCMATTACHDATA(vstr_ccode)[] = "ccode=%c%c";
303 static const char BCMATTACHDATA(vstr_cctl)[] = "cctl=0x%x";
304 static const char BCMATTACHDATA(vstr_cckpo)[] = "cckpo=0x%x";
305 static const char BCMATTACHDATA(vstr_ofdmpo)[] = "ofdmpo=0x%x";
306 static const char BCMATTACHDATA(vstr_rdlid)[] = "rdlid=0x%x";
307 static const char BCMATTACHDATA(vstr_rdlrndis)[] = "rdlrndis=%d";
308 static const char BCMATTACHDATA(vstr_rdlrwu)[] = "rdlrwu=%d";
309 static const char BCMATTACHDATA(vstr_usbfs)[] = "usbfs=%d";
310 static const char BCMATTACHDATA(vstr_wpsgpio)[] = "wpsgpio=%d";
311 static const char BCMATTACHDATA(vstr_wpsled)[] = "wpsled=%d";
312 static const char BCMATTACHDATA(vstr_rdlsn)[] = "rdlsn=%d";
313 static const char BCMATTACHDATA(vstr_rssismf2g)[] = "rssismf2g=%d";
314 static const char BCMATTACHDATA(vstr_rssismc2g)[] = "rssismc2g=%d";
315 static const char BCMATTACHDATA(vstr_rssisav2g)[] = "rssisav2g=%d";
316 static const char BCMATTACHDATA(vstr_bxa2g)[] = "bxa2g=%d";
317 static const char BCMATTACHDATA(vstr_rssismf5g)[] = "rssismf5g=%d";
318 static const char BCMATTACHDATA(vstr_rssismc5g)[] = "rssismc5g=%d";
319 static const char BCMATTACHDATA(vstr_rssisav5g)[] = "rssisav5g=%d";
320 static const char BCMATTACHDATA(vstr_bxa5g)[] = "bxa5g=%d";
321 static const char BCMATTACHDATA(vstr_tri2g)[] = "tri2g=%d";
322 static const char BCMATTACHDATA(vstr_tri5gl)[] = "tri5gl=%d";
323 static const char BCMATTACHDATA(vstr_tri5g)[] = "tri5g=%d";
324 static const char BCMATTACHDATA(vstr_tri5gh)[] = "tri5gh=%d";
325 static const char BCMATTACHDATA(vstr_rxpo2g)[] = "rxpo2g=%d";
326 static const char BCMATTACHDATA(vstr_rxpo5g)[] = "rxpo5g=%d";
327 static const char BCMATTACHDATA(vstr_boardtype)[] = "boardtype=0x%x";
328 static const char BCMATTACHDATA(vstr_leddc)[] = "leddc=0x%04x";
329 static const char BCMATTACHDATA(vstr_vendid)[] = "vendid=0x%x";
330 static const char BCMATTACHDATA(vstr_devid)[] = "devid=0x%x";
331 static const char BCMATTACHDATA(vstr_xtalfreq)[] = "xtalfreq=%d";
332 static const char BCMATTACHDATA(vstr_txchain)[] = "txchain=0x%x";
333 static const char BCMATTACHDATA(vstr_rxchain)[] = "rxchain=0x%x";
334 static const char BCMATTACHDATA(vstr_antswitch)[] = "antswitch=0x%x";
335 static const char BCMATTACHDATA(vstr_regrev)[] = "regrev=0x%x";
336 static const char BCMATTACHDATA(vstr_antswctl2g)[] = "antswctl2g=0x%x";
337 static const char BCMATTACHDATA(vstr_triso2g)[] = "triso2g=0x%x";
338 static const char BCMATTACHDATA(vstr_pdetrange2g)[] = "pdetrange2g=0x%x";
339 static const char BCMATTACHDATA(vstr_extpagain2g)[] = "extpagain2g=0x%x";
340 static const char BCMATTACHDATA(vstr_tssipos2g)[] = "tssipos2g=0x%x";
341 static const char BCMATTACHDATA(vstr_antswctl5g)[] = "antswctl5g=0x%x";
342 static const char BCMATTACHDATA(vstr_triso5g)[] = "triso5g=0x%x";
343 static const char BCMATTACHDATA(vstr_pdetrange5g)[] = "pdetrange5g=0x%x";
344 static const char BCMATTACHDATA(vstr_extpagain5g)[] = "extpagain5g=0x%x";
345 static const char BCMATTACHDATA(vstr_tssipos5g)[] = "tssipos5g=0x%x";
346 static const char BCMATTACHDATA(vstr_maxp2ga0)[] = "maxp2ga0=0x%x";
347 static const char BCMATTACHDATA(vstr_itt2ga0)[] = "itt2ga0=0x%x";
348 static const char BCMATTACHDATA(vstr_pa)[] = "pa%dgw%da%d=0x%x";
349 static const char BCMATTACHDATA(vstr_pahl)[] = "pa%dg%cw%da%d=0x%x";
350 static const char BCMATTACHDATA(vstr_maxp5ga0)[] = "maxp5ga0=0x%x";
351 static const char BCMATTACHDATA(vstr_itt5ga0)[] = "itt5ga0=0x%x";
352 static const char BCMATTACHDATA(vstr_maxp5gha0)[] = "maxp5gha0=0x%x";
353 static const char BCMATTACHDATA(vstr_maxp5gla0)[] = "maxp5gla0=0x%x";
354 static const char BCMATTACHDATA(vstr_maxp2ga1)[] = "maxp2ga1=0x%x";
355 static const char BCMATTACHDATA(vstr_itt2ga1)[] = "itt2ga1=0x%x";
356 static const char BCMATTACHDATA(vstr_maxp5ga1)[] = "maxp5ga1=0x%x";
357 static const char BCMATTACHDATA(vstr_itt5ga1)[] = "itt5ga1=0x%x";
358 static const char BCMATTACHDATA(vstr_maxp5gha1)[] = "maxp5gha1=0x%x";
359 static const char BCMATTACHDATA(vstr_maxp5gla1)[] = "maxp5gla1=0x%x";
360 static const char BCMATTACHDATA(vstr_cck2gpo)[] = "cck2gpo=0x%x";
361 static const char BCMATTACHDATA(vstr_ofdm2gpo)[] = "ofdm2gpo=0x%x";
362 static const char BCMATTACHDATA(vstr_ofdm5gpo)[] = "ofdm5gpo=0x%x";
363 static const char BCMATTACHDATA(vstr_ofdm5glpo)[] = "ofdm5glpo=0x%x";
364 static const char BCMATTACHDATA(vstr_ofdm5ghpo)[] = "ofdm5ghpo=0x%x";
365 static const char BCMATTACHDATA(vstr_cddpo)[] = "cddpo=0x%x";
366 static const char BCMATTACHDATA(vstr_stbcpo)[] = "stbcpo=0x%x";
367 static const char BCMATTACHDATA(vstr_bw40po)[] = "bw40po=0x%x";
368 static const char BCMATTACHDATA(vstr_bwduppo)[] = "bwduppo=0x%x";
369 static const char BCMATTACHDATA(vstr_mcspo)[] = "mcs%dgpo%d=0x%x";
370 static const char BCMATTACHDATA(vstr_mcspohl)[] = "mcs%dg%cpo%d=0x%x";
371 static const char BCMATTACHDATA(vstr_custom)[] = "customvar%d=0x%x";
372 static const char BCMATTACHDATA(vstr_cckdigfilttype)[] = "cckdigfilttype=%d";
373 static const char BCMATTACHDATA(vstr_boardnum)[] = "boardnum=%d";
374 static const char BCMATTACHDATA(vstr_macaddr)[] = "macaddr=%s";
375 static const char BCMATTACHDATA(vstr_usbepnum)[] = "usbepnum=0x%x";
376 static const char BCMATTACHDATA(vstr_end)[] = "END\0";
378 uint8 patch_pair = 0;
380 /* For dongle HW, accept partial calibration parameters */
381 #define BCMDONGLECASE(n)
384 BCMATTACHFN(srom_parsecis) (osl_t *osh, uint8 *pcis[], uint ciscnt,
385 char **vars, uint *count)
390 uint8 *cis, tup, tlen, sromrev = 1;
392 bool ag_init = FALSE;
400 ASSERT(vars != NULL);
401 ASSERT(count != NULL);
405 base = MALLOC(osh, MAXSZ_NVRAM_VARS);
406 ASSERT(base != NULL);
410 varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
411 bzero(base, MAXSZ_NVRAM_VARS);
413 for (cisnum = 0; cisnum < ciscnt; cisnum++) {
421 if (tup == CISTPL_NULL || tup == CISTPL_END)
426 if (cis[i] == CISTPL_NULL
427 || cis[i] == CISTPL_END) {
432 tup = CISTPL_BRCM_HNBU;
436 if ((i + tlen) >= CIS_SIZE)
441 /* assume the strings are good if the version field checks out */
442 if (((cis[i + 1] << 8) + cis[i]) >= 0x0008) {
443 varbuf_append(&b, vstr_manf,
445 varbuf_append(&b, vstr_productname,
454 varbuf_append(&b, vstr_manfid,
455 (cis[i + 1] << 8) + cis[i]);
456 varbuf_append(&b, vstr_prodid,
457 (cis[i + 3] << 8) + cis[i + 2]);
466 case CISTPL_FID_SDIO:
469 uint8 spd = cis[i + 3];
470 static int base[] = {
471 -1, 10, 12, 13, 15, 20,
473 35, 40, 45, 50, 55, 60,
476 static int mult[] = {
477 10, 100, 1000, 10000,
480 ASSERT((mult[spd & 0x7] != -1)
483 [(spd >> 3) & 0x0f]));
493 } else if (cis[i] == 1) {
504 /* set macaddr if HNBU_MACADDR not seen yet */
507 && !(ETHER_ISNULLADDR(&cis[i + 2]))
508 && !(ETHER_ISMULTI(&cis[i + 2]))) {
511 bcm_ether_ntoa((struct
516 /* set boardnum if HNBU_BOARDNUM not seen yet */
527 varbuf_append(&b, vstr_regwindowsz,
528 (cis[i + 7] << 8) | cis[i + 6]);
531 case CISTPL_BRCM_HNBU:
534 sromrev = cis[i + 1];
535 varbuf_append(&b, vstr_sromrev,
540 varbuf_append(&b, vstr_xtalfreq,
548 varbuf_append(&b, vstr_vendid,
551 varbuf_append(&b, vstr_devid,
555 varbuf_append(&b, vstr_chiprev,
566 varbuf_append(&b, vstr_subdevid,
569 /* subdevid doubles for boardtype */
579 (cis[i + 2] << 8) + cis[i + 1];
587 /* retrieve the patch pairs
588 * from tlen/6; where 6 is
589 * sizeof(patch addr(2)) +
590 * sizeof(patch data(4)).
592 patch_pair = tlen / 6;
594 for (j = 0; j < patch_pair; j++) {
649 varbuf_append(&b, vstr_boardrev,
652 varbuf_append(&b, vstr_boardrev,
657 case HNBU_BOARDFLAGS:
658 w32 = (cis[i + 2] << 8) + cis[i + 1];
661 ((cis[i + 4] << 24) +
663 varbuf_append(&b, vstr_boardflags, w32);
667 (cis[i + 6] << 8) + cis[i +
682 varbuf_append(&b, vstr_usbfs,
687 varbuf_append(&b, vstr_boardtype,
694 * what follows is a nonstandard HNBU CIS
695 * that lacks CISTPL_BRCM_HNBU tags
697 * skip 0xff (end of standard CIS)
701 standard_cis = FALSE;
705 varbuf_append(&b, vstr_usbepnum,
706 (cis[i + 2] << 8) | cis[i
712 varbuf_append(&b, vstr_aa2g,
715 varbuf_append(&b, vstr_aa5g,
720 varbuf_append(&b, vstr_ag, 0,
723 varbuf_append(&b, vstr_ag, 1,
726 varbuf_append(&b, vstr_ag, 2,
729 varbuf_append(&b, vstr_ag, 3,
735 varbuf_append(&b, vstr_aa5g,
737 varbuf_append(&b, vstr_ag, 1,
742 ASSERT(sromrev == 1);
743 varbuf_append(&b, vstr_cc, cis[i + 1]);
749 ASSERT(sromrev == 1);
755 ASSERT(sromrev >= 2);
756 varbuf_append(&b, vstr_opo,
770 for (j = 0; j < 3; j++) {
795 ASSERT((sromrev == 2)
815 for (j = 0; j < 3; j++) {
830 for (j = 3; j < 6; j++) {
845 for (j = 6; j < 9; j++) {
862 ASSERT((tlen == 19) ||
870 ASSERT(sromrev == 1);
871 varbuf_append(&b, vstr_oem,
872 cis[i + 1], cis[i + 2],
873 cis[i + 3], cis[i + 4],
874 cis[i + 5], cis[i + 6],
875 cis[i + 7], cis[i + 8]);
879 for (j = 1; j <= 4; j++) {
880 if (cis[i + j] != 0xff) {
892 if ((cis[i + 1] == 0)
893 || (cis[i + 2] == 0))
894 varbuf_append(&b, vstr_noccode);
896 varbuf_append(&b, vstr_ccode,
899 varbuf_append(&b, vstr_cctl,
905 varbuf_append(&b, vstr_cckpo,
906 (cis[i + 2] << 8) | cis[i
913 varbuf_append(&b, vstr_ofdmpo,
921 varbuf_append(&b, vstr_wpsgpio,
924 varbuf_append(&b, vstr_wpsled,
928 case HNBU_RSSISMBXA2G:
929 ASSERT(sromrev == 3);
930 varbuf_append(&b, vstr_rssismf2g,
932 varbuf_append(&b, vstr_rssismc2g,
933 (cis[i + 1] >> 4) & 0xf);
934 varbuf_append(&b, vstr_rssisav2g,
936 varbuf_append(&b, vstr_bxa2g,
937 (cis[i + 2] >> 3) & 0x3);
940 case HNBU_RSSISMBXA5G:
941 ASSERT(sromrev == 3);
942 varbuf_append(&b, vstr_rssismf5g,
944 varbuf_append(&b, vstr_rssismc5g,
945 (cis[i + 1] >> 4) & 0xf);
946 varbuf_append(&b, vstr_rssisav5g,
948 varbuf_append(&b, vstr_bxa5g,
949 (cis[i + 2] >> 3) & 0x3);
953 ASSERT(sromrev == 3);
954 varbuf_append(&b, vstr_tri2g,
959 ASSERT(sromrev == 3);
960 varbuf_append(&b, vstr_tri5gl,
962 varbuf_append(&b, vstr_tri5g,
964 varbuf_append(&b, vstr_tri5gh,
969 ASSERT(sromrev == 3);
970 varbuf_append(&b, vstr_rxpo2g,
975 ASSERT(sromrev == 3);
976 varbuf_append(&b, vstr_rxpo5g,
981 if (!(ETHER_ISNULLADDR(&cis[i + 1])) &&
982 !(ETHER_ISMULTI(&cis[i + 1]))) {
983 bcm_ether_ntoa((struct
988 /* set boardnum if HNBU_BOARDNUM not seen yet */
997 /* CIS leddc only has 16bits, convert it to 32bits */
998 w32 = ((cis[i + 2] << 24) | /* oncount */
999 (cis[i + 1] << 8)); /* offcount */
1000 varbuf_append(&b, vstr_leddc, w32);
1003 case HNBU_CHAINSWITCH:
1004 varbuf_append(&b, vstr_txchain,
1006 varbuf_append(&b, vstr_rxchain,
1008 varbuf_append(&b, vstr_antswitch,
1014 varbuf_append(&b, vstr_regrev,
1020 (cis[i + 2] << 8) + cis[i +
1025 SROM8_FEM_ANTSWLUT_MASK)
1027 SROM8_FEM_ANTSWLUT_SHIFT);
1028 varbuf_append(&b, vstr_triso2g,
1030 SROM8_FEM_TR_ISO_MASK)
1032 SROM8_FEM_TR_ISO_SHIFT);
1036 SROM8_FEM_PDET_RANGE_MASK)
1038 SROM8_FEM_PDET_RANGE_SHIFT);
1042 SROM8_FEM_EXTPA_GAIN_MASK)
1044 SROM8_FEM_EXTPA_GAIN_SHIFT);
1048 SROM8_FEM_TSSIPOS_MASK)
1050 SROM8_FEM_TSSIPOS_SHIFT);
1055 (cis[i + 4] << 8) + cis[i +
1060 SROM8_FEM_ANTSWLUT_MASK)
1062 SROM8_FEM_ANTSWLUT_SHIFT);
1063 varbuf_append(&b, vstr_triso5g,
1065 SROM8_FEM_TR_ISO_MASK)
1067 SROM8_FEM_TR_ISO_SHIFT);
1071 SROM8_FEM_PDET_RANGE_MASK)
1073 SROM8_FEM_PDET_RANGE_SHIFT);
1077 SROM8_FEM_EXTPA_GAIN_MASK)
1079 SROM8_FEM_EXTPA_GAIN_SHIFT);
1083 SROM8_FEM_TSSIPOS_MASK)
1085 SROM8_FEM_TSSIPOS_SHIFT);
1089 case HNBU_PAPARMS_C0:
1090 varbuf_append(&b, vstr_maxp2ga0,
1092 varbuf_append(&b, vstr_itt2ga0,
1094 varbuf_append(&b, vstr_pa, 2, 0, 0,
1097 varbuf_append(&b, vstr_pa, 2, 1, 0,
1100 varbuf_append(&b, vstr_pa, 2, 2, 0,
1106 varbuf_append(&b, vstr_maxp5ga0,
1108 varbuf_append(&b, vstr_itt5ga0,
1110 varbuf_append(&b, vstr_maxp5gha0,
1112 varbuf_append(&b, vstr_maxp5gla0,
1114 varbuf_append(&b, vstr_pa, 5, 0, 0,
1115 (cis[i + 14] << 8) +
1117 varbuf_append(&b, vstr_pa, 5, 1, 0,
1118 (cis[i + 16] << 8) +
1120 varbuf_append(&b, vstr_pa, 5, 2, 0,
1121 (cis[i + 18] << 8) +
1123 varbuf_append(&b, vstr_pahl, 5, 'l', 0,
1125 (cis[i + 20] << 8) +
1127 varbuf_append(&b, vstr_pahl, 5, 'l', 1,
1129 (cis[i + 22] << 8) +
1131 varbuf_append(&b, vstr_pahl, 5, 'l', 2,
1133 (cis[i + 24] << 8) +
1135 varbuf_append(&b, vstr_pahl, 5, 'h', 0,
1137 (cis[i + 26] << 8) +
1139 varbuf_append(&b, vstr_pahl, 5, 'h', 1,
1141 (cis[i + 28] << 8) +
1143 varbuf_append(&b, vstr_pahl, 5, 'h', 2,
1145 (cis[i + 30] << 8) +
1149 case HNBU_PAPARMS_C1:
1150 varbuf_append(&b, vstr_maxp2ga1,
1152 varbuf_append(&b, vstr_itt2ga1,
1154 varbuf_append(&b, vstr_pa, 2, 0, 1,
1157 varbuf_append(&b, vstr_pa, 2, 1, 1,
1160 varbuf_append(&b, vstr_pa, 2, 2, 1,
1166 varbuf_append(&b, vstr_maxp5ga1,
1168 varbuf_append(&b, vstr_itt5ga1,
1170 varbuf_append(&b, vstr_maxp5gha1,
1172 varbuf_append(&b, vstr_maxp5gla1,
1174 varbuf_append(&b, vstr_pa, 5, 0, 1,
1175 (cis[i + 14] << 8) +
1177 varbuf_append(&b, vstr_pa, 5, 1, 1,
1178 (cis[i + 16] << 8) +
1180 varbuf_append(&b, vstr_pa, 5, 2, 1,
1181 (cis[i + 18] << 8) +
1183 varbuf_append(&b, vstr_pahl, 5, 'l', 0,
1185 (cis[i + 20] << 8) +
1187 varbuf_append(&b, vstr_pahl, 5, 'l', 1,
1189 (cis[i + 22] << 8) +
1191 varbuf_append(&b, vstr_pahl, 5, 'l', 2,
1193 (cis[i + 24] << 8) +
1195 varbuf_append(&b, vstr_pahl, 5, 'h', 0,
1197 (cis[i + 26] << 8) +
1199 varbuf_append(&b, vstr_pahl, 5, 'h', 1,
1201 (cis[i + 28] << 8) +
1203 varbuf_append(&b, vstr_pahl, 5, 'h', 2,
1205 (cis[i + 30] << 8) +
1209 case HNBU_PO_CCKOFDM:
1210 varbuf_append(&b, vstr_cck2gpo,
1213 varbuf_append(&b, vstr_ofdm2gpo,
1214 (cis[i + 6] << 24) +
1215 (cis[i + 5] << 16) +
1221 varbuf_append(&b, vstr_ofdm5gpo,
1222 (cis[i + 10] << 24) +
1223 (cis[i + 9] << 16) +
1226 varbuf_append(&b, vstr_ofdm5glpo,
1227 (cis[i + 14] << 24) +
1228 (cis[i + 13] << 16) +
1229 (cis[i + 12] << 8) +
1231 varbuf_append(&b, vstr_ofdm5ghpo,
1232 (cis[i + 18] << 24) +
1233 (cis[i + 17] << 16) +
1234 (cis[i + 16] << 8) +
1239 for (j = 0; j <= (tlen / 2); j++) {
1240 varbuf_append(&b, vstr_mcspo, 2,
1250 case HNBU_PO_MCS5GM:
1251 for (j = 0; j <= (tlen / 2); j++) {
1252 varbuf_append(&b, vstr_mcspo, 5,
1262 case HNBU_PO_MCS5GLH:
1263 for (j = 0; j <= (tlen / 4); j++) {
1264 varbuf_append(&b, vstr_mcspohl,
1273 for (j = 0; j <= (tlen / 4); j++) {
1274 varbuf_append(&b, vstr_mcspohl,
1289 varbuf_append(&b, vstr_cddpo,
1295 varbuf_append(&b, vstr_stbcpo,
1301 varbuf_append(&b, vstr_bw40po,
1306 case HNBU_PO_40MDUP:
1307 varbuf_append(&b, vstr_bwduppo,
1313 varbuf_append(&b, vstr_ofdm5gpo,
1314 (cis[i + 4] << 24) +
1315 (cis[i + 3] << 16) +
1318 varbuf_append(&b, vstr_ofdm5glpo,
1319 (cis[i + 8] << 24) +
1320 (cis[i + 7] << 16) +
1323 varbuf_append(&b, vstr_ofdm5ghpo,
1324 (cis[i + 12] << 24) +
1325 (cis[i + 11] << 16) +
1326 (cis[i + 10] << 8) +
1331 varbuf_append(&b, vstr_custom, 1,
1332 ((cis[i + 4] << 24) +
1333 (cis[i + 3] << 16) +
1338 #if defined(BCMSDIO)
1339 case HNBU_SROM3SWRGN:
1342 uint8 srev = cis[i + 1 + 70];
1344 /* make tuple value 16-bit aligned and parse it */
1345 bcopy(&cis[i + 1], srom,
1347 _initvars_srom_pci(srev, srom,
1350 /* 2.4G antenna gain is included in SROM */
1352 /* Ethernet MAC address is included in SROM */
1356 /* create extra variables */
1358 varbuf_append(&b, vstr_vendid,
1364 varbuf_append(&b, vstr_devid,
1370 varbuf_append(&b, vstr_xtalfreq,
1376 #endif /* defined(BCMSDIO) */
1378 case HNBU_CCKFILTTYPE:
1379 varbuf_append(&b, vstr_cckdigfilttype,
1387 } while (tup != CISTPL_END);
1390 if (boardnum != -1) {
1391 varbuf_append(&b, vstr_boardnum, boardnum);
1395 varbuf_append(&b, vstr_macaddr, eabuf);
1398 /* if there is no antenna gain field, set default */
1399 if (getvar(NULL, "ag0") == NULL && ag_init == FALSE) {
1400 varbuf_append(&b, vstr_ag, 0, 0xff);
1403 /* final nullbyte terminator */
1404 ASSERT(b.size >= 1);
1407 ASSERT(b.buf - base <= MAXSZ_NVRAM_VARS);
1408 err = initvars_table(osh, base, b.buf, vars, count);
1410 MFREE(osh, base, MAXSZ_NVRAM_VARS);
1414 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
1415 * not in the bus cores.
1418 srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, uint32 cmd, uint wordoff,
1421 chipcregs_t *cc = (chipcregs_t *) ccregs;
1422 uint wait_cnt = 1000;
1424 if ((cmd == SRC_OP_READ) || (cmd == SRC_OP_WRITE)) {
1425 W_REG(osh, &cc->sromaddress, wordoff * 2);
1426 if (cmd == SRC_OP_WRITE)
1427 W_REG(osh, &cc->sromdata, data);
1430 W_REG(osh, &cc->sromcontrol, SRC_START | cmd);
1432 while (wait_cnt--) {
1433 if ((R_REG(osh, &cc->sromcontrol) & SRC_BUSY) == 0)
1438 BS_ERROR(("%s: Command 0x%x timed out\n", __func__, cmd));
1441 if (cmd == SRC_OP_READ)
1442 return (uint16) R_REG(osh, &cc->sromdata);
1448 * Read in and validate sprom.
1449 * Return 0 on success, nonzero on error.
1452 sprom_read_pci(osl_t *osh, si_t *sih, uint16 *sprom, uint wordoff,
1453 uint16 *buf, uint nwords, bool check_crc)
1457 void *ccregs = NULL;
1459 /* read the sprom */
1460 for (i = 0; i < nwords; i++) {
1462 if (sih->ccrev > 31 && ISSIM_ENAB(sih)) {
1463 /* use indirect since direct is too slow on QT */
1464 if ((sih->cccaps & CC_CAP_SROM) == 0)
1467 ccregs = (void *)((uint8 *) sprom - CC_SROM_OTP);
1469 srom_cc_cmd(sih, osh, ccregs, SRC_OP_READ,
1473 if (ISSIM_ENAB(sih))
1474 buf[i] = R_REG(osh, &sprom[wordoff + i]);
1476 buf[i] = R_REG(osh, &sprom[wordoff + i]);
1481 /* bypass crc checking for simulation to allow srom hack */
1482 if (ISSIM_ENAB(sih))
1487 if (buf[0] == 0xffff) {
1488 /* The hardware thinks that an srom that starts with 0xffff
1489 * is blank, regardless of the rest of the content, so declare
1492 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n",
1497 /* fixup the endianness so crc8 will pass */
1498 htol16_buf(buf, nwords * 2);
1499 if (hndcrc8((uint8 *) buf, nwords * 2, CRC8_INIT_VALUE) !=
1501 /* DBG only pci always read srom4 first, then srom8/9 */
1502 /* BS_ERROR(("%s: bad crc\n", __func__)); */
1505 /* now correct the endianness of the byte array */
1506 ltoh16_buf(buf, nwords * 2);
1511 #if defined(BCMNVRAMR)
1512 static int otp_read_pci(osl_t *osh, si_t *sih, uint16 *buf, uint bufsz)
1515 uint sz = OTP_SZ_MAX / 2; /* size in words */
1518 ASSERT(bufsz <= OTP_SZ_MAX);
1520 otp = MALLOC(osh, OTP_SZ_MAX);
1525 bzero(otp, OTP_SZ_MAX);
1527 err = otp_read_region(sih, OTP_HW_RGN, (uint16 *) otp, &sz);
1529 bcopy(otp, buf, bufsz);
1532 MFREE(osh, otp, OTP_SZ_MAX);
1535 if (buf[0] == 0xffff) {
1536 /* The hardware thinks that an srom that starts with 0xffff
1537 * is blank, regardless of the rest of the content, so declare
1540 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __func__,
1545 /* fixup the endianness so crc8 will pass */
1546 htol16_buf(buf, bufsz);
1547 if (hndcrc8((uint8 *) buf, SROM4_WORDS * 2, CRC8_INIT_VALUE) !=
1549 BS_ERROR(("%s: bad crc\n", __func__));
1552 /* now correct the endianness of the byte array */
1553 ltoh16_buf(buf, bufsz);
1557 #endif /* defined(BCMNVRAMR) */
1559 * Create variable table from memory.
1560 * Return 0 on success, nonzero on error.
1563 BCMATTACHFN(initvars_table) (osl_t *osh, char *start, char *end, char **vars,
1565 int c = (int)(end - start);
1567 /* do it only when there is more than just the null string */
1569 char *vp = MALLOC(osh, c);
1573 bcopy(start, vp, c);
1585 * Find variables with <devpath> from flash. 'base' points to the beginning
1586 * of the table upon enter and to the end of the table upon exit when success.
1587 * Return 0 on success, nonzero on error.
1590 BCMATTACHFN(initvars_flash) (si_t *sih, osl_t *osh, char **base, uint len)
1596 uint l, dl, copy_len;
1597 char devpath[SI_DEVPATH_BUFSZ];
1599 /* allocate memory and read in flash */
1600 flash = MALLOC(osh, NVRAM_SPACE);
1603 err = nvram_getall(flash, NVRAM_SPACE);
1607 si_devpath(sih, devpath, sizeof(devpath));
1609 /* grab vars with the <devpath> prefix in name */
1610 dl = strlen(devpath);
1611 for (s = flash; s && *s; s += l + 1) {
1614 /* skip non-matching variable */
1615 if (strncmp(s, devpath, dl))
1618 /* is there enough room to copy? */
1619 copy_len = l - dl + 1;
1620 if (len < copy_len) {
1621 err = BCME_BUFTOOSHORT;
1625 /* no prefix, just the name=value */
1626 strncpy(vp, &s[dl], copy_len);
1631 /* add null string as terminator */
1633 err = BCME_BUFTOOSHORT;
1640 exit: MFREE(osh, flash, NVRAM_SPACE);
1645 * Initialize nonvolatile variable table from flash.
1646 * Return 0 on success, nonzero on error.
1649 BCMATTACHFN(initvars_flash_si) (si_t *sih, char **vars, uint *count)
1651 osl_t *osh = si_osh(sih);
1655 ASSERT(vars != NULL);
1656 ASSERT(count != NULL);
1658 base = vp = MALLOC(osh, MAXSZ_NVRAM_VARS);
1663 err = initvars_flash(sih, osh, &vp, MAXSZ_NVRAM_VARS);
1665 err = initvars_table(osh, base, vp, vars, count);
1667 MFREE(osh, base, MAXSZ_NVRAM_VARS);
1672 /* Parse SROM and create name=value pairs. 'srom' points to
1673 * the SROM word array. 'off' specifies the offset of the
1674 * first word 'srom' points to, which should be either 0 or
1675 * SROM3_SWRG_OFF (full SROM or software region).
1678 static uint mask_shift(uint16 mask)
1681 for (i = 0; i < (sizeof(mask) << 3); i++) {
1682 if (mask & (1 << i))
1689 static uint mask_width(uint16 mask)
1692 for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
1693 if (mask & (1 << i))
1694 return (uint) (i - mask_shift(mask) + 1);
1701 static bool mask_valid(uint16 mask)
1703 uint shift = mask_shift(mask);
1704 uint width = mask_width(mask);
1705 return mask == ((~0 << shift) & ~(~0 << (shift + width)));
1710 BCMATTACHFN(_initvars_srom_pci) (uint8 sromrev, uint16 *srom, uint off,
1714 const sromvar_t *srv;
1717 uint32 sr = (1 << sromrev);
1719 varbuf_append(b, "sromrev=%d", sromrev);
1721 for (srv = pci_sromvars; srv->name != NULL; srv++) {
1724 if ((srv->revmask & sr) == 0)
1733 /* This entry is for mfgc only. Don't generate param for it, */
1734 if (flags & SRFL_NOVAR)
1737 if (flags & SRFL_ETHADDR) {
1738 char eabuf[ETHER_ADDR_STR_LEN];
1739 struct ether_addr ea;
1741 ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff;
1742 ea.octet[1] = srom[srv->off - off] & 0xff;
1743 ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff;
1744 ea.octet[3] = srom[srv->off + 1 - off] & 0xff;
1745 ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff;
1746 ea.octet[5] = srom[srv->off + 2 - off] & 0xff;
1747 bcm_ether_ntoa(&ea, eabuf);
1749 varbuf_append(b, "%s=%s", name, eabuf);
1751 ASSERT(mask_valid(srv->mask));
1752 ASSERT(mask_width(srv->mask));
1754 w = srom[srv->off - off];
1755 val = (w & srv->mask) >> mask_shift(srv->mask);
1756 width = mask_width(srv->mask);
1758 while (srv->flags & SRFL_MORE) {
1760 ASSERT(srv->name != NULL);
1762 if (srv->off == 0 || srv->off < off)
1765 ASSERT(mask_valid(srv->mask));
1766 ASSERT(mask_width(srv->mask));
1768 w = srom[srv->off - off];
1770 ((w & srv->mask) >> mask_shift(srv->
1773 width += mask_width(srv->mask);
1776 if ((flags & SRFL_NOFFS)
1777 && ((int)val == (1 << width) - 1))
1780 if (flags & SRFL_CCODE) {
1782 varbuf_append(b, "ccode=");
1784 varbuf_append(b, "ccode=%c%c",
1785 (val >> 8), (val & 0xff));
1787 /* LED Powersave duty cycle has to be scaled:
1788 *(oncount >> 24) (offcount >> 8)
1790 else if (flags & SRFL_LEDDC) {
1791 uint32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */
1792 (((val & 0xff)) << 8); /* offcount */
1793 varbuf_append(b, "leddc=%d", w32);
1794 } else if (flags & SRFL_PRHEX)
1795 varbuf_append(b, "%s=0x%x", name, val);
1796 else if ((flags & SRFL_PRSIGN)
1797 && (val & (1 << (width - 1))))
1798 varbuf_append(b, "%s=%d", name,
1799 (int)(val | (~0 << width)));
1801 varbuf_append(b, "%s=%u", name, val);
1806 /* Do per-path variables */
1811 psz = SROM8_PATH1 - SROM8_PATH0;
1814 psz = SROM4_PATH1 - SROM4_PATH0;
1817 for (p = 0; p < MAX_PATH_SROM; p++) {
1818 for (srv = perpath_pci_sromvars; srv->name != NULL;
1820 if ((srv->revmask & sr) == 0)
1823 if (pb + srv->off < off)
1826 /* This entry is for mfgc only. Don't generate param for it, */
1827 if (srv->flags & SRFL_NOVAR)
1830 w = srom[pb + srv->off - off];
1832 ASSERT(mask_valid(srv->mask));
1833 val = (w & srv->mask) >> mask_shift(srv->mask);
1834 width = mask_width(srv->mask);
1836 /* Cheating: no per-path var is more than 1 word */
1838 if ((srv->flags & SRFL_NOFFS)
1839 && ((int)val == (1 << width) - 1))
1842 if (srv->flags & SRFL_PRHEX)
1843 varbuf_append(b, "%s%d=0x%x", srv->name,
1846 varbuf_append(b, "%s%d=%d", srv->name,
1855 * Initialize nonvolatile variable table from sprom.
1856 * Return 0 on success, nonzero on error.
1859 BCMATTACHFN(initvars_srom_pci) (si_t *sih, void *curmap, char **vars,
1861 uint16 *srom, *sromwindow;
1865 char *vp, *base = NULL;
1866 osl_t *osh = si_osh(sih);
1871 * Apply CRC over SROM content regardless SROM is present or not,
1872 * and use variable <devpath>sromrev's existance in flash to decide
1873 * if we should return an error when CRC fails or read SROM variables
1876 srom = MALLOC(osh, SROM_MAX);
1877 ASSERT(srom != NULL);
1881 sromwindow = (uint16 *) SROM_OFFSET(sih);
1882 if (si_is_sprom_available(sih)) {
1884 sprom_read_pci(osh, sih, sromwindow, 0, srom, SROM_WORDS,
1887 if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
1888 (((sih->buscoretype == PCIE_CORE_ID)
1889 && (sih->buscorerev >= 6))
1890 || ((sih->buscoretype == PCI_CORE_ID)
1891 && (sih->buscorerev >= 0xe)))) {
1892 /* sromrev >= 4, read more */
1894 sprom_read_pci(osh, sih, sromwindow, 0, srom,
1896 sromrev = srom[SROM4_CRCREV] & 0xff;
1898 BS_ERROR(("%s: srom %d, bad crc\n", __func__,
1901 } else if (err == 0) {
1902 /* srom is good and is rev < 4 */
1903 /* top word of sprom contains version and crc8 */
1904 sromrev = srom[SROM_CRCREV] & 0xff;
1905 /* bcm4401 sroms misprogrammed */
1906 if (sromrev == 0x10)
1910 #if defined(BCMNVRAMR)
1911 /* Use OTP if SPROM not available */
1912 else if ((err = otp_read_pci(osh, sih, srom, SROM_MAX)) == 0) {
1913 /* OTP only contain SROM rev8/rev9 for now */
1914 sromrev = srom[SROM4_CRCREV] & 0xff;
1919 BS_ERROR(("Neither SPROM nor OTP has valid image\n"));
1922 /* We want internal/wltest driver to come up with default sromvars so we can
1923 * program a blank SPROM/OTP.
1930 value = si_getdevpathvar(sih, "sromrev");
1932 sromrev = (uint8) bcm_strtoul(value, NULL, 0);
1937 BS_ERROR(("%s, SROM CRC Error\n", __func__));
1939 value = si_getnvramflvar(sih, "sromrev");
1952 /* Bitmask for the sromrev */
1955 /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
1956 if ((sr & 0x33e) == 0) {
1961 ASSERT(vars != NULL);
1962 ASSERT(count != NULL);
1964 base = vp = MALLOC(osh, MAXSZ_NVRAM_VARS);
1971 /* read variables from flash */
1973 err = initvars_flash(sih, osh, &vp, MAXSZ_NVRAM_VARS);
1979 varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
1981 /* parse SROM into name=value pairs. */
1982 _initvars_srom_pci(sromrev, srom, 0, &b);
1984 /* final nullbyte terminator */
1985 ASSERT(b.size >= 1);
1989 ASSERT((vp - base) <= MAXSZ_NVRAM_VARS);
1992 err = initvars_table(osh, base, vp, vars, count);
1996 MFREE(osh, base, MAXSZ_NVRAM_VARS);
1998 MFREE(osh, srom, SROM_MAX);
2004 * Read the SDIO cis and call parsecis to initialize the vars.
2005 * Return 0 on success, nonzero on error.
2008 BCMATTACHFN(initvars_cis_sdio) (osl_t *osh, char **vars, uint *count)
2010 uint8 *cis[SBSDIO_NUM_FUNCTION + 1];
2014 numfn = bcmsdh_query_iofnum(NULL);
2015 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
2017 for (fn = 0; fn <= numfn; fn++) {
2018 cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT)
2019 if (cis[fn] == NULL) {
2024 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
2026 if (bcmsdh_cis_read(NULL, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT) !=
2028 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
2035 rc = srom_parsecis(osh, cis, fn, vars, count);
2038 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
2043 /* set SDIO sprom command register */
2044 static int BCMATTACHFN(sprom_cmd_sdio) (osl_t *osh, uint8 cmd)
2047 uint wait_cnt = 1000;
2049 /* write sprom command register */
2050 bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_CS, cmd, NULL);
2053 while (wait_cnt--) {
2055 bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_CS, NULL);
2056 if (status & SBSDIO_SPROM_DONE)
2063 /* read a word from the SDIO srom */
2064 static int sprom_read_sdio(osl_t *osh, uint16 addr, uint16 *data)
2066 uint8 addr_l, addr_h, data_l, data_h;
2068 addr_l = (uint8) ((addr * 2) & 0xff);
2069 addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
2072 bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_HIGH, addr_h,
2074 bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_LOW, addr_l,
2078 if (sprom_cmd_sdio(osh, SBSDIO_SPROM_READ))
2083 bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_HIGH, NULL);
2085 bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_LOW, NULL);
2087 *data = (data_h << 8) | data_l;
2090 #endif /* BCMSDIO */
2093 BCMATTACHFN(initvars_srom_si) (si_t *sih, osl_t *osh, void *curmap,
2094 char **vars, uint *varsz) {
2095 /* Search flash nvram section for srom variables */
2096 return initvars_flash_si(sih, vars, varsz);