2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <linux/kernel.h>
21 #include <linux/string.h>
28 #include <bcmendian.h>
32 #include <bcmsrom_tbl.h>
44 #include <sbsdpcmdev.h>
47 #include <proto/ethernet.h> /* for sprom content groking */
49 #define BS_ERROR(args)
51 #define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
52 (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
53 ((u8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
54 ((u8 *)curmap + PCI_BAR0_SPROM_OFFSET))
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 */
61 typedef 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 */
69 #define SROM_CIS_SINGLE 1
71 static int initvars_srom_si(si_t
*sih
, osl_t
*osh
, void *curmap
, char **vars
,
73 static void _initvars_srom_pci(u8 sromrev
, u16
*srom
, uint off
,
75 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
,
77 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
);
79 static int initvars_cis_sdio(osl_t
*osh
, char **vars
, uint
*count
);
80 static int sprom_cmd_sdio(osl_t
*osh
, u8 cmd
);
81 static int sprom_read_sdio(osl_t
*osh
, u16 addr
, u16
*data
);
83 static int sprom_read_pci(osl_t
*osh
, si_t
*sih
, u16
*sprom
, uint wordoff
,
84 u16
*buf
, uint nwords
, bool check_crc
);
85 #if defined(BCMNVRAMR)
86 static int otp_read_pci(osl_t
*osh
, si_t
*sih
, u16
*buf
, uint bufsz
);
88 static u16
srom_cc_cmd(si_t
*sih
, osl_t
*osh
, void *ccregs
, u32 cmd
,
89 uint wordoff
, u16 data
);
91 static int initvars_table(osl_t
*osh
, char *start
, char *end
, char **vars
,
93 static int initvars_flash(si_t
*sih
, osl_t
*osh
, char **vp
, uint len
);
95 /* Initialization of varbuf structure */
96 static void varbuf_init(varbuf_t
*b
, char *buf
, uint size
)
99 b
->base
= b
->buf
= buf
;
102 /* append a null terminated var=value string */
103 static int varbuf_append(varbuf_t
*b
, const char *fmt
, ...)
114 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
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.
124 if ((r
== -1) || (r
> (int)(b
->size
- 2))) {
129 /* Remove any earlier occurrence of the same variable */
130 s
= strchr(b
->buf
, '=');
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
] == '=') {
136 memmove(s
, (s
+ len
),
137 ((b
->buf
+ r
+ 1) - (s
+ len
)));
139 b
->size
+= (unsigned int)len
;
148 /* skip over this string's null termination */
157 * Initialize local vars from the right source for this platform.
158 * Return 0 on success, nonzero on error.
160 int srom_var_init(si_t
*sih
, uint bustype
, void *curmap
, osl_t
*osh
,
161 char **vars
, uint
*count
)
167 ASSERT(bustype
== BUSTYPE(bustype
));
168 if (vars
== NULL
|| count
== NULL
)
174 switch (BUSTYPE(bustype
)) {
177 return initvars_srom_si(sih
, osh
, curmap
, vars
, count
);
180 ASSERT(curmap
!= NULL
);
184 return initvars_srom_pci(sih
, curmap
, vars
, count
);
188 return initvars_cis_sdio(osh
, vars
, count
);
197 /* support only 16-bit word read from srom */
199 srom_read(si_t
*sih
, uint bustype
, void *curmap
, osl_t
*osh
,
200 uint byteoff
, uint nbytes
, u16
*buf
, bool check_crc
)
207 ASSERT(bustype
== BUSTYPE(bustype
));
209 /* check input - 16-bit access only */
210 if (byteoff
& 1 || nbytes
& 1 || (byteoff
+ nbytes
) > SROM_MAX
)
216 if (BUSTYPE(bustype
) == PCI_BUS
) {
220 if (si_is_sprom_available(sih
)) {
223 srom
= (u16
*) SROM_OFFSET(sih
);
228 (osh
, sih
, srom
, off
, buf
, nw
, check_crc
))
231 #if defined(BCMNVRAMR)
233 if (otp_read_pci(osh
, sih
, buf
, SROM_MAX
))
238 } else if (BUSTYPE(bustype
) == SDIO_BUS
) {
241 for (i
= 0; i
< nw
; i
++) {
243 (osh
, (u16
) (off
+ i
), (u16
*) (buf
+ i
)))
247 } else if (BUSTYPE(bustype
) == SI_BUS
) {
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";
261 static const char vstr_sdmaxspeed
[] = "sdmaxspeed=%d";
262 static const char vstr_sdmaxblk
[][13] = {
263 "sdmaxblk0=%d", "sdmaxblk1=%d", "sdmaxblk2=%d"};
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"};
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"};
284 static const char vstr_pa1lob
[][11] = {
285 "pa1lob0=%d", "pa1lob1=%d", "pa1lob2=%d"};
287 static const char vstr_pa1hib
[][11] = {
288 "pa1hib0=%d", "pa1hib1=%d", "pa1hib2=%d"};
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";
378 /* For dongle HW, accept partial calibration parameters */
379 #define BCMDONGLECASE(n)
381 int srom_parsecis(osl_t
*osh
, u8
*pcis
[], uint ciscnt
, char **vars
, uint
*count
)
386 u8
*cis
, tup
, tlen
, sromrev
= 1;
388 bool ag_init
= false;
396 ASSERT(vars
!= NULL
);
397 ASSERT(count
!= NULL
);
401 base
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
402 ASSERT(base
!= NULL
);
406 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
407 bzero(base
, MAXSZ_NVRAM_VARS
);
409 for (cisnum
= 0; cisnum
< ciscnt
; cisnum
++) {
417 if (tup
== CISTPL_NULL
|| tup
== CISTPL_END
)
422 if (cis
[i
] == CISTPL_NULL
423 || cis
[i
] == CISTPL_END
) {
428 tup
= CISTPL_BRCM_HNBU
;
432 if ((i
+ tlen
) >= CIS_SIZE
)
437 /* assume the strings are good if the version field checks out */
438 if (((cis
[i
+ 1] << 8) + cis
[i
]) >= 0x0008) {
439 varbuf_append(&b
, vstr_manf
,
441 varbuf_append(&b
, vstr_productname
,
450 varbuf_append(&b
, vstr_manfid
,
451 (cis
[i
+ 1] << 8) + cis
[i
]);
452 varbuf_append(&b
, vstr_prodid
,
453 (cis
[i
+ 3] << 8) + cis
[i
+ 2]);
462 case CISTPL_FID_SDIO
:
466 static int base
[] = {
467 -1, 10, 12, 13, 15, 20,
469 35, 40, 45, 50, 55, 60,
472 static int mult
[] = {
473 10, 100, 1000, 10000,
476 ASSERT((mult
[spd
& 0x7] != -1)
479 [(spd
>> 3) & 0x0f]));
489 } else if (cis
[i
] == 1) {
500 /* set macaddr if HNBU_MACADDR not seen yet */
503 && !(ETHER_ISNULLADDR(&cis
[i
+ 2]))
504 && !(ETHER_ISMULTI(&cis
[i
+ 2]))) {
507 snprintf(eabuf
, sizeof(eabuf
),
510 /* set boardnum if HNBU_BOARDNUM not seen yet */
521 varbuf_append(&b
, vstr_regwindowsz
,
522 (cis
[i
+ 7] << 8) | cis
[i
+ 6]);
525 case CISTPL_BRCM_HNBU
:
528 sromrev
= cis
[i
+ 1];
529 varbuf_append(&b
, vstr_sromrev
,
534 varbuf_append(&b
, vstr_xtalfreq
,
542 varbuf_append(&b
, vstr_vendid
,
545 varbuf_append(&b
, vstr_devid
,
549 varbuf_append(&b
, vstr_chiprev
,
560 varbuf_append(&b
, vstr_subdevid
,
563 /* subdevid doubles for boardtype */
573 (cis
[i
+ 2] << 8) + cis
[i
+ 1];
581 /* retrieve the patch pairs
582 * from tlen/6; where 6 is
583 * sizeof(patch addr(2)) +
584 * sizeof(patch data(4)).
586 patch_pair
= tlen
/ 6;
588 for (j
= 0; j
< patch_pair
; j
++) {
643 varbuf_append(&b
, vstr_boardrev
,
646 varbuf_append(&b
, vstr_boardrev
,
651 case HNBU_BOARDFLAGS
:
652 w32
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
655 ((cis
[i
+ 4] << 24) +
657 varbuf_append(&b
, vstr_boardflags
, w32
);
661 (cis
[i
+ 6] << 8) + cis
[i
+
676 varbuf_append(&b
, vstr_usbfs
,
681 varbuf_append(&b
, vstr_boardtype
,
688 * what follows is a nonstandard HNBU CIS
689 * that lacks CISTPL_BRCM_HNBU tags
691 * skip 0xff (end of standard CIS)
695 standard_cis
= false;
699 varbuf_append(&b
, vstr_usbepnum
,
700 (cis
[i
+ 2] << 8) | cis
[i
706 varbuf_append(&b
, vstr_aa2g
,
709 varbuf_append(&b
, vstr_aa5g
,
714 varbuf_append(&b
, vstr_ag
, 0,
717 varbuf_append(&b
, vstr_ag
, 1,
720 varbuf_append(&b
, vstr_ag
, 2,
723 varbuf_append(&b
, vstr_ag
, 3,
729 varbuf_append(&b
, vstr_aa5g
,
731 varbuf_append(&b
, vstr_ag
, 1,
736 ASSERT(sromrev
== 1);
737 varbuf_append(&b
, vstr_cc
, cis
[i
+ 1]);
743 ASSERT(sromrev
== 1);
749 ASSERT(sromrev
>= 2);
750 varbuf_append(&b
, vstr_opo
,
764 for (j
= 0; j
< 3; j
++) {
789 ASSERT((sromrev
== 2)
809 for (j
= 0; j
< 3; j
++) {
824 for (j
= 3; j
< 6; j
++) {
839 for (j
= 6; j
< 9; j
++) {
856 ASSERT((tlen
== 19) ||
864 ASSERT(sromrev
== 1);
865 varbuf_append(&b
, vstr_oem
,
866 cis
[i
+ 1], cis
[i
+ 2],
867 cis
[i
+ 3], cis
[i
+ 4],
868 cis
[i
+ 5], cis
[i
+ 6],
869 cis
[i
+ 7], cis
[i
+ 8]);
873 for (j
= 1; j
<= 4; j
++) {
874 if (cis
[i
+ j
] != 0xff) {
886 if ((cis
[i
+ 1] == 0)
887 || (cis
[i
+ 2] == 0))
888 varbuf_append(&b
, vstr_noccode
);
890 varbuf_append(&b
, vstr_ccode
,
893 varbuf_append(&b
, vstr_cctl
,
899 varbuf_append(&b
, vstr_cckpo
,
900 (cis
[i
+ 2] << 8) | cis
[i
907 varbuf_append(&b
, vstr_ofdmpo
,
915 varbuf_append(&b
, vstr_wpsgpio
,
918 varbuf_append(&b
, vstr_wpsled
,
922 case HNBU_RSSISMBXA2G
:
923 ASSERT(sromrev
== 3);
924 varbuf_append(&b
, vstr_rssismf2g
,
926 varbuf_append(&b
, vstr_rssismc2g
,
927 (cis
[i
+ 1] >> 4) & 0xf);
928 varbuf_append(&b
, vstr_rssisav2g
,
930 varbuf_append(&b
, vstr_bxa2g
,
931 (cis
[i
+ 2] >> 3) & 0x3);
934 case HNBU_RSSISMBXA5G
:
935 ASSERT(sromrev
== 3);
936 varbuf_append(&b
, vstr_rssismf5g
,
938 varbuf_append(&b
, vstr_rssismc5g
,
939 (cis
[i
+ 1] >> 4) & 0xf);
940 varbuf_append(&b
, vstr_rssisav5g
,
942 varbuf_append(&b
, vstr_bxa5g
,
943 (cis
[i
+ 2] >> 3) & 0x3);
947 ASSERT(sromrev
== 3);
948 varbuf_append(&b
, vstr_tri2g
,
953 ASSERT(sromrev
== 3);
954 varbuf_append(&b
, vstr_tri5gl
,
956 varbuf_append(&b
, vstr_tri5g
,
958 varbuf_append(&b
, vstr_tri5gh
,
963 ASSERT(sromrev
== 3);
964 varbuf_append(&b
, vstr_rxpo2g
,
969 ASSERT(sromrev
== 3);
970 varbuf_append(&b
, vstr_rxpo5g
,
975 if (!(ETHER_ISNULLADDR(&cis
[i
+ 1])) &&
976 !(ETHER_ISMULTI(&cis
[i
+ 1]))) {
977 snprintf(eabuf
, sizeof(eabuf
),
980 /* set boardnum if HNBU_BOARDNUM not seen yet */
989 /* CIS leddc only has 16bits, convert it to 32bits */
990 w32
= ((cis
[i
+ 2] << 24) | /* oncount */
991 (cis
[i
+ 1] << 8)); /* offcount */
992 varbuf_append(&b
, vstr_leddc
, w32
);
995 case HNBU_CHAINSWITCH
:
996 varbuf_append(&b
, vstr_txchain
,
998 varbuf_append(&b
, vstr_rxchain
,
1000 varbuf_append(&b
, vstr_antswitch
,
1006 varbuf_append(&b
, vstr_regrev
,
1012 (cis
[i
+ 2] << 8) + cis
[i
+
1017 SROM8_FEM_ANTSWLUT_MASK
)
1019 SROM8_FEM_ANTSWLUT_SHIFT
);
1020 varbuf_append(&b
, vstr_triso2g
,
1022 SROM8_FEM_TR_ISO_MASK
)
1024 SROM8_FEM_TR_ISO_SHIFT
);
1028 SROM8_FEM_PDET_RANGE_MASK
)
1030 SROM8_FEM_PDET_RANGE_SHIFT
);
1034 SROM8_FEM_EXTPA_GAIN_MASK
)
1036 SROM8_FEM_EXTPA_GAIN_SHIFT
);
1040 SROM8_FEM_TSSIPOS_MASK
)
1042 SROM8_FEM_TSSIPOS_SHIFT
);
1047 (cis
[i
+ 4] << 8) + cis
[i
+
1052 SROM8_FEM_ANTSWLUT_MASK
)
1054 SROM8_FEM_ANTSWLUT_SHIFT
);
1055 varbuf_append(&b
, vstr_triso5g
,
1057 SROM8_FEM_TR_ISO_MASK
)
1059 SROM8_FEM_TR_ISO_SHIFT
);
1063 SROM8_FEM_PDET_RANGE_MASK
)
1065 SROM8_FEM_PDET_RANGE_SHIFT
);
1069 SROM8_FEM_EXTPA_GAIN_MASK
)
1071 SROM8_FEM_EXTPA_GAIN_SHIFT
);
1075 SROM8_FEM_TSSIPOS_MASK
)
1077 SROM8_FEM_TSSIPOS_SHIFT
);
1081 case HNBU_PAPARMS_C0
:
1082 varbuf_append(&b
, vstr_maxp2ga0
,
1084 varbuf_append(&b
, vstr_itt2ga0
,
1086 varbuf_append(&b
, vstr_pa
, 2, 0, 0,
1089 varbuf_append(&b
, vstr_pa
, 2, 1, 0,
1092 varbuf_append(&b
, vstr_pa
, 2, 2, 0,
1098 varbuf_append(&b
, vstr_maxp5ga0
,
1100 varbuf_append(&b
, vstr_itt5ga0
,
1102 varbuf_append(&b
, vstr_maxp5gha0
,
1104 varbuf_append(&b
, vstr_maxp5gla0
,
1106 varbuf_append(&b
, vstr_pa
, 5, 0, 0,
1107 (cis
[i
+ 14] << 8) +
1109 varbuf_append(&b
, vstr_pa
, 5, 1, 0,
1110 (cis
[i
+ 16] << 8) +
1112 varbuf_append(&b
, vstr_pa
, 5, 2, 0,
1113 (cis
[i
+ 18] << 8) +
1115 varbuf_append(&b
, vstr_pahl
, 5, 'l', 0,
1117 (cis
[i
+ 20] << 8) +
1119 varbuf_append(&b
, vstr_pahl
, 5, 'l', 1,
1121 (cis
[i
+ 22] << 8) +
1123 varbuf_append(&b
, vstr_pahl
, 5, 'l', 2,
1125 (cis
[i
+ 24] << 8) +
1127 varbuf_append(&b
, vstr_pahl
, 5, 'h', 0,
1129 (cis
[i
+ 26] << 8) +
1131 varbuf_append(&b
, vstr_pahl
, 5, 'h', 1,
1133 (cis
[i
+ 28] << 8) +
1135 varbuf_append(&b
, vstr_pahl
, 5, 'h', 2,
1137 (cis
[i
+ 30] << 8) +
1141 case HNBU_PAPARMS_C1
:
1142 varbuf_append(&b
, vstr_maxp2ga1
,
1144 varbuf_append(&b
, vstr_itt2ga1
,
1146 varbuf_append(&b
, vstr_pa
, 2, 0, 1,
1149 varbuf_append(&b
, vstr_pa
, 2, 1, 1,
1152 varbuf_append(&b
, vstr_pa
, 2, 2, 1,
1158 varbuf_append(&b
, vstr_maxp5ga1
,
1160 varbuf_append(&b
, vstr_itt5ga1
,
1162 varbuf_append(&b
, vstr_maxp5gha1
,
1164 varbuf_append(&b
, vstr_maxp5gla1
,
1166 varbuf_append(&b
, vstr_pa
, 5, 0, 1,
1167 (cis
[i
+ 14] << 8) +
1169 varbuf_append(&b
, vstr_pa
, 5, 1, 1,
1170 (cis
[i
+ 16] << 8) +
1172 varbuf_append(&b
, vstr_pa
, 5, 2, 1,
1173 (cis
[i
+ 18] << 8) +
1175 varbuf_append(&b
, vstr_pahl
, 5, 'l', 0,
1177 (cis
[i
+ 20] << 8) +
1179 varbuf_append(&b
, vstr_pahl
, 5, 'l', 1,
1181 (cis
[i
+ 22] << 8) +
1183 varbuf_append(&b
, vstr_pahl
, 5, 'l', 2,
1185 (cis
[i
+ 24] << 8) +
1187 varbuf_append(&b
, vstr_pahl
, 5, 'h', 0,
1189 (cis
[i
+ 26] << 8) +
1191 varbuf_append(&b
, vstr_pahl
, 5, 'h', 1,
1193 (cis
[i
+ 28] << 8) +
1195 varbuf_append(&b
, vstr_pahl
, 5, 'h', 2,
1197 (cis
[i
+ 30] << 8) +
1201 case HNBU_PO_CCKOFDM
:
1202 varbuf_append(&b
, vstr_cck2gpo
,
1205 varbuf_append(&b
, vstr_ofdm2gpo
,
1206 (cis
[i
+ 6] << 24) +
1207 (cis
[i
+ 5] << 16) +
1213 varbuf_append(&b
, vstr_ofdm5gpo
,
1214 (cis
[i
+ 10] << 24) +
1215 (cis
[i
+ 9] << 16) +
1218 varbuf_append(&b
, vstr_ofdm5glpo
,
1219 (cis
[i
+ 14] << 24) +
1220 (cis
[i
+ 13] << 16) +
1221 (cis
[i
+ 12] << 8) +
1223 varbuf_append(&b
, vstr_ofdm5ghpo
,
1224 (cis
[i
+ 18] << 24) +
1225 (cis
[i
+ 17] << 16) +
1226 (cis
[i
+ 16] << 8) +
1231 for (j
= 0; j
<= (tlen
/ 2); j
++) {
1232 varbuf_append(&b
, vstr_mcspo
, 2,
1242 case HNBU_PO_MCS5GM
:
1243 for (j
= 0; j
<= (tlen
/ 2); j
++) {
1244 varbuf_append(&b
, vstr_mcspo
, 5,
1254 case HNBU_PO_MCS5GLH
:
1255 for (j
= 0; j
<= (tlen
/ 4); j
++) {
1256 varbuf_append(&b
, vstr_mcspohl
,
1265 for (j
= 0; j
<= (tlen
/ 4); j
++) {
1266 varbuf_append(&b
, vstr_mcspohl
,
1281 varbuf_append(&b
, vstr_cddpo
,
1287 varbuf_append(&b
, vstr_stbcpo
,
1293 varbuf_append(&b
, vstr_bw40po
,
1298 case HNBU_PO_40MDUP
:
1299 varbuf_append(&b
, vstr_bwduppo
,
1305 varbuf_append(&b
, vstr_ofdm5gpo
,
1306 (cis
[i
+ 4] << 24) +
1307 (cis
[i
+ 3] << 16) +
1310 varbuf_append(&b
, vstr_ofdm5glpo
,
1311 (cis
[i
+ 8] << 24) +
1312 (cis
[i
+ 7] << 16) +
1315 varbuf_append(&b
, vstr_ofdm5ghpo
,
1316 (cis
[i
+ 12] << 24) +
1317 (cis
[i
+ 11] << 16) +
1318 (cis
[i
+ 10] << 8) +
1323 varbuf_append(&b
, vstr_custom
, 1,
1324 ((cis
[i
+ 4] << 24) +
1325 (cis
[i
+ 3] << 16) +
1330 #if defined(BCMSDIO)
1331 case HNBU_SROM3SWRGN
:
1334 u8 srev
= cis
[i
+ 1 + 70];
1336 /* make tuple value 16-bit aligned and parse it */
1337 bcopy(&cis
[i
+ 1], srom
,
1339 _initvars_srom_pci(srev
, srom
,
1342 /* 2.4G antenna gain is included in SROM */
1344 /* Ethernet MAC address is included in SROM */
1348 /* create extra variables */
1350 varbuf_append(&b
, vstr_vendid
,
1356 varbuf_append(&b
, vstr_devid
,
1362 varbuf_append(&b
, vstr_xtalfreq
,
1368 #endif /* defined(BCMSDIO) */
1370 case HNBU_CCKFILTTYPE
:
1371 varbuf_append(&b
, vstr_cckdigfilttype
,
1379 } while (tup
!= CISTPL_END
);
1382 if (boardnum
!= -1) {
1383 varbuf_append(&b
, vstr_boardnum
, boardnum
);
1387 varbuf_append(&b
, vstr_macaddr
, eabuf
);
1390 /* if there is no antenna gain field, set default */
1391 if (getvar(NULL
, "ag0") == NULL
&& ag_init
== false) {
1392 varbuf_append(&b
, vstr_ag
, 0, 0xff);
1395 /* final nullbyte terminator */
1396 ASSERT(b
.size
>= 1);
1399 ASSERT(b
.buf
- base
<= MAXSZ_NVRAM_VARS
);
1400 err
= initvars_table(osh
, base
, b
.buf
, vars
, count
);
1406 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
1407 * not in the bus cores.
1410 srom_cc_cmd(si_t
*sih
, osl_t
*osh
, void *ccregs
, u32 cmd
, uint wordoff
,
1413 chipcregs_t
*cc
= (chipcregs_t
*) ccregs
;
1414 uint wait_cnt
= 1000;
1416 if ((cmd
== SRC_OP_READ
) || (cmd
== SRC_OP_WRITE
)) {
1417 W_REG(osh
, &cc
->sromaddress
, wordoff
* 2);
1418 if (cmd
== SRC_OP_WRITE
)
1419 W_REG(osh
, &cc
->sromdata
, data
);
1422 W_REG(osh
, &cc
->sromcontrol
, SRC_START
| cmd
);
1424 while (wait_cnt
--) {
1425 if ((R_REG(osh
, &cc
->sromcontrol
) & SRC_BUSY
) == 0)
1430 BS_ERROR(("%s: Command 0x%x timed out\n", __func__
, cmd
));
1433 if (cmd
== SRC_OP_READ
)
1434 return (u16
) R_REG(osh
, &cc
->sromdata
);
1440 * Read in and validate sprom.
1441 * Return 0 on success, nonzero on error.
1444 sprom_read_pci(osl_t
*osh
, si_t
*sih
, u16
*sprom
, uint wordoff
,
1445 u16
*buf
, uint nwords
, bool check_crc
)
1449 void *ccregs
= NULL
;
1451 /* read the sprom */
1452 for (i
= 0; i
< nwords
; i
++) {
1454 if (sih
->ccrev
> 31 && ISSIM_ENAB(sih
)) {
1455 /* use indirect since direct is too slow on QT */
1456 if ((sih
->cccaps
& CC_CAP_SROM
) == 0)
1459 ccregs
= (void *)((u8
*) sprom
- CC_SROM_OTP
);
1461 srom_cc_cmd(sih
, osh
, ccregs
, SRC_OP_READ
,
1465 if (ISSIM_ENAB(sih
))
1466 buf
[i
] = R_REG(osh
, &sprom
[wordoff
+ i
]);
1468 buf
[i
] = R_REG(osh
, &sprom
[wordoff
+ i
]);
1473 /* bypass crc checking for simulation to allow srom hack */
1474 if (ISSIM_ENAB(sih
))
1479 if (buf
[0] == 0xffff) {
1480 /* The hardware thinks that an srom that starts with 0xffff
1481 * is blank, regardless of the rest of the content, so declare
1484 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n",
1489 /* fixup the endianness so crc8 will pass */
1490 htol16_buf(buf
, nwords
* 2);
1491 if (hndcrc8((u8
*) buf
, nwords
* 2, CRC8_INIT_VALUE
) !=
1493 /* DBG only pci always read srom4 first, then srom8/9 */
1494 /* BS_ERROR(("%s: bad crc\n", __func__)); */
1497 /* now correct the endianness of the byte array */
1498 ltoh16_buf(buf
, nwords
* 2);
1503 #if defined(BCMNVRAMR)
1504 static int otp_read_pci(osl_t
*osh
, si_t
*sih
, u16
*buf
, uint bufsz
)
1507 uint sz
= OTP_SZ_MAX
/ 2; /* size in words */
1510 ASSERT(bufsz
<= OTP_SZ_MAX
);
1512 otp
= kzalloc(OTP_SZ_MAX
, GFP_ATOMIC
);
1517 err
= otp_read_region(sih
, OTP_HW_RGN
, (u16
*) otp
, &sz
);
1519 bcopy(otp
, buf
, bufsz
);
1525 if (buf
[0] == 0xffff) {
1526 /* The hardware thinks that an srom that starts with 0xffff
1527 * is blank, regardless of the rest of the content, so declare
1530 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __func__
,
1535 /* fixup the endianness so crc8 will pass */
1536 htol16_buf(buf
, bufsz
);
1537 if (hndcrc8((u8
*) buf
, SROM4_WORDS
* 2, CRC8_INIT_VALUE
) !=
1539 BS_ERROR(("%s: bad crc\n", __func__
));
1542 /* now correct the endianness of the byte array */
1543 ltoh16_buf(buf
, bufsz
);
1547 #endif /* defined(BCMNVRAMR) */
1549 * Create variable table from memory.
1550 * Return 0 on success, nonzero on error.
1552 static int initvars_table(osl_t
*osh
, char *start
, char *end
, char **vars
,
1555 int c
= (int)(end
- start
);
1557 /* do it only when there is more than just the null string */
1559 char *vp
= kmalloc(c
, GFP_ATOMIC
);
1563 bcopy(start
, vp
, c
);
1575 * Find variables with <devpath> from flash. 'base' points to the beginning
1576 * of the table upon enter and to the end of the table upon exit when success.
1577 * Return 0 on success, nonzero on error.
1579 static int initvars_flash(si_t
*sih
, osl_t
*osh
, char **base
, uint len
)
1585 uint l
, dl
, copy_len
;
1586 char devpath
[SI_DEVPATH_BUFSZ
];
1588 /* allocate memory and read in flash */
1589 flash
= kmalloc(NVRAM_SPACE
, GFP_ATOMIC
);
1592 err
= nvram_getall(flash
, NVRAM_SPACE
);
1596 si_devpath(sih
, devpath
, sizeof(devpath
));
1598 /* grab vars with the <devpath> prefix in name */
1599 dl
= strlen(devpath
);
1600 for (s
= flash
; s
&& *s
; s
+= l
+ 1) {
1603 /* skip non-matching variable */
1604 if (strncmp(s
, devpath
, dl
))
1607 /* is there enough room to copy? */
1608 copy_len
= l
- dl
+ 1;
1609 if (len
< copy_len
) {
1610 err
= BCME_BUFTOOSHORT
;
1614 /* no prefix, just the name=value */
1615 strncpy(vp
, &s
[dl
], copy_len
);
1620 /* add null string as terminator */
1622 err
= BCME_BUFTOOSHORT
;
1634 * Initialize nonvolatile variable table from flash.
1635 * Return 0 on success, nonzero on error.
1637 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
)
1639 osl_t
*osh
= si_osh(sih
);
1643 ASSERT(vars
!= NULL
);
1644 ASSERT(count
!= NULL
);
1646 base
= vp
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
1651 err
= initvars_flash(sih
, osh
, &vp
, MAXSZ_NVRAM_VARS
);
1653 err
= initvars_table(osh
, base
, vp
, vars
, count
);
1660 /* Parse SROM and create name=value pairs. 'srom' points to
1661 * the SROM word array. 'off' specifies the offset of the
1662 * first word 'srom' points to, which should be either 0 or
1663 * SROM3_SWRG_OFF (full SROM or software region).
1666 static uint
mask_shift(u16 mask
)
1669 for (i
= 0; i
< (sizeof(mask
) << 3); i
++) {
1670 if (mask
& (1 << i
))
1677 static uint
mask_width(u16 mask
)
1680 for (i
= (sizeof(mask
) << 3) - 1; i
>= 0; i
--) {
1681 if (mask
& (1 << i
))
1682 return (uint
) (i
- mask_shift(mask
) + 1);
1689 static bool mask_valid(u16 mask
)
1691 uint shift
= mask_shift(mask
);
1692 uint width
= mask_width(mask
);
1693 return mask
== ((~0 << shift
) & ~(~0 << (shift
+ width
)));
1697 static void _initvars_srom_pci(u8 sromrev
, u16
*srom
, uint off
, varbuf_t
*b
)
1701 const sromvar_t
*srv
;
1704 u32 sr
= (1 << sromrev
);
1706 varbuf_append(b
, "sromrev=%d", sromrev
);
1708 for (srv
= pci_sromvars
; srv
->name
!= NULL
; srv
++) {
1711 if ((srv
->revmask
& sr
) == 0)
1720 /* This entry is for mfgc only. Don't generate param for it, */
1721 if (flags
& SRFL_NOVAR
)
1724 if (flags
& SRFL_ETHADDR
) {
1725 struct ether_addr ea
;
1727 ea
.octet
[0] = (srom
[srv
->off
- off
] >> 8) & 0xff;
1728 ea
.octet
[1] = srom
[srv
->off
- off
] & 0xff;
1729 ea
.octet
[2] = (srom
[srv
->off
+ 1 - off
] >> 8) & 0xff;
1730 ea
.octet
[3] = srom
[srv
->off
+ 1 - off
] & 0xff;
1731 ea
.octet
[4] = (srom
[srv
->off
+ 2 - off
] >> 8) & 0xff;
1732 ea
.octet
[5] = srom
[srv
->off
+ 2 - off
] & 0xff;
1734 varbuf_append(b
, "%s=%pM", name
, ea
.octet
);
1736 ASSERT(mask_valid(srv
->mask
));
1737 ASSERT(mask_width(srv
->mask
));
1739 w
= srom
[srv
->off
- off
];
1740 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
1741 width
= mask_width(srv
->mask
);
1743 while (srv
->flags
& SRFL_MORE
) {
1745 ASSERT(srv
->name
!= NULL
);
1747 if (srv
->off
== 0 || srv
->off
< off
)
1750 ASSERT(mask_valid(srv
->mask
));
1751 ASSERT(mask_width(srv
->mask
));
1753 w
= srom
[srv
->off
- off
];
1755 ((w
& srv
->mask
) >> mask_shift(srv
->
1758 width
+= mask_width(srv
->mask
);
1761 if ((flags
& SRFL_NOFFS
)
1762 && ((int)val
== (1 << width
) - 1))
1765 if (flags
& SRFL_CCODE
) {
1767 varbuf_append(b
, "ccode=");
1769 varbuf_append(b
, "ccode=%c%c",
1770 (val
>> 8), (val
& 0xff));
1772 /* LED Powersave duty cycle has to be scaled:
1773 *(oncount >> 24) (offcount >> 8)
1775 else if (flags
& SRFL_LEDDC
) {
1776 u32 w32
= (((val
>> 8) & 0xff) << 24) | /* oncount */
1777 (((val
& 0xff)) << 8); /* offcount */
1778 varbuf_append(b
, "leddc=%d", w32
);
1779 } else if (flags
& SRFL_PRHEX
)
1780 varbuf_append(b
, "%s=0x%x", name
, val
);
1781 else if ((flags
& SRFL_PRSIGN
)
1782 && (val
& (1 << (width
- 1))))
1783 varbuf_append(b
, "%s=%d", name
,
1784 (int)(val
| (~0 << width
)));
1786 varbuf_append(b
, "%s=%u", name
, val
);
1791 /* Do per-path variables */
1796 psz
= SROM8_PATH1
- SROM8_PATH0
;
1799 psz
= SROM4_PATH1
- SROM4_PATH0
;
1802 for (p
= 0; p
< MAX_PATH_SROM
; p
++) {
1803 for (srv
= perpath_pci_sromvars
; srv
->name
!= NULL
;
1805 if ((srv
->revmask
& sr
) == 0)
1808 if (pb
+ srv
->off
< off
)
1811 /* This entry is for mfgc only. Don't generate param for it, */
1812 if (srv
->flags
& SRFL_NOVAR
)
1815 w
= srom
[pb
+ srv
->off
- off
];
1817 ASSERT(mask_valid(srv
->mask
));
1818 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
1819 width
= mask_width(srv
->mask
);
1821 /* Cheating: no per-path var is more than 1 word */
1823 if ((srv
->flags
& SRFL_NOFFS
)
1824 && ((int)val
== (1 << width
) - 1))
1827 if (srv
->flags
& SRFL_PRHEX
)
1828 varbuf_append(b
, "%s%d=0x%x", srv
->name
,
1831 varbuf_append(b
, "%s%d=%d", srv
->name
,
1840 * Initialize nonvolatile variable table from sprom.
1841 * Return 0 on success, nonzero on error.
1843 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
, uint
*count
)
1845 u16
*srom
, *sromwindow
;
1849 char *vp
, *base
= NULL
;
1850 osl_t
*osh
= si_osh(sih
);
1855 * Apply CRC over SROM content regardless SROM is present or not,
1856 * and use variable <devpath>sromrev's existance in flash to decide
1857 * if we should return an error when CRC fails or read SROM variables
1860 srom
= kmalloc(SROM_MAX
, GFP_ATOMIC
);
1861 ASSERT(srom
!= NULL
);
1865 sromwindow
= (u16
*) SROM_OFFSET(sih
);
1866 if (si_is_sprom_available(sih
)) {
1868 sprom_read_pci(osh
, sih
, sromwindow
, 0, srom
, SROM_WORDS
,
1871 if ((srom
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
1872 (((sih
->buscoretype
== PCIE_CORE_ID
)
1873 && (sih
->buscorerev
>= 6))
1874 || ((sih
->buscoretype
== PCI_CORE_ID
)
1875 && (sih
->buscorerev
>= 0xe)))) {
1876 /* sromrev >= 4, read more */
1878 sprom_read_pci(osh
, sih
, sromwindow
, 0, srom
,
1880 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
1882 BS_ERROR(("%s: srom %d, bad crc\n", __func__
,
1885 } else if (err
== 0) {
1886 /* srom is good and is rev < 4 */
1887 /* top word of sprom contains version and crc8 */
1888 sromrev
= srom
[SROM_CRCREV
] & 0xff;
1889 /* bcm4401 sroms misprogrammed */
1890 if (sromrev
== 0x10)
1894 #if defined(BCMNVRAMR)
1895 /* Use OTP if SPROM not available */
1896 else if ((err
= otp_read_pci(osh
, sih
, srom
, SROM_MAX
)) == 0) {
1897 /* OTP only contain SROM rev8/rev9 for now */
1898 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
1903 BS_ERROR(("Neither SPROM nor OTP has valid image\n"));
1906 /* We want internal/wltest driver to come up with default sromvars so we can
1907 * program a blank SPROM/OTP.
1914 value
= si_getdevpathvar(sih
, "sromrev");
1916 sromrev
= (u8
) simple_strtoul(value
, NULL
, 0);
1921 BS_ERROR(("%s, SROM CRC Error\n", __func__
));
1923 value
= si_getnvramflvar(sih
, "sromrev");
1936 /* Bitmask for the sromrev */
1939 /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
1940 if ((sr
& 0x33e) == 0) {
1945 ASSERT(vars
!= NULL
);
1946 ASSERT(count
!= NULL
);
1948 base
= vp
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
1955 /* read variables from flash */
1957 err
= initvars_flash(sih
, osh
, &vp
, MAXSZ_NVRAM_VARS
);
1963 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
1965 /* parse SROM into name=value pairs. */
1966 _initvars_srom_pci(sromrev
, srom
, 0, &b
);
1968 /* final nullbyte terminator */
1969 ASSERT(b
.size
>= 1);
1973 ASSERT((vp
- base
) <= MAXSZ_NVRAM_VARS
);
1976 err
= initvars_table(osh
, base
, vp
, vars
, count
);
1988 * Read the SDIO cis and call parsecis to initialize the vars.
1989 * Return 0 on success, nonzero on error.
1991 static int initvars_cis_sdio(osl_t
*osh
, char **vars
, uint
*count
)
1993 u8
*cis
[SBSDIO_NUM_FUNCTION
+ 1];
1997 numfn
= bcmsdh_query_iofnum(NULL
);
1998 ASSERT(numfn
<= SDIOD_MAX_IOFUNCS
);
2000 for (fn
= 0; fn
<= numfn
; fn
++) {
2001 cis
[fn
] = kzalloc(SBSDIO_CIS_SIZE_LIMIT
, GFP_ATOMIC
);
2002 if (cis
[fn
] == NULL
) {
2007 if (bcmsdh_cis_read(NULL
, fn
, cis
[fn
], SBSDIO_CIS_SIZE_LIMIT
) !=
2016 rc
= srom_parsecis(osh
, cis
, fn
, vars
, count
);
2024 /* set SDIO sprom command register */
2025 static int sprom_cmd_sdio(osl_t
*osh
, u8 cmd
)
2028 uint wait_cnt
= 1000;
2030 /* write sprom command register */
2031 bcmsdh_cfg_write(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_CS
, cmd
, NULL
);
2034 while (wait_cnt
--) {
2036 bcmsdh_cfg_read(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_CS
, NULL
);
2037 if (status
& SBSDIO_SPROM_DONE
)
2044 /* read a word from the SDIO srom */
2045 static int sprom_read_sdio(osl_t
*osh
, u16 addr
, u16
*data
)
2047 u8 addr_l
, addr_h
, data_l
, data_h
;
2049 addr_l
= (u8
) ((addr
* 2) & 0xff);
2050 addr_h
= (u8
) (((addr
* 2) >> 8) & 0xff);
2053 bcmsdh_cfg_write(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_ADDR_HIGH
, addr_h
,
2055 bcmsdh_cfg_write(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_ADDR_LOW
, addr_l
,
2059 if (sprom_cmd_sdio(osh
, SBSDIO_SPROM_READ
))
2064 bcmsdh_cfg_read(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_DATA_HIGH
, NULL
);
2066 bcmsdh_cfg_read(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_DATA_LOW
, NULL
);
2068 *data
= (data_h
<< 8) | data_l
;
2071 #endif /* BCMSDIO */
2073 static int initvars_srom_si(si_t
*sih
, osl_t
*osh
, void *curmap
, char **vars
,
2076 /* Search flash nvram section for srom variables */
2077 return initvars_flash_si(sih
, vars
, varsz
);