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