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