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