31f6ad8917da97d0fc64fa29177f4814e15d2095
[cascardo/linux.git] / drivers / staging / brcm80211 / util / bcmsrom.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
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.
7  *
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.
15  */
16
17 #include <typedefs.h>
18 #include <bcmdefs.h>
19 #include <osl.h>
20 #include <stdarg.h>
21 #include <bcmutils.h>
22 #include <hndsoc.h>
23 #include <sbchipc.h>
24 #include <bcmdevs.h>
25 #include <bcmendian.h>
26 #include <pcicfg.h>
27 #include <siutils.h>
28 #include <bcmsrom.h>
29 #include <bcmsrom_tbl.h>
30 #ifdef BCMSDIO
31 #include <bcmsdh.h>
32 #include <sdio.h>
33 #endif
34
35 #include <bcmnvram.h>
36 #include <bcmotp.h>
37
38 #if defined(BCMSDIO)
39 #include <sbsdio.h>
40 #include <sbhnddma.h>
41 #include <sbsdpcmdev.h>
42 #endif
43
44 #include <proto/ethernet.h>     /* for sprom content groking */
45
46 #define BS_ERROR(args)
47
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))
52
53 #if defined(BCMDBG)
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 */
56 #endif
57
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 */
62 } varbuf_t;
63 extern char *_vars;
64 extern uint _varsz;
65
66 #define SROM_CIS_SINGLE 1
67
68 static int initvars_srom_si(si_t *sih, osl_t *osh, void *curmap, char **vars,
69                             uint *count);
70 static void _initvars_srom_pci(uint8 sromrev, uint16 *srom, uint off,
71                                varbuf_t *b);
72 static int initvars_srom_pci(si_t *sih, void *curmap, char **vars,
73                              uint *count);
74 static int initvars_flash_si(si_t *sih, char **vars, uint *count);
75 #ifdef BCMSDIO
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);
79 #endif                          /* BCMSDIO */
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);
84 #endif
85 static uint16 srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, uint32 cmd,
86                           uint wordoff, uint16 data);
87
88 static int initvars_table(osl_t *osh, char *start, char *end, char **vars,
89                           uint *count);
90 static int initvars_flash(si_t *sih, osl_t *osh, char **vp, uint len);
91
92 /* Initialization of varbuf structure */
93 static void BCMATTACHFN(varbuf_init) (varbuf_t *b, char *buf, uint size) {
94         b->size = size;
95         b->base = b->buf = buf;
96 }
97
98 /* append a null terminated var=value string */
99 static int BCMATTACHFN(varbuf_append) (varbuf_t *b, const char *fmt, ...) {
100         va_list ap;
101         int r;
102         size_t len;
103         char *s;
104
105         if (b->size < 2)
106                 return 0;
107
108         va_start(ap, fmt);
109         r = vsnprintf(b->buf, b->size, fmt, ap);
110         va_end(ap);
111
112         /* C99 snprintf behavior returns r >= size on overflow,
113          * others return -1 on overflow.
114          * All return -1 on format error.
115          * We need to leave room for 2 null terminations, one for the current var
116          * string, and one for final null of the var table. So check that the
117          * strlen written, r, leaves room for 2 chars.
118          */
119         if ((r == -1) || (r > (int)(b->size - 2))) {
120                 b->size = 0;
121                 return 0;
122         }
123
124         /* Remove any earlier occurrence of the same variable */
125         if ((s = strchr(b->buf, '=')) != NULL) {
126                 len = (size_t) (s - b->buf);
127                 for (s = b->base; s < b->buf;) {
128                         if ((bcmp(s, b->buf, len) == 0) && s[len] == '=') {
129                                 len = strlen(s) + 1;
130                                 memmove(s, (s + len),
131                                         ((b->buf + r + 1) - (s + len)));
132                                 b->buf -= len;
133                                 b->size += (unsigned int)len;
134                                 break;
135                         }
136
137                         while (*s++) ;
138                 }
139         }
140
141         /* skip over this string's null termination */
142         r++;
143         b->size -= r;
144         b->buf += r;
145
146         return r;
147 }
148
149 /*
150  * Initialize local vars from the right source for this platform.
151  * Return 0 on success, nonzero on error.
152  */
153 int
154 BCMATTACHFN(srom_var_init) (si_t *sih, uint bustype, void *curmap, osl_t *osh,
155                             char **vars, uint *count) {
156         uint len;
157
158         len = 0;
159
160         ASSERT(bustype == BUSTYPE(bustype));
161         if (vars == NULL || count == NULL)
162                 return (0);
163
164         *vars = NULL;
165         *count = 0;
166
167         switch (BUSTYPE(bustype)) {
168         case SI_BUS:
169         case JTAG_BUS:
170                 return initvars_srom_si(sih, osh, curmap, vars, count);
171
172         case PCI_BUS:
173                 ASSERT(curmap != NULL);
174                 if (curmap == NULL)
175                         return (-1);
176
177                 return initvars_srom_pci(sih, curmap, vars, count);
178
179 #ifdef BCMSDIO
180         case SDIO_BUS:
181                 return initvars_cis_sdio(osh, vars, count);
182 #endif                          /* BCMSDIO */
183
184         default:
185                 ASSERT(0);
186         }
187         return (-1);
188 }
189
190 /* support only 16-bit word read from srom */
191 int
192 srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
193           uint byteoff, uint nbytes, uint16 *buf, bool check_crc)
194 {
195         uint off, nw;
196 #ifdef BCMSDIO
197         uint i;
198 #endif                          /* BCMSDIO */
199
200         ASSERT(bustype == BUSTYPE(bustype));
201
202         /* check input - 16-bit access only */
203         if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > SROM_MAX)
204                 return 1;
205
206         off = byteoff / 2;
207         nw = nbytes / 2;
208
209         if (BUSTYPE(bustype) == PCI_BUS) {
210                 if (!curmap)
211                         return 1;
212
213                 if (si_is_sprom_available(sih)) {
214                         uint16 *srom;
215
216                         srom = (uint16 *) SROM_OFFSET(sih);
217                         if (srom == NULL)
218                                 return 1;
219
220                         if (sprom_read_pci
221                             (osh, sih, srom, off, buf, nw, check_crc))
222                                 return 1;
223                 }
224 #if defined(BCMNVRAMR)
225                 else {
226                         if (otp_read_pci(osh, sih, buf, SROM_MAX))
227                                 return 1;
228                 }
229 #endif
230 #ifdef BCMSDIO
231         } else if (BUSTYPE(bustype) == SDIO_BUS) {
232                 off = byteoff / 2;
233                 nw = nbytes / 2;
234                 for (i = 0; i < nw; i++) {
235                         if (sprom_read_sdio
236                             (osh, (uint16) (off + i), (uint16 *) (buf + i)))
237                                 return 1;
238                 }
239 #endif                          /* BCMSDIO */
240         } else if (BUSTYPE(bustype) == SI_BUS) {
241                 return 1;
242         } else {
243                 return 1;
244         }
245
246         return 0;
247 }
248
249 static const char BCMATTACHDATA(vstr_manf)[] = "manf=%s";
250 static const char BCMATTACHDATA(vstr_productname)[] = "productname=%s";
251 static const char BCMATTACHDATA(vstr_manfid)[] = "manfid=0x%x";
252 static const char BCMATTACHDATA(vstr_prodid)[] = "prodid=0x%x";
253 #ifdef BCMSDIO
254 static const char BCMATTACHDATA(vstr_sdmaxspeed)[] = "sdmaxspeed=%d";
255 static const char BCMATTACHDATA(vstr_sdmaxblk)[][13] =
256 {
257 "sdmaxblk0=%d", "sdmaxblk1=%d", "sdmaxblk2=%d"};
258 #endif
259 static const char BCMATTACHDATA(vstr_regwindowsz)[] = "regwindowsz=%d";
260 static const char BCMATTACHDATA(vstr_sromrev)[] = "sromrev=%d";
261 static const char BCMATTACHDATA(vstr_chiprev)[] = "chiprev=%d";
262 static const char BCMATTACHDATA(vstr_subvendid)[] = "subvendid=0x%x";
263 static const char BCMATTACHDATA(vstr_subdevid)[] = "subdevid=0x%x";
264 static const char BCMATTACHDATA(vstr_boardrev)[] = "boardrev=0x%x";
265 static const char BCMATTACHDATA(vstr_aa2g)[] = "aa2g=0x%x";
266 static const char BCMATTACHDATA(vstr_aa5g)[] = "aa5g=0x%x";
267 static const char BCMATTACHDATA(vstr_ag)[] = "ag%d=0x%x";
268 static const char BCMATTACHDATA(vstr_cc)[] = "cc=%d";
269 static const char BCMATTACHDATA(vstr_opo)[] = "opo=%d";
270 static const char BCMATTACHDATA(vstr_pa0b)[][9] =
271 {
272 "pa0b0=%d", "pa0b1=%d", "pa0b2=%d"};
273
274 static const char BCMATTACHDATA(vstr_pa0itssit)[] = "pa0itssit=%d";
275 static const char BCMATTACHDATA(vstr_pa0maxpwr)[] = "pa0maxpwr=%d";
276 static const char BCMATTACHDATA(vstr_pa1b)[][9] =
277 {
278 "pa1b0=%d", "pa1b1=%d", "pa1b2=%d"};
279
280 static const char BCMATTACHDATA(vstr_pa1lob)[][11] =
281 {
282 "pa1lob0=%d", "pa1lob1=%d", "pa1lob2=%d"};
283
284 static const char BCMATTACHDATA(vstr_pa1hib)[][11] =
285 {
286 "pa1hib0=%d", "pa1hib1=%d", "pa1hib2=%d"};
287
288 static const char BCMATTACHDATA(vstr_pa1itssit)[] = "pa1itssit=%d";
289 static const char BCMATTACHDATA(vstr_pa1maxpwr)[] = "pa1maxpwr=%d";
290 static const char BCMATTACHDATA(vstr_pa1lomaxpwr)[] = "pa1lomaxpwr=%d";
291 static const char BCMATTACHDATA(vstr_pa1himaxpwr)[] = "pa1himaxpwr=%d";
292 static const char BCMATTACHDATA(vstr_oem)[] =
293     "oem=%02x%02x%02x%02x%02x%02x%02x%02x";
294 static const char BCMATTACHDATA(vstr_boardflags)[] = "boardflags=0x%x";
295 static const char BCMATTACHDATA(vstr_boardflags2)[] = "boardflags2=0x%x";
296 static const char BCMATTACHDATA(vstr_ledbh)[] = "ledbh%d=0x%x";
297 static const char BCMATTACHDATA(vstr_noccode)[] = "ccode=0x0";
298 static const char BCMATTACHDATA(vstr_ccode)[] = "ccode=%c%c";
299 static const char BCMATTACHDATA(vstr_cctl)[] = "cctl=0x%x";
300 static const char BCMATTACHDATA(vstr_cckpo)[] = "cckpo=0x%x";
301 static const char BCMATTACHDATA(vstr_ofdmpo)[] = "ofdmpo=0x%x";
302 static const char BCMATTACHDATA(vstr_rdlid)[] = "rdlid=0x%x";
303 static const char BCMATTACHDATA(vstr_rdlrndis)[] = "rdlrndis=%d";
304 static const char BCMATTACHDATA(vstr_rdlrwu)[] = "rdlrwu=%d";
305 static const char BCMATTACHDATA(vstr_usbfs)[] = "usbfs=%d";
306 static const char BCMATTACHDATA(vstr_wpsgpio)[] = "wpsgpio=%d";
307 static const char BCMATTACHDATA(vstr_wpsled)[] = "wpsled=%d";
308 static const char BCMATTACHDATA(vstr_rdlsn)[] = "rdlsn=%d";
309 static const char BCMATTACHDATA(vstr_rssismf2g)[] = "rssismf2g=%d";
310 static const char BCMATTACHDATA(vstr_rssismc2g)[] = "rssismc2g=%d";
311 static const char BCMATTACHDATA(vstr_rssisav2g)[] = "rssisav2g=%d";
312 static const char BCMATTACHDATA(vstr_bxa2g)[] = "bxa2g=%d";
313 static const char BCMATTACHDATA(vstr_rssismf5g)[] = "rssismf5g=%d";
314 static const char BCMATTACHDATA(vstr_rssismc5g)[] = "rssismc5g=%d";
315 static const char BCMATTACHDATA(vstr_rssisav5g)[] = "rssisav5g=%d";
316 static const char BCMATTACHDATA(vstr_bxa5g)[] = "bxa5g=%d";
317 static const char BCMATTACHDATA(vstr_tri2g)[] = "tri2g=%d";
318 static const char BCMATTACHDATA(vstr_tri5gl)[] = "tri5gl=%d";
319 static const char BCMATTACHDATA(vstr_tri5g)[] = "tri5g=%d";
320 static const char BCMATTACHDATA(vstr_tri5gh)[] = "tri5gh=%d";
321 static const char BCMATTACHDATA(vstr_rxpo2g)[] = "rxpo2g=%d";
322 static const char BCMATTACHDATA(vstr_rxpo5g)[] = "rxpo5g=%d";
323 static const char BCMATTACHDATA(vstr_boardtype)[] = "boardtype=0x%x";
324 static const char BCMATTACHDATA(vstr_leddc)[] = "leddc=0x%04x";
325 static const char BCMATTACHDATA(vstr_vendid)[] = "vendid=0x%x";
326 static const char BCMATTACHDATA(vstr_devid)[] = "devid=0x%x";
327 static const char BCMATTACHDATA(vstr_xtalfreq)[] = "xtalfreq=%d";
328 static const char BCMATTACHDATA(vstr_txchain)[] = "txchain=0x%x";
329 static const char BCMATTACHDATA(vstr_rxchain)[] = "rxchain=0x%x";
330 static const char BCMATTACHDATA(vstr_antswitch)[] = "antswitch=0x%x";
331 static const char BCMATTACHDATA(vstr_regrev)[] = "regrev=0x%x";
332 static const char BCMATTACHDATA(vstr_antswctl2g)[] = "antswctl2g=0x%x";
333 static const char BCMATTACHDATA(vstr_triso2g)[] = "triso2g=0x%x";
334 static const char BCMATTACHDATA(vstr_pdetrange2g)[] = "pdetrange2g=0x%x";
335 static const char BCMATTACHDATA(vstr_extpagain2g)[] = "extpagain2g=0x%x";
336 static const char BCMATTACHDATA(vstr_tssipos2g)[] = "tssipos2g=0x%x";
337 static const char BCMATTACHDATA(vstr_antswctl5g)[] = "antswctl5g=0x%x";
338 static const char BCMATTACHDATA(vstr_triso5g)[] = "triso5g=0x%x";
339 static const char BCMATTACHDATA(vstr_pdetrange5g)[] = "pdetrange5g=0x%x";
340 static const char BCMATTACHDATA(vstr_extpagain5g)[] = "extpagain5g=0x%x";
341 static const char BCMATTACHDATA(vstr_tssipos5g)[] = "tssipos5g=0x%x";
342 static const char BCMATTACHDATA(vstr_maxp2ga0)[] = "maxp2ga0=0x%x";
343 static const char BCMATTACHDATA(vstr_itt2ga0)[] = "itt2ga0=0x%x";
344 static const char BCMATTACHDATA(vstr_pa)[] = "pa%dgw%da%d=0x%x";
345 static const char BCMATTACHDATA(vstr_pahl)[] = "pa%dg%cw%da%d=0x%x";
346 static const char BCMATTACHDATA(vstr_maxp5ga0)[] = "maxp5ga0=0x%x";
347 static const char BCMATTACHDATA(vstr_itt5ga0)[] = "itt5ga0=0x%x";
348 static const char BCMATTACHDATA(vstr_maxp5gha0)[] = "maxp5gha0=0x%x";
349 static const char BCMATTACHDATA(vstr_maxp5gla0)[] = "maxp5gla0=0x%x";
350 static const char BCMATTACHDATA(vstr_maxp2ga1)[] = "maxp2ga1=0x%x";
351 static const char BCMATTACHDATA(vstr_itt2ga1)[] = "itt2ga1=0x%x";
352 static const char BCMATTACHDATA(vstr_maxp5ga1)[] = "maxp5ga1=0x%x";
353 static const char BCMATTACHDATA(vstr_itt5ga1)[] = "itt5ga1=0x%x";
354 static const char BCMATTACHDATA(vstr_maxp5gha1)[] = "maxp5gha1=0x%x";
355 static const char BCMATTACHDATA(vstr_maxp5gla1)[] = "maxp5gla1=0x%x";
356 static const char BCMATTACHDATA(vstr_cck2gpo)[] = "cck2gpo=0x%x";
357 static const char BCMATTACHDATA(vstr_ofdm2gpo)[] = "ofdm2gpo=0x%x";
358 static const char BCMATTACHDATA(vstr_ofdm5gpo)[] = "ofdm5gpo=0x%x";
359 static const char BCMATTACHDATA(vstr_ofdm5glpo)[] = "ofdm5glpo=0x%x";
360 static const char BCMATTACHDATA(vstr_ofdm5ghpo)[] = "ofdm5ghpo=0x%x";
361 static const char BCMATTACHDATA(vstr_cddpo)[] = "cddpo=0x%x";
362 static const char BCMATTACHDATA(vstr_stbcpo)[] = "stbcpo=0x%x";
363 static const char BCMATTACHDATA(vstr_bw40po)[] = "bw40po=0x%x";
364 static const char BCMATTACHDATA(vstr_bwduppo)[] = "bwduppo=0x%x";
365 static const char BCMATTACHDATA(vstr_mcspo)[] = "mcs%dgpo%d=0x%x";
366 static const char BCMATTACHDATA(vstr_mcspohl)[] = "mcs%dg%cpo%d=0x%x";
367 static const char BCMATTACHDATA(vstr_custom)[] = "customvar%d=0x%x";
368 static const char BCMATTACHDATA(vstr_cckdigfilttype)[] = "cckdigfilttype=%d";
369 static const char BCMATTACHDATA(vstr_boardnum)[] = "boardnum=%d";
370 static const char BCMATTACHDATA(vstr_macaddr)[] = "macaddr=%s";
371 static const char BCMATTACHDATA(vstr_usbepnum)[] = "usbepnum=0x%x";
372 static const char BCMATTACHDATA(vstr_end)[] = "END\0";
373
374 uint8 patch_pair = 0;
375
376 /* For dongle HW, accept partial calibration parameters */
377 #define BCMDONGLECASE(n)
378
379 int
380 BCMATTACHFN(srom_parsecis) (osl_t *osh, uint8 *pcis[], uint ciscnt,
381                             char **vars, uint *count)
382 {
383         char eabuf[32];
384         char *base;
385         varbuf_t b;
386         uint8 *cis, tup, tlen, sromrev = 1;
387         int i, j;
388         bool ag_init = FALSE;
389         uint32 w32;
390         uint funcid;
391         uint cisnum;
392         int32 boardnum;
393         int err;
394         bool standard_cis;
395
396         ASSERT(vars != NULL);
397         ASSERT(count != NULL);
398
399         boardnum = -1;
400
401         base = MALLOC(osh, MAXSZ_NVRAM_VARS);
402         ASSERT(base != NULL);
403         if (!base)
404                 return -2;
405
406         varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
407         bzero(base, MAXSZ_NVRAM_VARS);
408         eabuf[0] = '\0';
409         for (cisnum = 0; cisnum < ciscnt; cisnum++) {
410                 cis = *pcis++;
411                 i = 0;
412                 funcid = 0;
413                 standard_cis = TRUE;
414                 do {
415                         if (standard_cis) {
416                                 tup = cis[i++];
417                                 if (tup == CISTPL_NULL || tup == CISTPL_END)
418                                         tlen = 0;
419                                 else
420                                         tlen = cis[i++];
421                         } else {
422                                 if (cis[i] == CISTPL_NULL
423                                     || cis[i] == CISTPL_END) {
424                                         tlen = 0;
425                                         tup = cis[i];
426                                 } else {
427                                         tlen = cis[i];
428                                         tup = CISTPL_BRCM_HNBU;
429                                 }
430                                 ++i;
431                         }
432                         if ((i + tlen) >= CIS_SIZE)
433                                 break;
434
435                         switch (tup) {
436                         case CISTPL_VERS_1:
437                                 /* assume the strings are good if the version field checks out */
438                                 if (((cis[i + 1] << 8) + cis[i]) >= 0x0008) {
439                                         varbuf_append(&b, vstr_manf,
440                                                       &cis[i + 2]);
441                                         varbuf_append(&b, vstr_productname,
442                                                       &cis[i + 3 +
443                                                            strlen((char *)
444                                                                   &cis[i +
445                                                                        2])]);
446                                         break;
447                                 }
448
449                         case CISTPL_MANFID:
450                                 varbuf_append(&b, vstr_manfid,
451                                               (cis[i + 1] << 8) + cis[i]);
452                                 varbuf_append(&b, vstr_prodid,
453                                               (cis[i + 3] << 8) + cis[i + 2]);
454                                 break;
455
456                         case CISTPL_FUNCID:
457                                 funcid = cis[i];
458                                 break;
459
460                         case CISTPL_FUNCE:
461                                 switch (funcid) {
462                                 case CISTPL_FID_SDIO:
463 #ifdef BCMSDIO
464                                         if (cis[i] == 0) {
465                                                 uint8 spd = cis[i + 3];
466                                                 static int base[] = {
467                                                         -1, 10, 12, 13, 15, 20,
468                                                             25, 30,
469                                                         35, 40, 45, 50, 55, 60,
470                                                             70, 80
471                                                 };
472                                                 static int mult[] = {
473                                                         10, 100, 1000, 10000,
474                                                         -1, -1, -1, -1
475                                                 };
476                                                 ASSERT((mult[spd & 0x7] != -1)
477                                                        &&
478                                                        (base
479                                                         [(spd >> 3) & 0x0f]));
480                                                 varbuf_append(&b,
481                                                               vstr_sdmaxblk[0],
482                                                               (cis[i + 2] << 8)
483                                                               + cis[i + 1]);
484                                                 varbuf_append(&b,
485                                                               vstr_sdmaxspeed,
486                                                               (mult[spd & 0x7] *
487                                                                base[(spd >> 3) &
488                                                                     0x0f]));
489                                         } else if (cis[i] == 1) {
490                                                 varbuf_append(&b,
491                                                               vstr_sdmaxblk
492                                                               [cisnum],
493                                                               (cis[i + 13] << 8)
494                                                               | cis[i + 12]);
495                                         }
496 #endif                          /* BCMSDIO */
497                                         funcid = 0;
498                                         break;
499                                 default:
500                                         /* set macaddr if HNBU_MACADDR not seen yet */
501                                         if (eabuf[0] == '\0'
502                                             && cis[i] == LAN_NID
503                                             && !(ETHER_ISNULLADDR(&cis[i + 2]))
504                                             && !(ETHER_ISMULTI(&cis[i + 2]))) {
505                                                 ASSERT(cis[i + 1] ==
506                                                        ETHER_ADDR_LEN);
507                                                 bcm_ether_ntoa((struct
508                                                                 ether_addr *)
509                                                                &cis[i + 2],
510                                                                eabuf);
511
512                                                 /* set boardnum if HNBU_BOARDNUM not seen yet */
513                                                 if (boardnum == -1)
514                                                         boardnum =
515                                                             (cis[i + 6] << 8) +
516                                                             cis[i + 7];
517                                         }
518                                         break;
519                                 }
520                                 break;
521
522                         case CISTPL_CFTABLE:
523                                 varbuf_append(&b, vstr_regwindowsz,
524                                               (cis[i + 7] << 8) | cis[i + 6]);
525                                 break;
526
527                         case CISTPL_BRCM_HNBU:
528                                 switch (cis[i]) {
529                                 case HNBU_SROMREV:
530                                         sromrev = cis[i + 1];
531                                         varbuf_append(&b, vstr_sromrev,
532                                                       sromrev);
533                                         break;
534
535                                 case HNBU_XTALFREQ:
536                                         varbuf_append(&b, vstr_xtalfreq,
537                                                       (cis[i + 4] << 24) |
538                                                       (cis[i + 3] << 16) |
539                                                       (cis[i + 2] << 8) |
540                                                       cis[i + 1]);
541                                         break;
542
543                                 case HNBU_CHIPID:
544                                         varbuf_append(&b, vstr_vendid,
545                                                       (cis[i + 2] << 8) +
546                                                       cis[i + 1]);
547                                         varbuf_append(&b, vstr_devid,
548                                                       (cis[i + 4] << 8) +
549                                                       cis[i + 3]);
550                                         if (tlen >= 7) {
551                                                 varbuf_append(&b, vstr_chiprev,
552                                                               (cis[i + 6] << 8)
553                                                               + cis[i + 5]);
554                                         }
555                                         if (tlen >= 9) {
556                                                 varbuf_append(&b,
557                                                               vstr_subvendid,
558                                                               (cis[i + 8] << 8)
559                                                               + cis[i + 7]);
560                                         }
561                                         if (tlen >= 11) {
562                                                 varbuf_append(&b, vstr_subdevid,
563                                                               (cis[i + 10] << 8)
564                                                               + cis[i + 9]);
565                                                 /* subdevid doubles for boardtype */
566                                                 varbuf_append(&b,
567                                                               vstr_boardtype,
568                                                               (cis[i + 10] << 8)
569                                                               + cis[i + 9]);
570                                         }
571                                         break;
572
573                                 case HNBU_BOARDNUM:
574                                         boardnum =
575                                             (cis[i + 2] << 8) + cis[i + 1];
576                                         break;
577
578                                 case HNBU_PATCH:
579                                         {
580                                                 char vstr_paddr[16];
581                                                 char vstr_pdata[16];
582
583                                                 /* retrieve the patch pairs
584                                                  * from tlen/6; where 6 is
585                                                  * sizeof(patch addr(2)) +
586                                                  * sizeof(patch data(4)).
587                                                  */
588                                                 patch_pair = tlen / 6;
589
590                                                 for (j = 0; j < patch_pair; j++) {
591                                                         snprintf(vstr_paddr,
592                                                                  sizeof
593                                                                  (vstr_paddr),
594                                                                  "pa%d=0x%%x",
595                                                                  j);
596                                                         snprintf(vstr_pdata,
597                                                                  sizeof
598                                                                  (vstr_pdata),
599                                                                  "pd%d=0x%%x",
600                                                                  j);
601
602                                                         varbuf_append(&b,
603                                                                       vstr_paddr,
604                                                                       (cis
605                                                                        [i +
606                                                                         (j *
607                                                                          6) +
608                                                                         2] << 8)
609                                                                       | cis[i +
610                                                                             (j *
611                                                                              6)
612                                                                             +
613                                                                             1]);
614
615                                                         varbuf_append(&b,
616                                                                       vstr_pdata,
617                                                                       (cis
618                                                                        [i +
619                                                                         (j *
620                                                                          6) +
621                                                                         6] <<
622                                                                        24) |
623                                                                       (cis
624                                                                        [i +
625                                                                         (j *
626                                                                          6) +
627                                                                         5] <<
628                                                                        16) |
629                                                                       (cis
630                                                                        [i +
631                                                                         (j *
632                                                                          6) +
633                                                                         4] << 8)
634                                                                       | cis[i +
635                                                                             (j *
636                                                                              6)
637                                                                             +
638                                                                             3]);
639                                                 }
640                                         }
641                                         break;
642
643                                 case HNBU_BOARDREV:
644                                         if (tlen == 2)
645                                                 varbuf_append(&b, vstr_boardrev,
646                                                               cis[i + 1]);
647                                         else
648                                                 varbuf_append(&b, vstr_boardrev,
649                                                               (cis[i + 2] << 8)
650                                                               + cis[i + 1]);
651                                         break;
652
653                                 case HNBU_BOARDFLAGS:
654                                         w32 = (cis[i + 2] << 8) + cis[i + 1];
655                                         if (tlen >= 5)
656                                                 w32 |=
657                                                     ((cis[i + 4] << 24) +
658                                                      (cis[i + 3] << 16));
659                                         varbuf_append(&b, vstr_boardflags, w32);
660
661                                         if (tlen >= 7) {
662                                                 w32 =
663                                                     (cis[i + 6] << 8) + cis[i +
664                                                                             5];
665                                                 if (tlen >= 9)
666                                                         w32 |=
667                                                             ((cis[i + 8] << 24)
668                                                              +
669                                                              (cis[i + 7] <<
670                                                               16));
671                                                 varbuf_append(&b,
672                                                               vstr_boardflags2,
673                                                               w32);
674                                         }
675                                         break;
676
677                                 case HNBU_USBFS:
678                                         varbuf_append(&b, vstr_usbfs,
679                                                       cis[i + 1]);
680                                         break;
681
682                                 case HNBU_BOARDTYPE:
683                                         varbuf_append(&b, vstr_boardtype,
684                                                       (cis[i + 2] << 8) +
685                                                       cis[i + 1]);
686                                         break;
687
688                                 case HNBU_HNBUCIS:
689                                         /*
690                                          * what follows is a nonstandard HNBU CIS
691                                          * that lacks CISTPL_BRCM_HNBU tags
692                                          *
693                                          * skip 0xff (end of standard CIS)
694                                          * after this tuple
695                                          */
696                                         tlen++;
697                                         standard_cis = FALSE;
698                                         break;
699
700                                 case HNBU_USBEPNUM:
701                                         varbuf_append(&b, vstr_usbepnum,
702                                                       (cis[i + 2] << 8) | cis[i
703                                                                               +
704                                                                               1]);
705                                         break;
706
707                                 case HNBU_AA:
708                                         varbuf_append(&b, vstr_aa2g,
709                                                       cis[i + 1]);
710                                         if (tlen >= 3)
711                                                 varbuf_append(&b, vstr_aa5g,
712                                                               cis[i + 2]);
713                                         break;
714
715                                 case HNBU_AG:
716                                         varbuf_append(&b, vstr_ag, 0,
717                                                       cis[i + 1]);
718                                         if (tlen >= 3)
719                                                 varbuf_append(&b, vstr_ag, 1,
720                                                               cis[i + 2]);
721                                         if (tlen >= 4)
722                                                 varbuf_append(&b, vstr_ag, 2,
723                                                               cis[i + 3]);
724                                         if (tlen >= 5)
725                                                 varbuf_append(&b, vstr_ag, 3,
726                                                               cis[i + 4]);
727                                         ag_init = TRUE;
728                                         break;
729
730                                 case HNBU_ANT5G:
731                                         varbuf_append(&b, vstr_aa5g,
732                                                       cis[i + 1]);
733                                         varbuf_append(&b, vstr_ag, 1,
734                                                       cis[i + 2]);
735                                         break;
736
737                                 case HNBU_CC:
738                                         ASSERT(sromrev == 1);
739                                         varbuf_append(&b, vstr_cc, cis[i + 1]);
740                                         break;
741
742                                 case HNBU_PAPARMS:
743                                         switch (tlen) {
744                                         case 2:
745                                                 ASSERT(sromrev == 1);
746                                                 varbuf_append(&b,
747                                                               vstr_pa0maxpwr,
748                                                               cis[i + 1]);
749                                                 break;
750                                         case 10:
751                                                 ASSERT(sromrev >= 2);
752                                                 varbuf_append(&b, vstr_opo,
753                                                               cis[i + 9]);
754                                                 /* FALLTHROUGH */
755                                         case 9:
756                                                 varbuf_append(&b,
757                                                               vstr_pa0maxpwr,
758                                                               cis[i + 8]);
759                                                 /* FALLTHROUGH */
760                                                 BCMDONGLECASE(8)
761                                                     varbuf_append(&b,
762                                                                   vstr_pa0itssit,
763                                                                   cis[i + 7]);
764                                                 /* FALLTHROUGH */
765                                                 BCMDONGLECASE(7)
766                                                     for (j = 0; j < 3; j++) {
767                                                         varbuf_append(&b,
768                                                                       vstr_pa0b
769                                                                       [j],
770                                                                       (cis
771                                                                        [i +
772                                                                         (j *
773                                                                          2) +
774                                                                         2] << 8)
775                                                                       + cis[i +
776                                                                             (j *
777                                                                              2)
778                                                                             +
779                                                                             1]);
780                                                 }
781                                                 break;
782                                         default:
783                                                 ASSERT((tlen == 2)
784                                                        || (tlen == 9)
785                                                        || (tlen == 10));
786                                                 break;
787                                         }
788                                         break;
789
790                                 case HNBU_PAPARMS5G:
791                                         ASSERT((sromrev == 2)
792                                                || (sromrev == 3));
793                                         switch (tlen) {
794                                         case 23:
795                                                 varbuf_append(&b,
796                                                               vstr_pa1himaxpwr,
797                                                               cis[i + 22]);
798                                                 varbuf_append(&b,
799                                                               vstr_pa1lomaxpwr,
800                                                               cis[i + 21]);
801                                                 varbuf_append(&b,
802                                                               vstr_pa1maxpwr,
803                                                               cis[i + 20]);
804                                                 /* FALLTHROUGH */
805                                         case 20:
806                                                 varbuf_append(&b,
807                                                               vstr_pa1itssit,
808                                                               cis[i + 19]);
809                                                 /* FALLTHROUGH */
810                                         case 19:
811                                                 for (j = 0; j < 3; j++) {
812                                                         varbuf_append(&b,
813                                                                       vstr_pa1b
814                                                                       [j],
815                                                                       (cis
816                                                                        [i +
817                                                                         (j *
818                                                                          2) +
819                                                                         2] << 8)
820                                                                       + cis[i +
821                                                                             (j *
822                                                                              2)
823                                                                             +
824                                                                             1]);
825                                                 }
826                                                 for (j = 3; j < 6; j++) {
827                                                         varbuf_append(&b,
828                                                                       vstr_pa1lob
829                                                                       [j - 3],
830                                                                       (cis
831                                                                        [i +
832                                                                         (j *
833                                                                          2) +
834                                                                         2] << 8)
835                                                                       + cis[i +
836                                                                             (j *
837                                                                              2)
838                                                                             +
839                                                                             1]);
840                                                 }
841                                                 for (j = 6; j < 9; j++) {
842                                                         varbuf_append(&b,
843                                                                       vstr_pa1hib
844                                                                       [j - 6],
845                                                                       (cis
846                                                                        [i +
847                                                                         (j *
848                                                                          2) +
849                                                                         2] << 8)
850                                                                       + cis[i +
851                                                                             (j *
852                                                                              2)
853                                                                             +
854                                                                             1]);
855                                                 }
856                                                 break;
857                                         default:
858                                                 ASSERT((tlen == 19) ||
859                                                        (tlen == 20)
860                                                        || (tlen == 23));
861                                                 break;
862                                         }
863                                         break;
864
865                                 case HNBU_OEM:
866                                         ASSERT(sromrev == 1);
867                                         varbuf_append(&b, vstr_oem,
868                                                       cis[i + 1], cis[i + 2],
869                                                       cis[i + 3], cis[i + 4],
870                                                       cis[i + 5], cis[i + 6],
871                                                       cis[i + 7], cis[i + 8]);
872                                         break;
873
874                                 case HNBU_LEDS:
875                                         for (j = 1; j <= 4; j++) {
876                                                 if (cis[i + j] != 0xff) {
877                                                         varbuf_append(&b,
878                                                                       vstr_ledbh,
879                                                                       j - 1,
880                                                                       cis[i +
881                                                                           j]);
882                                                 }
883                                         }
884                                         break;
885
886                                 case HNBU_CCODE:
887                                         ASSERT(sromrev > 1);
888                                         if ((cis[i + 1] == 0)
889                                             || (cis[i + 2] == 0))
890                                                 varbuf_append(&b, vstr_noccode);
891                                         else
892                                                 varbuf_append(&b, vstr_ccode,
893                                                               cis[i + 1],
894                                                               cis[i + 2]);
895                                         varbuf_append(&b, vstr_cctl,
896                                                       cis[i + 3]);
897                                         break;
898
899                                 case HNBU_CCKPO:
900                                         ASSERT(sromrev > 2);
901                                         varbuf_append(&b, vstr_cckpo,
902                                                       (cis[i + 2] << 8) | cis[i
903                                                                               +
904                                                                               1]);
905                                         break;
906
907                                 case HNBU_OFDMPO:
908                                         ASSERT(sromrev > 2);
909                                         varbuf_append(&b, vstr_ofdmpo,
910                                                       (cis[i + 4] << 24) |
911                                                       (cis[i + 3] << 16) |
912                                                       (cis[i + 2] << 8) |
913                                                       cis[i + 1]);
914                                         break;
915
916                                 case HNBU_WPS:
917                                         varbuf_append(&b, vstr_wpsgpio,
918                                                       cis[i + 1]);
919                                         if (tlen >= 3)
920                                                 varbuf_append(&b, vstr_wpsled,
921                                                               cis[i + 2]);
922                                         break;
923
924                                 case HNBU_RSSISMBXA2G:
925                                         ASSERT(sromrev == 3);
926                                         varbuf_append(&b, vstr_rssismf2g,
927                                                       cis[i + 1] & 0xf);
928                                         varbuf_append(&b, vstr_rssismc2g,
929                                                       (cis[i + 1] >> 4) & 0xf);
930                                         varbuf_append(&b, vstr_rssisav2g,
931                                                       cis[i + 2] & 0x7);
932                                         varbuf_append(&b, vstr_bxa2g,
933                                                       (cis[i + 2] >> 3) & 0x3);
934                                         break;
935
936                                 case HNBU_RSSISMBXA5G:
937                                         ASSERT(sromrev == 3);
938                                         varbuf_append(&b, vstr_rssismf5g,
939                                                       cis[i + 1] & 0xf);
940                                         varbuf_append(&b, vstr_rssismc5g,
941                                                       (cis[i + 1] >> 4) & 0xf);
942                                         varbuf_append(&b, vstr_rssisav5g,
943                                                       cis[i + 2] & 0x7);
944                                         varbuf_append(&b, vstr_bxa5g,
945                                                       (cis[i + 2] >> 3) & 0x3);
946                                         break;
947
948                                 case HNBU_TRI2G:
949                                         ASSERT(sromrev == 3);
950                                         varbuf_append(&b, vstr_tri2g,
951                                                       cis[i + 1]);
952                                         break;
953
954                                 case HNBU_TRI5G:
955                                         ASSERT(sromrev == 3);
956                                         varbuf_append(&b, vstr_tri5gl,
957                                                       cis[i + 1]);
958                                         varbuf_append(&b, vstr_tri5g,
959                                                       cis[i + 2]);
960                                         varbuf_append(&b, vstr_tri5gh,
961                                                       cis[i + 3]);
962                                         break;
963
964                                 case HNBU_RXPO2G:
965                                         ASSERT(sromrev == 3);
966                                         varbuf_append(&b, vstr_rxpo2g,
967                                                       cis[i + 1]);
968                                         break;
969
970                                 case HNBU_RXPO5G:
971                                         ASSERT(sromrev == 3);
972                                         varbuf_append(&b, vstr_rxpo5g,
973                                                       cis[i + 1]);
974                                         break;
975
976                                 case HNBU_MACADDR:
977                                         if (!(ETHER_ISNULLADDR(&cis[i + 1])) &&
978                                             !(ETHER_ISMULTI(&cis[i + 1]))) {
979                                                 bcm_ether_ntoa((struct
980                                                                 ether_addr *)
981                                                                &cis[i + 1],
982                                                                eabuf);
983
984                                                 /* set boardnum if HNBU_BOARDNUM not seen yet */
985                                                 if (boardnum == -1)
986                                                         boardnum =
987                                                             (cis[i + 5] << 8) +
988                                                             cis[i + 6];
989                                         }
990                                         break;
991
992                                 case HNBU_LEDDC:
993                                         /* CIS leddc only has 16bits, convert it to 32bits */
994                                         w32 = ((cis[i + 2] << 24) |     /* oncount */
995                                                (cis[i + 1] << 8));      /* offcount */
996                                         varbuf_append(&b, vstr_leddc, w32);
997                                         break;
998
999                                 case HNBU_CHAINSWITCH:
1000                                         varbuf_append(&b, vstr_txchain,
1001                                                       cis[i + 1]);
1002                                         varbuf_append(&b, vstr_rxchain,
1003                                                       cis[i + 2]);
1004                                         varbuf_append(&b, vstr_antswitch,
1005                                                       (cis[i + 4] << 8) +
1006                                                       cis[i + 3]);
1007                                         break;
1008
1009                                 case HNBU_REGREV:
1010                                         varbuf_append(&b, vstr_regrev,
1011                                                       cis[i + 1]);
1012                                         break;
1013
1014                                 case HNBU_FEM:{
1015                                                 uint16 fem =
1016                                                     (cis[i + 2] << 8) + cis[i +
1017                                                                             1];
1018                                                 varbuf_append(&b,
1019                                                               vstr_antswctl2g,
1020                                                               (fem &
1021                                                                SROM8_FEM_ANTSWLUT_MASK)
1022                                                               >>
1023                                                               SROM8_FEM_ANTSWLUT_SHIFT);
1024                                                 varbuf_append(&b, vstr_triso2g,
1025                                                               (fem &
1026                                                                SROM8_FEM_TR_ISO_MASK)
1027                                                               >>
1028                                                               SROM8_FEM_TR_ISO_SHIFT);
1029                                                 varbuf_append(&b,
1030                                                               vstr_pdetrange2g,
1031                                                               (fem &
1032                                                                SROM8_FEM_PDET_RANGE_MASK)
1033                                                               >>
1034                                                               SROM8_FEM_PDET_RANGE_SHIFT);
1035                                                 varbuf_append(&b,
1036                                                               vstr_extpagain2g,
1037                                                               (fem &
1038                                                                SROM8_FEM_EXTPA_GAIN_MASK)
1039                                                               >>
1040                                                               SROM8_FEM_EXTPA_GAIN_SHIFT);
1041                                                 varbuf_append(&b,
1042                                                               vstr_tssipos2g,
1043                                                               (fem &
1044                                                                SROM8_FEM_TSSIPOS_MASK)
1045                                                               >>
1046                                                               SROM8_FEM_TSSIPOS_SHIFT);
1047                                                 if (tlen < 5)
1048                                                         break;
1049
1050                                                 fem =
1051                                                     (cis[i + 4] << 8) + cis[i +
1052                                                                             3];
1053                                                 varbuf_append(&b,
1054                                                               vstr_antswctl5g,
1055                                                               (fem &
1056                                                                SROM8_FEM_ANTSWLUT_MASK)
1057                                                               >>
1058                                                               SROM8_FEM_ANTSWLUT_SHIFT);
1059                                                 varbuf_append(&b, vstr_triso5g,
1060                                                               (fem &
1061                                                                SROM8_FEM_TR_ISO_MASK)
1062                                                               >>
1063                                                               SROM8_FEM_TR_ISO_SHIFT);
1064                                                 varbuf_append(&b,
1065                                                               vstr_pdetrange5g,
1066                                                               (fem &
1067                                                                SROM8_FEM_PDET_RANGE_MASK)
1068                                                               >>
1069                                                               SROM8_FEM_PDET_RANGE_SHIFT);
1070                                                 varbuf_append(&b,
1071                                                               vstr_extpagain5g,
1072                                                               (fem &
1073                                                                SROM8_FEM_EXTPA_GAIN_MASK)
1074                                                               >>
1075                                                               SROM8_FEM_EXTPA_GAIN_SHIFT);
1076                                                 varbuf_append(&b,
1077                                                               vstr_tssipos5g,
1078                                                               (fem &
1079                                                                SROM8_FEM_TSSIPOS_MASK)
1080                                                               >>
1081                                                               SROM8_FEM_TSSIPOS_SHIFT);
1082                                                 break;
1083                                         }
1084
1085                                 case HNBU_PAPARMS_C0:
1086                                         varbuf_append(&b, vstr_maxp2ga0,
1087                                                       cis[i + 1]);
1088                                         varbuf_append(&b, vstr_itt2ga0,
1089                                                       cis[i + 2]);
1090                                         varbuf_append(&b, vstr_pa, 2, 0, 0,
1091                                                       (cis[i + 4] << 8) +
1092                                                       cis[i + 3]);
1093                                         varbuf_append(&b, vstr_pa, 2, 1, 0,
1094                                                       (cis[i + 6] << 8) +
1095                                                       cis[i + 5]);
1096                                         varbuf_append(&b, vstr_pa, 2, 2, 0,
1097                                                       (cis[i + 8] << 8) +
1098                                                       cis[i + 7]);
1099                                         if (tlen < 31)
1100                                                 break;
1101
1102                                         varbuf_append(&b, vstr_maxp5ga0,
1103                                                       cis[i + 9]);
1104                                         varbuf_append(&b, vstr_itt5ga0,
1105                                                       cis[i + 10]);
1106                                         varbuf_append(&b, vstr_maxp5gha0,
1107                                                       cis[i + 11]);
1108                                         varbuf_append(&b, vstr_maxp5gla0,
1109                                                       cis[i + 12]);
1110                                         varbuf_append(&b, vstr_pa, 5, 0, 0,
1111                                                       (cis[i + 14] << 8) +
1112                                                       cis[i + 13]);
1113                                         varbuf_append(&b, vstr_pa, 5, 1, 0,
1114                                                       (cis[i + 16] << 8) +
1115                                                       cis[i + 15]);
1116                                         varbuf_append(&b, vstr_pa, 5, 2, 0,
1117                                                       (cis[i + 18] << 8) +
1118                                                       cis[i + 17]);
1119                                         varbuf_append(&b, vstr_pahl, 5, 'l', 0,
1120                                                       0,
1121                                                       (cis[i + 20] << 8) +
1122                                                       cis[i + 19]);
1123                                         varbuf_append(&b, vstr_pahl, 5, 'l', 1,
1124                                                       0,
1125                                                       (cis[i + 22] << 8) +
1126                                                       cis[i + 21]);
1127                                         varbuf_append(&b, vstr_pahl, 5, 'l', 2,
1128                                                       0,
1129                                                       (cis[i + 24] << 8) +
1130                                                       cis[i + 23]);
1131                                         varbuf_append(&b, vstr_pahl, 5, 'h', 0,
1132                                                       0,
1133                                                       (cis[i + 26] << 8) +
1134                                                       cis[i + 25]);
1135                                         varbuf_append(&b, vstr_pahl, 5, 'h', 1,
1136                                                       0,
1137                                                       (cis[i + 28] << 8) +
1138                                                       cis[i + 27]);
1139                                         varbuf_append(&b, vstr_pahl, 5, 'h', 2,
1140                                                       0,
1141                                                       (cis[i + 30] << 8) +
1142                                                       cis[i + 29]);
1143                                         break;
1144
1145                                 case HNBU_PAPARMS_C1:
1146                                         varbuf_append(&b, vstr_maxp2ga1,
1147                                                       cis[i + 1]);
1148                                         varbuf_append(&b, vstr_itt2ga1,
1149                                                       cis[i + 2]);
1150                                         varbuf_append(&b, vstr_pa, 2, 0, 1,
1151                                                       (cis[i + 4] << 8) +
1152                                                       cis[i + 3]);
1153                                         varbuf_append(&b, vstr_pa, 2, 1, 1,
1154                                                       (cis[i + 6] << 8) +
1155                                                       cis[i + 5]);
1156                                         varbuf_append(&b, vstr_pa, 2, 2, 1,
1157                                                       (cis[i + 8] << 8) +
1158                                                       cis[i + 7]);
1159                                         if (tlen < 31)
1160                                                 break;
1161
1162                                         varbuf_append(&b, vstr_maxp5ga1,
1163                                                       cis[i + 9]);
1164                                         varbuf_append(&b, vstr_itt5ga1,
1165                                                       cis[i + 10]);
1166                                         varbuf_append(&b, vstr_maxp5gha1,
1167                                                       cis[i + 11]);
1168                                         varbuf_append(&b, vstr_maxp5gla1,
1169                                                       cis[i + 12]);
1170                                         varbuf_append(&b, vstr_pa, 5, 0, 1,
1171                                                       (cis[i + 14] << 8) +
1172                                                       cis[i + 13]);
1173                                         varbuf_append(&b, vstr_pa, 5, 1, 1,
1174                                                       (cis[i + 16] << 8) +
1175                                                       cis[i + 15]);
1176                                         varbuf_append(&b, vstr_pa, 5, 2, 1,
1177                                                       (cis[i + 18] << 8) +
1178                                                       cis[i + 17]);
1179                                         varbuf_append(&b, vstr_pahl, 5, 'l', 0,
1180                                                       1,
1181                                                       (cis[i + 20] << 8) +
1182                                                       cis[i + 19]);
1183                                         varbuf_append(&b, vstr_pahl, 5, 'l', 1,
1184                                                       1,
1185                                                       (cis[i + 22] << 8) +
1186                                                       cis[i + 21]);
1187                                         varbuf_append(&b, vstr_pahl, 5, 'l', 2,
1188                                                       1,
1189                                                       (cis[i + 24] << 8) +
1190                                                       cis[i + 23]);
1191                                         varbuf_append(&b, vstr_pahl, 5, 'h', 0,
1192                                                       1,
1193                                                       (cis[i + 26] << 8) +
1194                                                       cis[i + 25]);
1195                                         varbuf_append(&b, vstr_pahl, 5, 'h', 1,
1196                                                       1,
1197                                                       (cis[i + 28] << 8) +
1198                                                       cis[i + 27]);
1199                                         varbuf_append(&b, vstr_pahl, 5, 'h', 2,
1200                                                       1,
1201                                                       (cis[i + 30] << 8) +
1202                                                       cis[i + 29]);
1203                                         break;
1204
1205                                 case HNBU_PO_CCKOFDM:
1206                                         varbuf_append(&b, vstr_cck2gpo,
1207                                                       (cis[i + 2] << 8) +
1208                                                       cis[i + 1]);
1209                                         varbuf_append(&b, vstr_ofdm2gpo,
1210                                                       (cis[i + 6] << 24) +
1211                                                       (cis[i + 5] << 16) +
1212                                                       (cis[i + 4] << 8) +
1213                                                       cis[i + 3]);
1214                                         if (tlen < 19)
1215                                                 break;
1216
1217                                         varbuf_append(&b, vstr_ofdm5gpo,
1218                                                       (cis[i + 10] << 24) +
1219                                                       (cis[i + 9] << 16) +
1220                                                       (cis[i + 8] << 8) +
1221                                                       cis[i + 7]);
1222                                         varbuf_append(&b, vstr_ofdm5glpo,
1223                                                       (cis[i + 14] << 24) +
1224                                                       (cis[i + 13] << 16) +
1225                                                       (cis[i + 12] << 8) +
1226                                                       cis[i + 11]);
1227                                         varbuf_append(&b, vstr_ofdm5ghpo,
1228                                                       (cis[i + 18] << 24) +
1229                                                       (cis[i + 17] << 16) +
1230                                                       (cis[i + 16] << 8) +
1231                                                       cis[i + 15]);
1232                                         break;
1233
1234                                 case HNBU_PO_MCS2G:
1235                                         for (j = 0; j <= (tlen / 2); j++) {
1236                                                 varbuf_append(&b, vstr_mcspo, 2,
1237                                                               j,
1238                                                               (cis
1239                                                                [i + 2 +
1240                                                                 2 * j] << 8) +
1241                                                               cis[i + 1 +
1242                                                                   2 * j]);
1243                                         }
1244                                         break;
1245
1246                                 case HNBU_PO_MCS5GM:
1247                                         for (j = 0; j <= (tlen / 2); j++) {
1248                                                 varbuf_append(&b, vstr_mcspo, 5,
1249                                                               j,
1250                                                               (cis
1251                                                                [i + 2 +
1252                                                                 2 * j] << 8) +
1253                                                               cis[i + 1 +
1254                                                                   2 * j]);
1255                                         }
1256                                         break;
1257
1258                                 case HNBU_PO_MCS5GLH:
1259                                         for (j = 0; j <= (tlen / 4); j++) {
1260                                                 varbuf_append(&b, vstr_mcspohl,
1261                                                               5, 'l', j,
1262                                                               (cis
1263                                                                [i + 2 +
1264                                                                 2 * j] << 8) +
1265                                                               cis[i + 1 +
1266                                                                   2 * j]);
1267                                         }
1268
1269                                         for (j = 0; j <= (tlen / 4); j++) {
1270                                                 varbuf_append(&b, vstr_mcspohl,
1271                                                               5, 'h', j,
1272                                                               (cis
1273                                                                [i +
1274                                                                 ((tlen / 2) +
1275                                                                  2) +
1276                                                                 2 * j] << 8) +
1277                                                               cis[i +
1278                                                                   ((tlen / 2) +
1279                                                                    1) + 2 * j]);
1280                                         }
1281
1282                                         break;
1283
1284                                 case HNBU_PO_CDD:
1285                                         varbuf_append(&b, vstr_cddpo,
1286                                                       (cis[i + 2] << 8) +
1287                                                       cis[i + 1]);
1288                                         break;
1289
1290                                 case HNBU_PO_STBC:
1291                                         varbuf_append(&b, vstr_stbcpo,
1292                                                       (cis[i + 2] << 8) +
1293                                                       cis[i + 1]);
1294                                         break;
1295
1296                                 case HNBU_PO_40M:
1297                                         varbuf_append(&b, vstr_bw40po,
1298                                                       (cis[i + 2] << 8) +
1299                                                       cis[i + 1]);
1300                                         break;
1301
1302                                 case HNBU_PO_40MDUP:
1303                                         varbuf_append(&b, vstr_bwduppo,
1304                                                       (cis[i + 2] << 8) +
1305                                                       cis[i + 1]);
1306                                         break;
1307
1308                                 case HNBU_OFDMPO5G:
1309                                         varbuf_append(&b, vstr_ofdm5gpo,
1310                                                       (cis[i + 4] << 24) +
1311                                                       (cis[i + 3] << 16) +
1312                                                       (cis[i + 2] << 8) +
1313                                                       cis[i + 1]);
1314                                         varbuf_append(&b, vstr_ofdm5glpo,
1315                                                       (cis[i + 8] << 24) +
1316                                                       (cis[i + 7] << 16) +
1317                                                       (cis[i + 6] << 8) +
1318                                                       cis[i + 5]);
1319                                         varbuf_append(&b, vstr_ofdm5ghpo,
1320                                                       (cis[i + 12] << 24) +
1321                                                       (cis[i + 11] << 16) +
1322                                                       (cis[i + 10] << 8) +
1323                                                       cis[i + 9]);
1324                                         break;
1325
1326                                 case HNBU_CUSTOM1:
1327                                         varbuf_append(&b, vstr_custom, 1,
1328                                                       ((cis[i + 4] << 24) +
1329                                                        (cis[i + 3] << 16) +
1330                                                        (cis[i + 2] << 8) +
1331                                                        cis[i + 1]));
1332                                         break;
1333
1334 #if defined(BCMSDIO)
1335                                 case HNBU_SROM3SWRGN:
1336                                         if (tlen >= 73) {
1337                                                 uint16 srom[35];
1338                                                 uint8 srev = cis[i + 1 + 70];
1339                                                 ASSERT(srev == 3);
1340                                                 /* make tuple value 16-bit aligned and parse it */
1341                                                 bcopy(&cis[i + 1], srom,
1342                                                       sizeof(srom));
1343                                                 _initvars_srom_pci(srev, srom,
1344                                                                    SROM3_SWRGN_OFF,
1345                                                                    &b);
1346                                                 /* 2.4G antenna gain is included in SROM */
1347                                                 ag_init = TRUE;
1348                                                 /* Ethernet MAC address is included in SROM */
1349                                                 eabuf[0] = 0;
1350                                                 boardnum = -1;
1351                                         }
1352                                         /* create extra variables */
1353                                         if (tlen >= 75)
1354                                                 varbuf_append(&b, vstr_vendid,
1355                                                               (cis[i + 1 + 73]
1356                                                                << 8) + cis[i +
1357                                                                            1 +
1358                                                                            72]);
1359                                         if (tlen >= 77)
1360                                                 varbuf_append(&b, vstr_devid,
1361                                                               (cis[i + 1 + 75]
1362                                                                << 8) + cis[i +
1363                                                                            1 +
1364                                                                            74]);
1365                                         if (tlen >= 79)
1366                                                 varbuf_append(&b, vstr_xtalfreq,
1367                                                               (cis[i + 1 + 77]
1368                                                                << 8) + cis[i +
1369                                                                            1 +
1370                                                                            76]);
1371                                         break;
1372 #endif                          /* defined(BCMSDIO) */
1373
1374                                 case HNBU_CCKFILTTYPE:
1375                                         varbuf_append(&b, vstr_cckdigfilttype,
1376                                                       (cis[i + 1]));
1377                                         break;
1378                                 }
1379
1380                                 break;
1381                         }
1382                         i += tlen;
1383                 } while (tup != CISTPL_END);
1384         }
1385
1386         if (boardnum != -1) {
1387                 varbuf_append(&b, vstr_boardnum, boardnum);
1388         }
1389
1390         if (eabuf[0]) {
1391                 varbuf_append(&b, vstr_macaddr, eabuf);
1392         }
1393
1394         /* if there is no antenna gain field, set default */
1395         if (getvar(NULL, "ag0") == NULL && ag_init == FALSE) {
1396                 varbuf_append(&b, vstr_ag, 0, 0xff);
1397         }
1398
1399         /* final nullbyte terminator */
1400         ASSERT(b.size >= 1);
1401         *b.buf++ = '\0';
1402
1403         ASSERT(b.buf - base <= MAXSZ_NVRAM_VARS);
1404         err = initvars_table(osh, base, b.buf, vars, count);
1405
1406         MFREE(osh, base, MAXSZ_NVRAM_VARS);
1407         return err;
1408 }
1409
1410 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
1411  * not in the bus cores.
1412  */
1413 static uint16
1414 srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, uint32 cmd, uint wordoff,
1415             uint16 data)
1416 {
1417         chipcregs_t *cc = (chipcregs_t *) ccregs;
1418         uint wait_cnt = 1000;
1419
1420         if ((cmd == SRC_OP_READ) || (cmd == SRC_OP_WRITE)) {
1421                 W_REG(osh, &cc->sromaddress, wordoff * 2);
1422                 if (cmd == SRC_OP_WRITE)
1423                         W_REG(osh, &cc->sromdata, data);
1424         }
1425
1426         W_REG(osh, &cc->sromcontrol, SRC_START | cmd);
1427
1428         while (wait_cnt--) {
1429                 if ((R_REG(osh, &cc->sromcontrol) & SRC_BUSY) == 0)
1430                         break;
1431         }
1432
1433         if (!wait_cnt) {
1434                 BS_ERROR(("%s: Command 0x%x timed out\n", __func__, cmd));
1435                 return 0xffff;
1436         }
1437         if (cmd == SRC_OP_READ)
1438                 return (uint16) R_REG(osh, &cc->sromdata);
1439         else
1440                 return 0xffff;
1441 }
1442
1443 /*
1444  * Read in and validate sprom.
1445  * Return 0 on success, nonzero on error.
1446  */
1447 static int
1448 sprom_read_pci(osl_t *osh, si_t *sih, uint16 *sprom, uint wordoff,
1449                uint16 *buf, uint nwords, bool check_crc)
1450 {
1451         int err = 0;
1452         uint i;
1453         void *ccregs = NULL;
1454
1455         /* read the sprom */
1456         for (i = 0; i < nwords; i++) {
1457
1458                 if (sih->ccrev > 31 && ISSIM_ENAB(sih)) {
1459                         /* use indirect since direct is too slow on QT */
1460                         if ((sih->cccaps & CC_CAP_SROM) == 0)
1461                                 return 1;
1462
1463                         ccregs = (void *)((uint8 *) sprom - CC_SROM_OTP);
1464                         buf[i] =
1465                             srom_cc_cmd(sih, osh, ccregs, SRC_OP_READ,
1466                                         wordoff + i, 0);
1467
1468                 } else {
1469                         if (ISSIM_ENAB(sih))
1470                                 buf[i] = R_REG(osh, &sprom[wordoff + i]);
1471
1472                         buf[i] = R_REG(osh, &sprom[wordoff + i]);
1473                 }
1474
1475         }
1476
1477         /* bypass crc checking for simulation to allow srom hack */
1478         if (ISSIM_ENAB(sih))
1479                 return err;
1480
1481         if (check_crc) {
1482
1483                 if (buf[0] == 0xffff) {
1484                         /* The hardware thinks that an srom that starts with 0xffff
1485                          * is blank, regardless of the rest of the content, so declare
1486                          * it bad.
1487                          */
1488                         BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n",
1489                                   __func__, buf[0]));
1490                         return 1;
1491                 }
1492
1493                 /* fixup the endianness so crc8 will pass */
1494                 htol16_buf(buf, nwords * 2);
1495                 if (hndcrc8((uint8 *) buf, nwords * 2, CRC8_INIT_VALUE) !=
1496                     CRC8_GOOD_VALUE) {
1497                         /* DBG only pci always read srom4 first, then srom8/9 */
1498                         /* BS_ERROR(("%s: bad crc\n", __func__)); */
1499                         err = 1;
1500                 }
1501                 /* now correct the endianness of the byte array */
1502                 ltoh16_buf(buf, nwords * 2);
1503         }
1504         return err;
1505 }
1506
1507 #if defined(BCMNVRAMR)
1508 static int otp_read_pci(osl_t *osh, si_t *sih, uint16 *buf, uint bufsz)
1509 {
1510         uint8 *otp;
1511         uint sz = OTP_SZ_MAX / 2;       /* size in words */
1512         int err = 0;
1513
1514         ASSERT(bufsz <= OTP_SZ_MAX);
1515
1516         if ((otp = MALLOC(osh, OTP_SZ_MAX)) == NULL) {
1517                 return BCME_ERROR;
1518         }
1519
1520         bzero(otp, OTP_SZ_MAX);
1521
1522         err = otp_read_region(sih, OTP_HW_RGN, (uint16 *) otp, &sz);
1523
1524         bcopy(otp, buf, bufsz);
1525
1526         if (otp)
1527                 MFREE(osh, otp, OTP_SZ_MAX);
1528
1529         /* Check CRC */
1530         if (buf[0] == 0xffff) {
1531                 /* The hardware thinks that an srom that starts with 0xffff
1532                  * is blank, regardless of the rest of the content, so declare
1533                  * it bad.
1534                  */
1535                 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __func__,
1536                           buf[0]));
1537                 return 1;
1538         }
1539
1540         /* fixup the endianness so crc8 will pass */
1541         htol16_buf(buf, bufsz);
1542         if (hndcrc8((uint8 *) buf, SROM4_WORDS * 2, CRC8_INIT_VALUE) !=
1543             CRC8_GOOD_VALUE) {
1544                 BS_ERROR(("%s: bad crc\n", __func__));
1545                 err = 1;
1546         }
1547         /* now correct the endianness of the byte array */
1548         ltoh16_buf(buf, bufsz);
1549
1550         return err;
1551 }
1552 #endif                          /* defined(BCMNVRAMR) */
1553 /*
1554 * Create variable table from memory.
1555 * Return 0 on success, nonzero on error.
1556 */
1557 static int
1558 BCMATTACHFN(initvars_table) (osl_t *osh, char *start, char *end, char **vars,
1559                              uint *count) {
1560         int c = (int)(end - start);
1561
1562         /* do it only when there is more than just the null string */
1563         if (c > 1) {
1564                 char *vp = MALLOC(osh, c);
1565                 ASSERT(vp != NULL);
1566                 if (!vp)
1567                         return BCME_NOMEM;
1568                 bcopy(start, vp, c);
1569                 *vars = vp;
1570                 *count = c;
1571         } else {
1572                 *vars = NULL;
1573                 *count = 0;
1574         }
1575
1576         return 0;
1577 }
1578
1579 /*
1580  * Find variables with <devpath> from flash. 'base' points to the beginning
1581  * of the table upon enter and to the end of the table upon exit when success.
1582  * Return 0 on success, nonzero on error.
1583  */
1584 static int
1585 BCMATTACHFN(initvars_flash) (si_t *sih, osl_t *osh, char **base, uint len) {
1586         char *vp = *base;
1587         char *flash;
1588         int err;
1589         char *s;
1590         uint l, dl, copy_len;
1591         char devpath[SI_DEVPATH_BUFSZ];
1592
1593         /* allocate memory and read in flash */
1594         if (!(flash = MALLOC(osh, NVRAM_SPACE)))
1595                 return BCME_NOMEM;
1596         if ((err = nvram_getall(flash, NVRAM_SPACE)))
1597                 goto exit;
1598
1599         si_devpath(sih, devpath, sizeof(devpath));
1600
1601         /* grab vars with the <devpath> prefix in name */
1602         dl = strlen(devpath);
1603         for (s = flash; s && *s; s += l + 1) {
1604                 l = strlen(s);
1605
1606                 /* skip non-matching variable */
1607                 if (strncmp(s, devpath, dl))
1608                         continue;
1609
1610                 /* is there enough room to copy? */
1611                 copy_len = l - dl + 1;
1612                 if (len < copy_len) {
1613                         err = BCME_BUFTOOSHORT;
1614                         goto exit;
1615                 }
1616
1617                 /* no prefix, just the name=value */
1618                 strncpy(vp, &s[dl], copy_len);
1619                 vp += copy_len;
1620                 len -= copy_len;
1621         }
1622
1623         /* add null string as terminator */
1624         if (len < 1) {
1625                 err = BCME_BUFTOOSHORT;
1626                 goto exit;
1627         }
1628         *vp++ = '\0';
1629
1630         *base = vp;
1631
1632  exit:  MFREE(osh, flash, NVRAM_SPACE);
1633         return err;
1634 }
1635
1636 /*
1637  * Initialize nonvolatile variable table from flash.
1638  * Return 0 on success, nonzero on error.
1639  */
1640 static int
1641 BCMATTACHFN(initvars_flash_si) (si_t *sih, char **vars, uint *count) {
1642         osl_t *osh = si_osh(sih);
1643         char *vp, *base;
1644         int err;
1645
1646         ASSERT(vars != NULL);
1647         ASSERT(count != NULL);
1648
1649         base = vp = MALLOC(osh, MAXSZ_NVRAM_VARS);
1650         ASSERT(vp != NULL);
1651         if (!vp)
1652                 return BCME_NOMEM;
1653
1654         if ((err = initvars_flash(sih, osh, &vp, MAXSZ_NVRAM_VARS)) == 0)
1655                 err = initvars_table(osh, base, vp, vars, count);
1656
1657         MFREE(osh, base, MAXSZ_NVRAM_VARS);
1658
1659         return err;
1660 }
1661
1662 /* Parse SROM and create name=value pairs. 'srom' points to
1663  * the SROM word array. 'off' specifies the offset of the
1664  * first word 'srom' points to, which should be either 0 or
1665  * SROM3_SWRG_OFF (full SROM or software region).
1666  */
1667
1668 static uint mask_shift(uint16 mask)
1669 {
1670         uint i;
1671         for (i = 0; i < (sizeof(mask) << 3); i++) {
1672                 if (mask & (1 << i))
1673                         return i;
1674         }
1675         ASSERT(mask);
1676         return 0;
1677 }
1678
1679 static uint mask_width(uint16 mask)
1680 {
1681         int i;
1682         for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
1683                 if (mask & (1 << i))
1684                         return (uint) (i - mask_shift(mask) + 1);
1685         }
1686         ASSERT(mask);
1687         return 0;
1688 }
1689
1690 #if defined(BCMDBG)
1691 static bool mask_valid(uint16 mask)
1692 {
1693         uint shift = mask_shift(mask);
1694         uint width = mask_width(mask);
1695         return mask == ((~0 << shift) & ~(~0 << (shift + width)));
1696 }
1697 #endif                          /* BCMDBG */
1698
1699 static void
1700 BCMATTACHFN(_initvars_srom_pci) (uint8 sromrev, uint16 *srom, uint off,
1701                                  varbuf_t *b) {
1702         uint16 w;
1703         uint32 val;
1704         const sromvar_t *srv;
1705         uint width;
1706         uint flags;
1707         uint32 sr = (1 << sromrev);
1708
1709         varbuf_append(b, "sromrev=%d", sromrev);
1710
1711         for (srv = pci_sromvars; srv->name != NULL; srv++) {
1712                 const char *name;
1713
1714                 if ((srv->revmask & sr) == 0)
1715                         continue;
1716
1717                 if (srv->off < off)
1718                         continue;
1719
1720                 flags = srv->flags;
1721                 name = srv->name;
1722
1723                 /* This entry is for mfgc only. Don't generate param for it, */
1724                 if (flags & SRFL_NOVAR)
1725                         continue;
1726
1727                 if (flags & SRFL_ETHADDR) {
1728                         char eabuf[ETHER_ADDR_STR_LEN];
1729                         struct ether_addr ea;
1730
1731                         ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff;
1732                         ea.octet[1] = srom[srv->off - off] & 0xff;
1733                         ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff;
1734                         ea.octet[3] = srom[srv->off + 1 - off] & 0xff;
1735                         ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff;
1736                         ea.octet[5] = srom[srv->off + 2 - off] & 0xff;
1737                         bcm_ether_ntoa(&ea, eabuf);
1738
1739                         varbuf_append(b, "%s=%s", name, eabuf);
1740                 } else {
1741                         ASSERT(mask_valid(srv->mask));
1742                         ASSERT(mask_width(srv->mask));
1743
1744                         w = srom[srv->off - off];
1745                         val = (w & srv->mask) >> mask_shift(srv->mask);
1746                         width = mask_width(srv->mask);
1747
1748                         while (srv->flags & SRFL_MORE) {
1749                                 srv++;
1750                                 ASSERT(srv->name != NULL);
1751
1752                                 if (srv->off == 0 || srv->off < off)
1753                                         continue;
1754
1755                                 ASSERT(mask_valid(srv->mask));
1756                                 ASSERT(mask_width(srv->mask));
1757
1758                                 w = srom[srv->off - off];
1759                                 val +=
1760                                     ((w & srv->mask) >> mask_shift(srv->
1761                                                                    mask)) <<
1762                                     width;
1763                                 width += mask_width(srv->mask);
1764                         }
1765
1766                         if ((flags & SRFL_NOFFS)
1767                             && ((int)val == (1 << width) - 1))
1768                                 continue;
1769
1770                         if (flags & SRFL_CCODE) {
1771                                 if (val == 0)
1772                                         varbuf_append(b, "ccode=");
1773                                 else
1774                                         varbuf_append(b, "ccode=%c%c",
1775                                                       (val >> 8), (val & 0xff));
1776                         }
1777                         /* LED Powersave duty cycle has to be scaled:
1778                          *(oncount >> 24) (offcount >> 8)
1779                          */
1780                         else if (flags & SRFL_LEDDC) {
1781                                 uint32 w32 = (((val >> 8) & 0xff) << 24) |      /* oncount */
1782                                     (((val & 0xff)) << 8);      /* offcount */
1783                                 varbuf_append(b, "leddc=%d", w32);
1784                         } else if (flags & SRFL_PRHEX)
1785                                 varbuf_append(b, "%s=0x%x", name, val);
1786                         else if ((flags & SRFL_PRSIGN)
1787                                  && (val & (1 << (width - 1))))
1788                                 varbuf_append(b, "%s=%d", name,
1789                                               (int)(val | (~0 << width)));
1790                         else
1791                                 varbuf_append(b, "%s=%u", name, val);
1792                 }
1793         }
1794
1795         if (sromrev >= 4) {
1796                 /* Do per-path variables */
1797                 uint p, pb, psz;
1798
1799                 if (sromrev >= 8) {
1800                         pb = SROM8_PATH0;
1801                         psz = SROM8_PATH1 - SROM8_PATH0;
1802                 } else {
1803                         pb = SROM4_PATH0;
1804                         psz = SROM4_PATH1 - SROM4_PATH0;
1805                 }
1806
1807                 for (p = 0; p < MAX_PATH_SROM; p++) {
1808                         for (srv = perpath_pci_sromvars; srv->name != NULL;
1809                              srv++) {
1810                                 if ((srv->revmask & sr) == 0)
1811                                         continue;
1812
1813                                 if (pb + srv->off < off)
1814                                         continue;
1815
1816                                 /* This entry is for mfgc only. Don't generate param for it, */
1817                                 if (srv->flags & SRFL_NOVAR)
1818                                         continue;
1819
1820                                 w = srom[pb + srv->off - off];
1821
1822                                 ASSERT(mask_valid(srv->mask));
1823                                 val = (w & srv->mask) >> mask_shift(srv->mask);
1824                                 width = mask_width(srv->mask);
1825
1826                                 /* Cheating: no per-path var is more than 1 word */
1827
1828                                 if ((srv->flags & SRFL_NOFFS)
1829                                     && ((int)val == (1 << width) - 1))
1830                                         continue;
1831
1832                                 if (srv->flags & SRFL_PRHEX)
1833                                         varbuf_append(b, "%s%d=0x%x", srv->name,
1834                                                       p, val);
1835                                 else
1836                                         varbuf_append(b, "%s%d=%d", srv->name,
1837                                                       p, val);
1838                         }
1839                         pb += psz;
1840                 }
1841         }
1842 }
1843
1844 /*
1845  * Initialize nonvolatile variable table from sprom.
1846  * Return 0 on success, nonzero on error.
1847  */
1848 static int
1849 BCMATTACHFN(initvars_srom_pci) (si_t *sih, void *curmap, char **vars,
1850                                 uint *count) {
1851         uint16 *srom, *sromwindow;
1852         uint8 sromrev = 0;
1853         uint32 sr;
1854         varbuf_t b;
1855         char *vp, *base = NULL;
1856         osl_t *osh = si_osh(sih);
1857         bool flash = FALSE;
1858         int err = 0;
1859
1860         /*
1861          * Apply CRC over SROM content regardless SROM is present or not,
1862          * and use variable <devpath>sromrev's existance in flash to decide
1863          * if we should return an error when CRC fails or read SROM variables
1864          * from flash.
1865          */
1866         srom = MALLOC(osh, SROM_MAX);
1867         ASSERT(srom != NULL);
1868         if (!srom)
1869                 return -2;
1870
1871         sromwindow = (uint16 *) SROM_OFFSET(sih);
1872         if (si_is_sprom_available(sih)) {
1873                 err =
1874                     sprom_read_pci(osh, sih, sromwindow, 0, srom, SROM_WORDS,
1875                                    TRUE);
1876
1877                 if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
1878                     (((sih->buscoretype == PCIE_CORE_ID)
1879                       && (sih->buscorerev >= 6))
1880                      || ((sih->buscoretype == PCI_CORE_ID)
1881                          && (sih->buscorerev >= 0xe)))) {
1882                         /* sromrev >= 4, read more */
1883                         err =
1884                             sprom_read_pci(osh, sih, sromwindow, 0, srom,
1885                                            SROM4_WORDS, TRUE);
1886                         sromrev = srom[SROM4_CRCREV] & 0xff;
1887                         if (err)
1888                                 BS_ERROR(("%s: srom %d, bad crc\n", __func__,
1889                                           sromrev));
1890
1891                 } else if (err == 0) {
1892                         /* srom is good and is rev < 4 */
1893                         /* top word of sprom contains version and crc8 */
1894                         sromrev = srom[SROM_CRCREV] & 0xff;
1895                         /* bcm4401 sroms misprogrammed */
1896                         if (sromrev == 0x10)
1897                                 sromrev = 1;
1898                 }
1899         }
1900 #if defined(BCMNVRAMR)
1901         /* Use OTP if SPROM not available */
1902         else if ((err = otp_read_pci(osh, sih, srom, SROM_MAX)) == 0) {
1903                 /* OTP only contain SROM rev8/rev9 for now */
1904                 sromrev = srom[SROM4_CRCREV] & 0xff;
1905         }
1906 #endif
1907         else {
1908                 err = 1;
1909                 BS_ERROR(("Neither SPROM nor OTP has valid image\n"));
1910         }
1911
1912         /* We want internal/wltest driver to come up with default sromvars so we can
1913          * program a blank SPROM/OTP.
1914          */
1915         if (err) {
1916                 char *value;
1917                 uint32 val;
1918                 val = 0;
1919
1920                 if ((value = si_getdevpathvar(sih, "sromrev"))) {
1921                         sromrev = (uint8) bcm_strtoul(value, NULL, 0);
1922                         flash = TRUE;
1923                         goto varscont;
1924                 }
1925
1926                 BS_ERROR(("%s, SROM CRC Error\n", __func__));
1927
1928                 if ((value = si_getnvramflvar(sih, "sromrev"))) {
1929                         err = 0;
1930                         goto errout;
1931                 }
1932
1933                 {
1934                         err = -1;
1935                         goto errout;
1936                 }
1937         }
1938
1939  varscont:
1940         /* Bitmask for the sromrev */
1941         sr = 1 << sromrev;
1942
1943         /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
1944         if ((sr & 0x33e) == 0) {
1945                 err = -2;
1946                 goto errout;
1947         }
1948
1949         ASSERT(vars != NULL);
1950         ASSERT(count != NULL);
1951
1952         base = vp = MALLOC(osh, MAXSZ_NVRAM_VARS);
1953         ASSERT(vp != NULL);
1954         if (!vp) {
1955                 err = -2;
1956                 goto errout;
1957         }
1958
1959         /* read variables from flash */
1960         if (flash) {
1961                 if ((err = initvars_flash(sih, osh, &vp, MAXSZ_NVRAM_VARS)))
1962                         goto errout;
1963                 goto varsdone;
1964         }
1965
1966         varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
1967
1968         /* parse SROM into name=value pairs. */
1969         _initvars_srom_pci(sromrev, srom, 0, &b);
1970
1971         /* final nullbyte terminator */
1972         ASSERT(b.size >= 1);
1973         vp = b.buf;
1974         *vp++ = '\0';
1975
1976         ASSERT((vp - base) <= MAXSZ_NVRAM_VARS);
1977
1978  varsdone:
1979         err = initvars_table(osh, base, vp, vars, count);
1980
1981  errout:
1982         if (base)
1983                 MFREE(osh, base, MAXSZ_NVRAM_VARS);
1984
1985         MFREE(osh, srom, SROM_MAX);
1986         return err;
1987 }
1988
1989 #ifdef BCMSDIO
1990 /*
1991  * Read the SDIO cis and call parsecis to initialize the vars.
1992  * Return 0 on success, nonzero on error.
1993  */
1994 static int
1995 BCMATTACHFN(initvars_cis_sdio) (osl_t *osh, char **vars, uint *count) {
1996         uint8 *cis[SBSDIO_NUM_FUNCTION + 1];
1997         uint fn, numfn;
1998         int rc = 0;
1999
2000         numfn = bcmsdh_query_iofnum(NULL);
2001         ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
2002
2003         for (fn = 0; fn <= numfn; fn++) {
2004                 if ((cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT)) == NULL) {
2005                         rc = -1;
2006                         break;
2007                 }
2008
2009                 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
2010
2011                 if (bcmsdh_cis_read(NULL, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT) !=
2012                     0) {
2013                         MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
2014                         rc = -2;
2015                         break;
2016                 }
2017         }
2018
2019         if (!rc)
2020                 rc = srom_parsecis(osh, cis, fn, vars, count);
2021
2022         while (fn-- > 0)
2023                 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
2024
2025         return (rc);
2026 }
2027
2028 /* set SDIO sprom command register */
2029 static int BCMATTACHFN(sprom_cmd_sdio) (osl_t *osh, uint8 cmd) {
2030         uint8 status = 0;
2031         uint wait_cnt = 1000;
2032
2033         /* write sprom command register */
2034         bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_CS, cmd, NULL);
2035
2036         /* wait status */
2037         while (wait_cnt--) {
2038                 status =
2039                     bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_CS, NULL);
2040                 if (status & SBSDIO_SPROM_DONE)
2041                         return 0;
2042         }
2043
2044         return 1;
2045 }
2046
2047 /* read a word from the SDIO srom */
2048 static int sprom_read_sdio(osl_t *osh, uint16 addr, uint16 *data)
2049 {
2050         uint8 addr_l, addr_h, data_l, data_h;
2051
2052         addr_l = (uint8) ((addr * 2) & 0xff);
2053         addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
2054
2055         /* set address */
2056         bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_HIGH, addr_h,
2057                          NULL);
2058         bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_LOW, addr_l,
2059                          NULL);
2060
2061         /* do read */
2062         if (sprom_cmd_sdio(osh, SBSDIO_SPROM_READ))
2063                 return 1;
2064
2065         /* read data */
2066         data_h =
2067             bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_HIGH, NULL);
2068         data_l =
2069             bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_LOW, NULL);
2070
2071         *data = (data_h << 8) | data_l;
2072         return 0;
2073 }
2074 #endif                          /* BCMSDIO */
2075
2076 static int
2077 BCMATTACHFN(initvars_srom_si) (si_t *sih, osl_t *osh, void *curmap,
2078                                char **vars, uint *varsz) {
2079         /* Search flash nvram section for srom variables */
2080         return initvars_flash_si(sih, vars, varsz);
2081 }