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.
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/etherdevice.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
30 #include <bcmsrom_tbl.h>
42 #include <sbsdpcmdev.h>
45 #include <linux/if_ether.h>
47 #define BS_ERROR(args)
49 #define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
50 (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
51 ((u8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
52 ((u8 *)curmap + PCI_BAR0_SPROM_OFFSET))
55 #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
56 #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
59 typedef struct varbuf
{
60 char *base
; /* pointer to buffer base */
61 char *buf
; /* pointer to current position */
62 unsigned int size
; /* current (residual) size in bytes */
67 #define SROM_CIS_SINGLE 1
69 static int initvars_srom_si(si_t
*sih
, void *curmap
, char **vars
, uint
*count
);
70 static void _initvars_srom_pci(u8 sromrev
, u16
*srom
, uint off
, varbuf_t
*b
);
71 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
, uint
*count
);
72 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
);
74 static int initvars_cis_sdio(char **vars
, uint
*count
);
75 static int sprom_cmd_sdio(u8 cmd
);
76 static int sprom_read_sdio(u16 addr
, u16
*data
);
78 static int sprom_read_pci(si_t
*sih
, u16
*sprom
,
79 uint wordoff
, u16
*buf
, uint nwords
, bool check_crc
);
80 #if defined(BCMNVRAMR)
81 static int otp_read_pci(si_t
*sih
, u16
*buf
, uint bufsz
);
83 static u16
srom_cc_cmd(si_t
*sih
, void *ccregs
, u32 cmd
,
84 uint wordoff
, u16 data
);
86 static int initvars_table(char *start
, char *end
,
87 char **vars
, uint
*count
);
88 static int initvars_flash(si_t
*sih
, char **vp
,
91 /* Initialization of varbuf structure */
92 static void varbuf_init(varbuf_t
*b
, char *buf
, uint size
)
95 b
->base
= b
->buf
= buf
;
98 /* append a null terminated var=value string */
99 static int varbuf_append(varbuf_t
*b
, const char *fmt
, ...)
110 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
113 /* C99 snprintf behavior returns r >= size on overflow,
114 * others return -1 on overflow.
115 * All return -1 on format error.
116 * We need to leave room for 2 null terminations, one for the current var
117 * string, and one for final null of the var table. So check that the
118 * strlen written, r, leaves room for 2 chars.
120 if ((r
== -1) || (r
> (int)(b
->size
- 2))) {
125 /* Remove any earlier occurrence of the same variable */
126 s
= strchr(b
->buf
, '=');
128 len
= (size_t) (s
- b
->buf
);
129 for (s
= b
->base
; s
< b
->buf
;) {
130 if ((memcmp(s
, b
->buf
, len
) == 0) && s
[len
] == '=') {
132 memmove(s
, (s
+ len
),
133 ((b
->buf
+ r
+ 1) - (s
+ len
)));
135 b
->size
+= (unsigned int)len
;
144 /* skip over this string's null termination */
153 * Initialize local vars from the right source for this platform.
154 * Return 0 on success, nonzero on error.
156 int srom_var_init(si_t
*sih
, uint bustype
, void *curmap
,
157 char **vars
, uint
*count
)
163 ASSERT(bustype
== bustype
);
164 if (vars
== NULL
|| count
== NULL
)
173 return initvars_srom_si(sih
, curmap
, vars
, count
);
176 ASSERT(curmap
!= NULL
);
180 return initvars_srom_pci(sih
, curmap
, vars
, count
);
184 return initvars_cis_sdio(vars
, count
);
193 /* support only 16-bit word read from srom */
195 srom_read(si_t
*sih
, uint bustype
, void *curmap
,
196 uint byteoff
, uint nbytes
, u16
*buf
, bool check_crc
)
203 ASSERT(bustype
== bustype
);
205 /* check input - 16-bit access only */
206 if (byteoff
& 1 || nbytes
& 1 || (byteoff
+ nbytes
) > SROM_MAX
)
212 if (bustype
== PCI_BUS
) {
216 if (si_is_sprom_available(sih
)) {
219 srom
= (u16
*) SROM_OFFSET(sih
);
224 (sih
, srom
, off
, buf
, nw
, check_crc
))
227 #if defined(BCMNVRAMR)
229 if (otp_read_pci(sih
, buf
, SROM_MAX
))
234 } else if (bustype
== SDIO_BUS
) {
237 for (i
= 0; i
< nw
; i
++) {
239 ((u16
) (off
+ i
), (u16
*) (buf
+ i
)))
243 } else if (bustype
== SI_BUS
) {
252 static const char vstr_manf
[] = "manf=%s";
253 static const char vstr_productname
[] = "productname=%s";
254 static const char vstr_manfid
[] = "manfid=0x%x";
255 static const char vstr_prodid
[] = "prodid=0x%x";
257 static const char vstr_sdmaxspeed
[] = "sdmaxspeed=%d";
258 static const char vstr_sdmaxblk
[][13] = {
259 "sdmaxblk0=%d", "sdmaxblk1=%d", "sdmaxblk2=%d"};
261 static const char vstr_regwindowsz
[] = "regwindowsz=%d";
262 static const char vstr_sromrev
[] = "sromrev=%d";
263 static const char vstr_chiprev
[] = "chiprev=%d";
264 static const char vstr_subvendid
[] = "subvendid=0x%x";
265 static const char vstr_subdevid
[] = "subdevid=0x%x";
266 static const char vstr_boardrev
[] = "boardrev=0x%x";
267 static const char vstr_aa2g
[] = "aa2g=0x%x";
268 static const char vstr_aa5g
[] = "aa5g=0x%x";
269 static const char vstr_ag
[] = "ag%d=0x%x";
270 static const char vstr_cc
[] = "cc=%d";
271 static const char vstr_opo
[] = "opo=%d";
272 static const char vstr_pa0b
[][9] = {
273 "pa0b0=%d", "pa0b1=%d", "pa0b2=%d"};
275 static const char vstr_pa0itssit
[] = "pa0itssit=%d";
276 static const char vstr_pa0maxpwr
[] = "pa0maxpwr=%d";
277 static const char vstr_pa1b
[][9] = {
278 "pa1b0=%d", "pa1b1=%d", "pa1b2=%d"};
280 static const char vstr_pa1lob
[][11] = {
281 "pa1lob0=%d", "pa1lob1=%d", "pa1lob2=%d"};
283 static const char vstr_pa1hib
[][11] = {
284 "pa1hib0=%d", "pa1hib1=%d", "pa1hib2=%d"};
286 static const char vstr_pa1itssit
[] = "pa1itssit=%d";
287 static const char vstr_pa1maxpwr
[] = "pa1maxpwr=%d";
288 static const char vstr_pa1lomaxpwr
[] = "pa1lomaxpwr=%d";
289 static const char vstr_pa1himaxpwr
[] = "pa1himaxpwr=%d";
290 static const char vstr_oem
[] =
291 "oem=%02x%02x%02x%02x%02x%02x%02x%02x";
292 static const char vstr_boardflags
[] = "boardflags=0x%x";
293 static const char vstr_boardflags2
[] = "boardflags2=0x%x";
294 static const char vstr_ledbh
[] = "ledbh%d=0x%x";
295 static const char vstr_noccode
[] = "ccode=0x0";
296 static const char vstr_ccode
[] = "ccode=%c%c";
297 static const char vstr_cctl
[] = "cctl=0x%x";
298 static const char vstr_cckpo
[] = "cckpo=0x%x";
299 static const char vstr_ofdmpo
[] = "ofdmpo=0x%x";
300 static const char vstr_rdlid
[] = "rdlid=0x%x";
301 static const char vstr_rdlrndis
[] = "rdlrndis=%d";
302 static const char vstr_rdlrwu
[] = "rdlrwu=%d";
303 static const char vstr_usbfs
[] = "usbfs=%d";
304 static const char vstr_wpsgpio
[] = "wpsgpio=%d";
305 static const char vstr_wpsled
[] = "wpsled=%d";
306 static const char vstr_rdlsn
[] = "rdlsn=%d";
307 static const char vstr_rssismf2g
[] = "rssismf2g=%d";
308 static const char vstr_rssismc2g
[] = "rssismc2g=%d";
309 static const char vstr_rssisav2g
[] = "rssisav2g=%d";
310 static const char vstr_bxa2g
[] = "bxa2g=%d";
311 static const char vstr_rssismf5g
[] = "rssismf5g=%d";
312 static const char vstr_rssismc5g
[] = "rssismc5g=%d";
313 static const char vstr_rssisav5g
[] = "rssisav5g=%d";
314 static const char vstr_bxa5g
[] = "bxa5g=%d";
315 static const char vstr_tri2g
[] = "tri2g=%d";
316 static const char vstr_tri5gl
[] = "tri5gl=%d";
317 static const char vstr_tri5g
[] = "tri5g=%d";
318 static const char vstr_tri5gh
[] = "tri5gh=%d";
319 static const char vstr_rxpo2g
[] = "rxpo2g=%d";
320 static const char vstr_rxpo5g
[] = "rxpo5g=%d";
321 static const char vstr_boardtype
[] = "boardtype=0x%x";
322 static const char vstr_leddc
[] = "leddc=0x%04x";
323 static const char vstr_vendid
[] = "vendid=0x%x";
324 static const char vstr_devid
[] = "devid=0x%x";
325 static const char vstr_xtalfreq
[] = "xtalfreq=%d";
326 static const char vstr_txchain
[] = "txchain=0x%x";
327 static const char vstr_rxchain
[] = "rxchain=0x%x";
328 static const char vstr_antswitch
[] = "antswitch=0x%x";
329 static const char vstr_regrev
[] = "regrev=0x%x";
330 static const char vstr_antswctl2g
[] = "antswctl2g=0x%x";
331 static const char vstr_triso2g
[] = "triso2g=0x%x";
332 static const char vstr_pdetrange2g
[] = "pdetrange2g=0x%x";
333 static const char vstr_extpagain2g
[] = "extpagain2g=0x%x";
334 static const char vstr_tssipos2g
[] = "tssipos2g=0x%x";
335 static const char vstr_antswctl5g
[] = "antswctl5g=0x%x";
336 static const char vstr_triso5g
[] = "triso5g=0x%x";
337 static const char vstr_pdetrange5g
[] = "pdetrange5g=0x%x";
338 static const char vstr_extpagain5g
[] = "extpagain5g=0x%x";
339 static const char vstr_tssipos5g
[] = "tssipos5g=0x%x";
340 static const char vstr_maxp2ga0
[] = "maxp2ga0=0x%x";
341 static const char vstr_itt2ga0
[] = "itt2ga0=0x%x";
342 static const char vstr_pa
[] = "pa%dgw%da%d=0x%x";
343 static const char vstr_pahl
[] = "pa%dg%cw%da%d=0x%x";
344 static const char vstr_maxp5ga0
[] = "maxp5ga0=0x%x";
345 static const char vstr_itt5ga0
[] = "itt5ga0=0x%x";
346 static const char vstr_maxp5gha0
[] = "maxp5gha0=0x%x";
347 static const char vstr_maxp5gla0
[] = "maxp5gla0=0x%x";
348 static const char vstr_maxp2ga1
[] = "maxp2ga1=0x%x";
349 static const char vstr_itt2ga1
[] = "itt2ga1=0x%x";
350 static const char vstr_maxp5ga1
[] = "maxp5ga1=0x%x";
351 static const char vstr_itt5ga1
[] = "itt5ga1=0x%x";
352 static const char vstr_maxp5gha1
[] = "maxp5gha1=0x%x";
353 static const char vstr_maxp5gla1
[] = "maxp5gla1=0x%x";
354 static const char vstr_cck2gpo
[] = "cck2gpo=0x%x";
355 static const char vstr_ofdm2gpo
[] = "ofdm2gpo=0x%x";
356 static const char vstr_ofdm5gpo
[] = "ofdm5gpo=0x%x";
357 static const char vstr_ofdm5glpo
[] = "ofdm5glpo=0x%x";
358 static const char vstr_ofdm5ghpo
[] = "ofdm5ghpo=0x%x";
359 static const char vstr_cddpo
[] = "cddpo=0x%x";
360 static const char vstr_stbcpo
[] = "stbcpo=0x%x";
361 static const char vstr_bw40po
[] = "bw40po=0x%x";
362 static const char vstr_bwduppo
[] = "bwduppo=0x%x";
363 static const char vstr_mcspo
[] = "mcs%dgpo%d=0x%x";
364 static const char vstr_mcspohl
[] = "mcs%dg%cpo%d=0x%x";
365 static const char vstr_custom
[] = "customvar%d=0x%x";
366 static const char vstr_cckdigfilttype
[] = "cckdigfilttype=%d";
367 static const char vstr_boardnum
[] = "boardnum=%d";
368 static const char vstr_macaddr
[] = "macaddr=%s";
369 static const char vstr_usbepnum
[] = "usbepnum=0x%x";
370 static const char vstr_end
[] = "END\0";
374 /* For dongle HW, accept partial calibration parameters */
375 #define BCMDONGLECASE(n)
377 int srom_parsecis(u8
*pcis
[], uint ciscnt
, char **vars
,
383 u8
*cis
, tup
, tlen
, sromrev
= 1;
385 bool ag_init
= false;
393 ASSERT(vars
!= NULL
);
394 ASSERT(count
!= NULL
);
398 base
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
399 ASSERT(base
!= NULL
);
403 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
404 memset(base
, 0, MAXSZ_NVRAM_VARS
);
406 for (cisnum
= 0; cisnum
< ciscnt
; cisnum
++) {
414 if (tup
== CISTPL_NULL
|| tup
== CISTPL_END
)
419 if (cis
[i
] == CISTPL_NULL
420 || cis
[i
] == CISTPL_END
) {
425 tup
= CISTPL_BRCM_HNBU
;
429 if ((i
+ tlen
) >= CIS_SIZE
)
434 /* assume the strings are good if the version field checks out */
435 if (((cis
[i
+ 1] << 8) + cis
[i
]) >= 0x0008) {
436 varbuf_append(&b
, vstr_manf
,
438 varbuf_append(&b
, vstr_productname
,
447 varbuf_append(&b
, vstr_manfid
,
448 (cis
[i
+ 1] << 8) + cis
[i
]);
449 varbuf_append(&b
, vstr_prodid
,
450 (cis
[i
+ 3] << 8) + cis
[i
+ 2]);
459 case CISTPL_FID_SDIO
:
463 static int base
[] = {
464 -1, 10, 12, 13, 15, 20,
466 35, 40, 45, 50, 55, 60,
469 static int mult
[] = {
470 10, 100, 1000, 10000,
473 ASSERT((mult
[spd
& 0x7] != -1)
476 [(spd
>> 3) & 0x0f]));
486 } else if (cis
[i
] == 1) {
497 /* set macaddr if HNBU_MACADDR not seen yet */
498 if (eabuf
[0] == '\0' &&
500 !is_zero_ether_addr(&cis
[i
+ 2]) &&
501 !is_multicast_ether_addr(&cis
[i
+ 2])) {
504 snprintf(eabuf
, sizeof(eabuf
),
507 /* set boardnum if HNBU_BOARDNUM not seen yet */
518 varbuf_append(&b
, vstr_regwindowsz
,
519 (cis
[i
+ 7] << 8) | cis
[i
+ 6]);
522 case CISTPL_BRCM_HNBU
:
525 sromrev
= cis
[i
+ 1];
526 varbuf_append(&b
, vstr_sromrev
,
531 varbuf_append(&b
, vstr_xtalfreq
,
539 varbuf_append(&b
, vstr_vendid
,
542 varbuf_append(&b
, vstr_devid
,
546 varbuf_append(&b
, vstr_chiprev
,
557 varbuf_append(&b
, vstr_subdevid
,
560 /* subdevid doubles for boardtype */
570 (cis
[i
+ 2] << 8) + cis
[i
+ 1];
578 /* retrieve the patch pairs
579 * from tlen/6; where 6 is
580 * sizeof(patch addr(2)) +
581 * sizeof(patch data(4)).
583 patch_pair
= tlen
/ 6;
585 for (j
= 0; j
< patch_pair
; j
++) {
640 varbuf_append(&b
, vstr_boardrev
,
643 varbuf_append(&b
, vstr_boardrev
,
648 case HNBU_BOARDFLAGS
:
649 w32
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
652 ((cis
[i
+ 4] << 24) +
654 varbuf_append(&b
, vstr_boardflags
, w32
);
658 (cis
[i
+ 6] << 8) + cis
[i
+
673 varbuf_append(&b
, vstr_usbfs
,
678 varbuf_append(&b
, vstr_boardtype
,
685 * what follows is a nonstandard HNBU CIS
686 * that lacks CISTPL_BRCM_HNBU tags
688 * skip 0xff (end of standard CIS)
692 standard_cis
= false;
696 varbuf_append(&b
, vstr_usbepnum
,
697 (cis
[i
+ 2] << 8) | cis
[i
703 varbuf_append(&b
, vstr_aa2g
,
706 varbuf_append(&b
, vstr_aa5g
,
711 varbuf_append(&b
, vstr_ag
, 0,
714 varbuf_append(&b
, vstr_ag
, 1,
717 varbuf_append(&b
, vstr_ag
, 2,
720 varbuf_append(&b
, vstr_ag
, 3,
726 varbuf_append(&b
, vstr_aa5g
,
728 varbuf_append(&b
, vstr_ag
, 1,
733 ASSERT(sromrev
== 1);
734 varbuf_append(&b
, vstr_cc
, cis
[i
+ 1]);
740 ASSERT(sromrev
== 1);
746 ASSERT(sromrev
>= 2);
747 varbuf_append(&b
, vstr_opo
,
761 for (j
= 0; j
< 3; j
++) {
786 ASSERT((sromrev
== 2)
806 for (j
= 0; j
< 3; j
++) {
821 for (j
= 3; j
< 6; j
++) {
836 for (j
= 6; j
< 9; j
++) {
853 ASSERT((tlen
== 19) ||
861 ASSERT(sromrev
== 1);
862 varbuf_append(&b
, vstr_oem
,
863 cis
[i
+ 1], cis
[i
+ 2],
864 cis
[i
+ 3], cis
[i
+ 4],
865 cis
[i
+ 5], cis
[i
+ 6],
866 cis
[i
+ 7], cis
[i
+ 8]);
870 for (j
= 1; j
<= 4; j
++) {
871 if (cis
[i
+ j
] != 0xff) {
883 if ((cis
[i
+ 1] == 0)
884 || (cis
[i
+ 2] == 0))
885 varbuf_append(&b
, vstr_noccode
);
887 varbuf_append(&b
, vstr_ccode
,
890 varbuf_append(&b
, vstr_cctl
,
896 varbuf_append(&b
, vstr_cckpo
,
897 (cis
[i
+ 2] << 8) | cis
[i
904 varbuf_append(&b
, vstr_ofdmpo
,
912 varbuf_append(&b
, vstr_wpsgpio
,
915 varbuf_append(&b
, vstr_wpsled
,
919 case HNBU_RSSISMBXA2G
:
920 ASSERT(sromrev
== 3);
921 varbuf_append(&b
, vstr_rssismf2g
,
923 varbuf_append(&b
, vstr_rssismc2g
,
924 (cis
[i
+ 1] >> 4) & 0xf);
925 varbuf_append(&b
, vstr_rssisav2g
,
927 varbuf_append(&b
, vstr_bxa2g
,
928 (cis
[i
+ 2] >> 3) & 0x3);
931 case HNBU_RSSISMBXA5G
:
932 ASSERT(sromrev
== 3);
933 varbuf_append(&b
, vstr_rssismf5g
,
935 varbuf_append(&b
, vstr_rssismc5g
,
936 (cis
[i
+ 1] >> 4) & 0xf);
937 varbuf_append(&b
, vstr_rssisav5g
,
939 varbuf_append(&b
, vstr_bxa5g
,
940 (cis
[i
+ 2] >> 3) & 0x3);
944 ASSERT(sromrev
== 3);
945 varbuf_append(&b
, vstr_tri2g
,
950 ASSERT(sromrev
== 3);
951 varbuf_append(&b
, vstr_tri5gl
,
953 varbuf_append(&b
, vstr_tri5g
,
955 varbuf_append(&b
, vstr_tri5gh
,
960 ASSERT(sromrev
== 3);
961 varbuf_append(&b
, vstr_rxpo2g
,
966 ASSERT(sromrev
== 3);
967 varbuf_append(&b
, vstr_rxpo5g
,
972 if (!is_zero_ether_addr(&cis
[i
+ 1]) &&
973 !is_multicast_ether_addr(&cis
[i
+ 1])) {
974 snprintf(eabuf
, sizeof(eabuf
),
977 /* set boardnum if HNBU_BOARDNUM not seen yet */
986 /* CIS leddc only has 16bits, convert it to 32bits */
987 w32
= ((cis
[i
+ 2] << 24) | /* oncount */
988 (cis
[i
+ 1] << 8)); /* offcount */
989 varbuf_append(&b
, vstr_leddc
, w32
);
992 case HNBU_CHAINSWITCH
:
993 varbuf_append(&b
, vstr_txchain
,
995 varbuf_append(&b
, vstr_rxchain
,
997 varbuf_append(&b
, vstr_antswitch
,
1003 varbuf_append(&b
, vstr_regrev
,
1009 (cis
[i
+ 2] << 8) + cis
[i
+
1014 SROM8_FEM_ANTSWLUT_MASK
)
1016 SROM8_FEM_ANTSWLUT_SHIFT
);
1017 varbuf_append(&b
, vstr_triso2g
,
1019 SROM8_FEM_TR_ISO_MASK
)
1021 SROM8_FEM_TR_ISO_SHIFT
);
1025 SROM8_FEM_PDET_RANGE_MASK
)
1027 SROM8_FEM_PDET_RANGE_SHIFT
);
1031 SROM8_FEM_EXTPA_GAIN_MASK
)
1033 SROM8_FEM_EXTPA_GAIN_SHIFT
);
1037 SROM8_FEM_TSSIPOS_MASK
)
1039 SROM8_FEM_TSSIPOS_SHIFT
);
1044 (cis
[i
+ 4] << 8) + cis
[i
+
1049 SROM8_FEM_ANTSWLUT_MASK
)
1051 SROM8_FEM_ANTSWLUT_SHIFT
);
1052 varbuf_append(&b
, vstr_triso5g
,
1054 SROM8_FEM_TR_ISO_MASK
)
1056 SROM8_FEM_TR_ISO_SHIFT
);
1060 SROM8_FEM_PDET_RANGE_MASK
)
1062 SROM8_FEM_PDET_RANGE_SHIFT
);
1066 SROM8_FEM_EXTPA_GAIN_MASK
)
1068 SROM8_FEM_EXTPA_GAIN_SHIFT
);
1072 SROM8_FEM_TSSIPOS_MASK
)
1074 SROM8_FEM_TSSIPOS_SHIFT
);
1078 case HNBU_PAPARMS_C0
:
1079 varbuf_append(&b
, vstr_maxp2ga0
,
1081 varbuf_append(&b
, vstr_itt2ga0
,
1083 varbuf_append(&b
, vstr_pa
, 2, 0, 0,
1086 varbuf_append(&b
, vstr_pa
, 2, 1, 0,
1089 varbuf_append(&b
, vstr_pa
, 2, 2, 0,
1095 varbuf_append(&b
, vstr_maxp5ga0
,
1097 varbuf_append(&b
, vstr_itt5ga0
,
1099 varbuf_append(&b
, vstr_maxp5gha0
,
1101 varbuf_append(&b
, vstr_maxp5gla0
,
1103 varbuf_append(&b
, vstr_pa
, 5, 0, 0,
1104 (cis
[i
+ 14] << 8) +
1106 varbuf_append(&b
, vstr_pa
, 5, 1, 0,
1107 (cis
[i
+ 16] << 8) +
1109 varbuf_append(&b
, vstr_pa
, 5, 2, 0,
1110 (cis
[i
+ 18] << 8) +
1112 varbuf_append(&b
, vstr_pahl
, 5, 'l', 0,
1114 (cis
[i
+ 20] << 8) +
1116 varbuf_append(&b
, vstr_pahl
, 5, 'l', 1,
1118 (cis
[i
+ 22] << 8) +
1120 varbuf_append(&b
, vstr_pahl
, 5, 'l', 2,
1122 (cis
[i
+ 24] << 8) +
1124 varbuf_append(&b
, vstr_pahl
, 5, 'h', 0,
1126 (cis
[i
+ 26] << 8) +
1128 varbuf_append(&b
, vstr_pahl
, 5, 'h', 1,
1130 (cis
[i
+ 28] << 8) +
1132 varbuf_append(&b
, vstr_pahl
, 5, 'h', 2,
1134 (cis
[i
+ 30] << 8) +
1138 case HNBU_PAPARMS_C1
:
1139 varbuf_append(&b
, vstr_maxp2ga1
,
1141 varbuf_append(&b
, vstr_itt2ga1
,
1143 varbuf_append(&b
, vstr_pa
, 2, 0, 1,
1146 varbuf_append(&b
, vstr_pa
, 2, 1, 1,
1149 varbuf_append(&b
, vstr_pa
, 2, 2, 1,
1155 varbuf_append(&b
, vstr_maxp5ga1
,
1157 varbuf_append(&b
, vstr_itt5ga1
,
1159 varbuf_append(&b
, vstr_maxp5gha1
,
1161 varbuf_append(&b
, vstr_maxp5gla1
,
1163 varbuf_append(&b
, vstr_pa
, 5, 0, 1,
1164 (cis
[i
+ 14] << 8) +
1166 varbuf_append(&b
, vstr_pa
, 5, 1, 1,
1167 (cis
[i
+ 16] << 8) +
1169 varbuf_append(&b
, vstr_pa
, 5, 2, 1,
1170 (cis
[i
+ 18] << 8) +
1172 varbuf_append(&b
, vstr_pahl
, 5, 'l', 0,
1174 (cis
[i
+ 20] << 8) +
1176 varbuf_append(&b
, vstr_pahl
, 5, 'l', 1,
1178 (cis
[i
+ 22] << 8) +
1180 varbuf_append(&b
, vstr_pahl
, 5, 'l', 2,
1182 (cis
[i
+ 24] << 8) +
1184 varbuf_append(&b
, vstr_pahl
, 5, 'h', 0,
1186 (cis
[i
+ 26] << 8) +
1188 varbuf_append(&b
, vstr_pahl
, 5, 'h', 1,
1190 (cis
[i
+ 28] << 8) +
1192 varbuf_append(&b
, vstr_pahl
, 5, 'h', 2,
1194 (cis
[i
+ 30] << 8) +
1198 case HNBU_PO_CCKOFDM
:
1199 varbuf_append(&b
, vstr_cck2gpo
,
1202 varbuf_append(&b
, vstr_ofdm2gpo
,
1203 (cis
[i
+ 6] << 24) +
1204 (cis
[i
+ 5] << 16) +
1210 varbuf_append(&b
, vstr_ofdm5gpo
,
1211 (cis
[i
+ 10] << 24) +
1212 (cis
[i
+ 9] << 16) +
1215 varbuf_append(&b
, vstr_ofdm5glpo
,
1216 (cis
[i
+ 14] << 24) +
1217 (cis
[i
+ 13] << 16) +
1218 (cis
[i
+ 12] << 8) +
1220 varbuf_append(&b
, vstr_ofdm5ghpo
,
1221 (cis
[i
+ 18] << 24) +
1222 (cis
[i
+ 17] << 16) +
1223 (cis
[i
+ 16] << 8) +
1228 for (j
= 0; j
<= (tlen
/ 2); j
++) {
1229 varbuf_append(&b
, vstr_mcspo
, 2,
1239 case HNBU_PO_MCS5GM
:
1240 for (j
= 0; j
<= (tlen
/ 2); j
++) {
1241 varbuf_append(&b
, vstr_mcspo
, 5,
1251 case HNBU_PO_MCS5GLH
:
1252 for (j
= 0; j
<= (tlen
/ 4); j
++) {
1253 varbuf_append(&b
, vstr_mcspohl
,
1262 for (j
= 0; j
<= (tlen
/ 4); j
++) {
1263 varbuf_append(&b
, vstr_mcspohl
,
1278 varbuf_append(&b
, vstr_cddpo
,
1284 varbuf_append(&b
, vstr_stbcpo
,
1290 varbuf_append(&b
, vstr_bw40po
,
1295 case HNBU_PO_40MDUP
:
1296 varbuf_append(&b
, vstr_bwduppo
,
1302 varbuf_append(&b
, vstr_ofdm5gpo
,
1303 (cis
[i
+ 4] << 24) +
1304 (cis
[i
+ 3] << 16) +
1307 varbuf_append(&b
, vstr_ofdm5glpo
,
1308 (cis
[i
+ 8] << 24) +
1309 (cis
[i
+ 7] << 16) +
1312 varbuf_append(&b
, vstr_ofdm5ghpo
,
1313 (cis
[i
+ 12] << 24) +
1314 (cis
[i
+ 11] << 16) +
1315 (cis
[i
+ 10] << 8) +
1320 varbuf_append(&b
, vstr_custom
, 1,
1321 ((cis
[i
+ 4] << 24) +
1322 (cis
[i
+ 3] << 16) +
1327 #if defined(BCMSDIO)
1328 case HNBU_SROM3SWRGN
:
1331 u8 srev
= cis
[i
+ 1 + 70];
1333 /* make tuple value 16-bit aligned and parse it */
1334 memcpy(srom
, &cis
[i
+ 1],
1336 _initvars_srom_pci(srev
, srom
,
1339 /* 2.4G antenna gain is included in SROM */
1341 /* Ethernet MAC address is included in SROM */
1345 /* create extra variables */
1347 varbuf_append(&b
, vstr_vendid
,
1353 varbuf_append(&b
, vstr_devid
,
1359 varbuf_append(&b
, vstr_xtalfreq
,
1365 #endif /* defined(BCMSDIO) */
1367 case HNBU_CCKFILTTYPE
:
1368 varbuf_append(&b
, vstr_cckdigfilttype
,
1376 } while (tup
!= CISTPL_END
);
1379 if (boardnum
!= -1) {
1380 varbuf_append(&b
, vstr_boardnum
, boardnum
);
1384 varbuf_append(&b
, vstr_macaddr
, eabuf
);
1387 /* if there is no antenna gain field, set default */
1388 if (getvar(NULL
, "ag0") == NULL
&& ag_init
== false) {
1389 varbuf_append(&b
, vstr_ag
, 0, 0xff);
1392 /* final nullbyte terminator */
1393 ASSERT(b
.size
>= 1);
1396 ASSERT(b
.buf
- base
<= MAXSZ_NVRAM_VARS
);
1397 err
= initvars_table(base
, b
.buf
, vars
, count
);
1403 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
1404 * not in the bus cores.
1407 srom_cc_cmd(si_t
*sih
, void *ccregs
, u32 cmd
,
1408 uint wordoff
, u16 data
)
1410 chipcregs_t
*cc
= (chipcregs_t
*) ccregs
;
1411 uint wait_cnt
= 1000;
1413 if ((cmd
== SRC_OP_READ
) || (cmd
== SRC_OP_WRITE
)) {
1414 W_REG(&cc
->sromaddress
, wordoff
* 2);
1415 if (cmd
== SRC_OP_WRITE
)
1416 W_REG(&cc
->sromdata
, data
);
1419 W_REG(&cc
->sromcontrol
, SRC_START
| cmd
);
1421 while (wait_cnt
--) {
1422 if ((R_REG(&cc
->sromcontrol
) & SRC_BUSY
) == 0)
1427 BS_ERROR(("%s: Command 0x%x timed out\n", __func__
, cmd
));
1430 if (cmd
== SRC_OP_READ
)
1431 return (u16
) R_REG(&cc
->sromdata
);
1436 static inline void ltoh16_buf(u16
*buf
, unsigned int size
)
1438 for (size
/= 2; size
; size
--)
1439 *(buf
+ size
) = le16_to_cpu(*(buf
+ size
));
1442 static inline void htol16_buf(u16
*buf
, unsigned int size
)
1444 for (size
/= 2; size
; size
--)
1445 *(buf
+ size
) = cpu_to_le16(*(buf
+ size
));
1449 * Read in and validate sprom.
1450 * Return 0 on success, nonzero on error.
1453 sprom_read_pci(si_t
*sih
, u16
*sprom
, uint wordoff
,
1454 u16
*buf
, uint nwords
, bool check_crc
)
1458 void *ccregs
= NULL
;
1460 /* read the sprom */
1461 for (i
= 0; i
< nwords
; i
++) {
1463 if (sih
->ccrev
> 31 && ISSIM_ENAB(sih
)) {
1464 /* use indirect since direct is too slow on QT */
1465 if ((sih
->cccaps
& CC_CAP_SROM
) == 0)
1468 ccregs
= (void *)((u8
*) sprom
- CC_SROM_OTP
);
1470 srom_cc_cmd(sih
, ccregs
, SRC_OP_READ
,
1474 if (ISSIM_ENAB(sih
))
1475 buf
[i
] = R_REG(&sprom
[wordoff
+ i
]);
1477 buf
[i
] = R_REG(&sprom
[wordoff
+ i
]);
1482 /* bypass crc checking for simulation to allow srom hack */
1483 if (ISSIM_ENAB(sih
))
1488 if (buf
[0] == 0xffff) {
1489 /* The hardware thinks that an srom that starts with 0xffff
1490 * is blank, regardless of the rest of the content, so declare
1493 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n",
1498 /* fixup the endianness so crc8 will pass */
1499 htol16_buf(buf
, nwords
* 2);
1500 if (hndcrc8((u8
*) buf
, nwords
* 2, CRC8_INIT_VALUE
) !=
1502 /* DBG only pci always read srom4 first, then srom8/9 */
1503 /* BS_ERROR(("%s: bad crc\n", __func__)); */
1506 /* now correct the endianness of the byte array */
1507 ltoh16_buf(buf
, nwords
* 2);
1512 #if defined(BCMNVRAMR)
1513 static int otp_read_pci(si_t
*sih
, u16
*buf
, uint bufsz
)
1516 uint sz
= OTP_SZ_MAX
/ 2; /* size in words */
1519 ASSERT(bufsz
<= OTP_SZ_MAX
);
1521 otp
= kzalloc(OTP_SZ_MAX
, GFP_ATOMIC
);
1526 err
= otp_read_region(sih
, OTP_HW_RGN
, (u16
*) otp
, &sz
);
1528 memcpy(buf
, otp
, bufsz
);
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
1538 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __func__
,
1543 /* fixup the endianness so crc8 will pass */
1544 htol16_buf(buf
, bufsz
);
1545 if (hndcrc8((u8
*) buf
, SROM4_WORDS
* 2, CRC8_INIT_VALUE
) !=
1547 BS_ERROR(("%s: bad crc\n", __func__
));
1550 /* now correct the endianness of the byte array */
1551 ltoh16_buf(buf
, bufsz
);
1555 #endif /* defined(BCMNVRAMR) */
1557 * Create variable table from memory.
1558 * Return 0 on success, nonzero on error.
1560 static int initvars_table(char *start
, char *end
,
1561 char **vars
, uint
*count
)
1563 int c
= (int)(end
- start
);
1565 /* do it only when there is more than just the null string */
1567 char *vp
= kmalloc(c
, GFP_ATOMIC
);
1571 memcpy(vp
, start
, c
);
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.
1587 static int initvars_flash(si_t
*sih
, char **base
, uint len
)
1593 uint l
, dl
, copy_len
;
1594 char devpath
[SI_DEVPATH_BUFSZ
];
1596 /* allocate memory and read in flash */
1597 flash
= kmalloc(NVRAM_SPACE
, GFP_ATOMIC
);
1600 err
= nvram_getall(flash
, NVRAM_SPACE
);
1604 si_devpath(sih
, devpath
, sizeof(devpath
));
1606 /* grab vars with the <devpath> prefix in name */
1607 dl
= strlen(devpath
);
1608 for (s
= flash
; s
&& *s
; s
+= l
+ 1) {
1611 /* skip non-matching variable */
1612 if (strncmp(s
, devpath
, dl
))
1615 /* is there enough room to copy? */
1616 copy_len
= l
- dl
+ 1;
1617 if (len
< copy_len
) {
1618 err
= BCME_BUFTOOSHORT
;
1622 /* no prefix, just the name=value */
1623 strncpy(vp
, &s
[dl
], copy_len
);
1628 /* add null string as terminator */
1630 err
= BCME_BUFTOOSHORT
;
1642 * Initialize nonvolatile variable table from flash.
1643 * Return 0 on success, nonzero on error.
1645 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
)
1650 ASSERT(vars
!= NULL
);
1651 ASSERT(count
!= NULL
);
1653 base
= vp
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
1658 err
= initvars_flash(sih
, &vp
, MAXSZ_NVRAM_VARS
);
1660 err
= initvars_table(base
, vp
, vars
, count
);
1667 /* Parse SROM and create name=value pairs. 'srom' points to
1668 * the SROM word array. 'off' specifies the offset of the
1669 * first word 'srom' points to, which should be either 0 or
1670 * SROM3_SWRG_OFF (full SROM or software region).
1673 static uint
mask_shift(u16 mask
)
1676 for (i
= 0; i
< (sizeof(mask
) << 3); i
++) {
1677 if (mask
& (1 << i
))
1684 static uint
mask_width(u16 mask
)
1687 for (i
= (sizeof(mask
) << 3) - 1; i
>= 0; i
--) {
1688 if (mask
& (1 << i
))
1689 return (uint
) (i
- mask_shift(mask
) + 1);
1696 static bool mask_valid(u16 mask
)
1698 uint shift
= mask_shift(mask
);
1699 uint width
= mask_width(mask
);
1700 return mask
== ((~0 << shift
) & ~(~0 << (shift
+ width
)));
1704 static void _initvars_srom_pci(u8 sromrev
, u16
*srom
, uint off
, varbuf_t
*b
)
1708 const sromvar_t
*srv
;
1711 u32 sr
= (1 << sromrev
);
1713 varbuf_append(b
, "sromrev=%d", sromrev
);
1715 for (srv
= pci_sromvars
; srv
->name
!= NULL
; srv
++) {
1718 if ((srv
->revmask
& sr
) == 0)
1727 /* This entry is for mfgc only. Don't generate param for it, */
1728 if (flags
& SRFL_NOVAR
)
1731 if (flags
& SRFL_ETHADDR
) {
1734 ea
[0] = (srom
[srv
->off
- off
] >> 8) & 0xff;
1735 ea
[1] = srom
[srv
->off
- off
] & 0xff;
1736 ea
[2] = (srom
[srv
->off
+ 1 - off
] >> 8) & 0xff;
1737 ea
[3] = srom
[srv
->off
+ 1 - off
] & 0xff;
1738 ea
[4] = (srom
[srv
->off
+ 2 - off
] >> 8) & 0xff;
1739 ea
[5] = srom
[srv
->off
+ 2 - off
] & 0xff;
1741 varbuf_append(b
, "%s=%pM", name
, ea
);
1743 ASSERT(mask_valid(srv
->mask
));
1744 ASSERT(mask_width(srv
->mask
));
1746 w
= srom
[srv
->off
- off
];
1747 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
1748 width
= mask_width(srv
->mask
);
1750 while (srv
->flags
& SRFL_MORE
) {
1752 ASSERT(srv
->name
!= NULL
);
1754 if (srv
->off
== 0 || srv
->off
< off
)
1757 ASSERT(mask_valid(srv
->mask
));
1758 ASSERT(mask_width(srv
->mask
));
1760 w
= srom
[srv
->off
- off
];
1762 ((w
& srv
->mask
) >> mask_shift(srv
->
1765 width
+= mask_width(srv
->mask
);
1768 if ((flags
& SRFL_NOFFS
)
1769 && ((int)val
== (1 << width
) - 1))
1772 if (flags
& SRFL_CCODE
) {
1774 varbuf_append(b
, "ccode=");
1776 varbuf_append(b
, "ccode=%c%c",
1777 (val
>> 8), (val
& 0xff));
1779 /* LED Powersave duty cycle has to be scaled:
1780 *(oncount >> 24) (offcount >> 8)
1782 else if (flags
& SRFL_LEDDC
) {
1783 u32 w32
= (((val
>> 8) & 0xff) << 24) | /* oncount */
1784 (((val
& 0xff)) << 8); /* offcount */
1785 varbuf_append(b
, "leddc=%d", w32
);
1786 } else if (flags
& SRFL_PRHEX
)
1787 varbuf_append(b
, "%s=0x%x", name
, val
);
1788 else if ((flags
& SRFL_PRSIGN
)
1789 && (val
& (1 << (width
- 1))))
1790 varbuf_append(b
, "%s=%d", name
,
1791 (int)(val
| (~0 << width
)));
1793 varbuf_append(b
, "%s=%u", name
, val
);
1798 /* Do per-path variables */
1803 psz
= SROM8_PATH1
- SROM8_PATH0
;
1806 psz
= SROM4_PATH1
- SROM4_PATH0
;
1809 for (p
= 0; p
< MAX_PATH_SROM
; p
++) {
1810 for (srv
= perpath_pci_sromvars
; srv
->name
!= NULL
;
1812 if ((srv
->revmask
& sr
) == 0)
1815 if (pb
+ srv
->off
< off
)
1818 /* This entry is for mfgc only. Don't generate param for it, */
1819 if (srv
->flags
& SRFL_NOVAR
)
1822 w
= srom
[pb
+ srv
->off
- off
];
1824 ASSERT(mask_valid(srv
->mask
));
1825 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
1826 width
= mask_width(srv
->mask
);
1828 /* Cheating: no per-path var is more than 1 word */
1830 if ((srv
->flags
& SRFL_NOFFS
)
1831 && ((int)val
== (1 << width
) - 1))
1834 if (srv
->flags
& SRFL_PRHEX
)
1835 varbuf_append(b
, "%s%d=0x%x", srv
->name
,
1838 varbuf_append(b
, "%s%d=%d", srv
->name
,
1847 * Initialize nonvolatile variable table from sprom.
1848 * Return 0 on success, nonzero on error.
1850 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
, uint
*count
)
1852 u16
*srom
, *sromwindow
;
1856 char *vp
, *base
= NULL
;
1861 * Apply CRC over SROM content regardless SROM is present or not,
1862 * and use variable <devpath>sromrev's existance in flash to decide
1863 * if we should return an error when CRC fails or read SROM variables
1866 srom
= kmalloc(SROM_MAX
, GFP_ATOMIC
);
1867 ASSERT(srom
!= NULL
);
1871 sromwindow
= (u16
*) SROM_OFFSET(sih
);
1872 if (si_is_sprom_available(sih
)) {
1874 sprom_read_pci(sih
, sromwindow
, 0, srom
, SROM_WORDS
,
1877 if ((srom
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
1878 (((sih
->buscoretype
== PCIE_CORE_ID
)
1879 && (sih
->buscorerev
>= 6))
1880 || ((sih
->buscoretype
== PCI_CORE_ID
)
1881 && (sih
->buscorerev
>= 0xe)))) {
1882 /* sromrev >= 4, read more */
1884 sprom_read_pci(sih
, sromwindow
, 0, srom
,
1886 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
1888 BS_ERROR(("%s: srom %d, bad crc\n", __func__
,
1891 } else if (err
== 0) {
1892 /* srom is good and is rev < 4 */
1893 /* top word of sprom contains version and crc8 */
1894 sromrev
= srom
[SROM_CRCREV
] & 0xff;
1895 /* bcm4401 sroms misprogrammed */
1896 if (sromrev
== 0x10)
1900 #if defined(BCMNVRAMR)
1901 /* Use OTP if SPROM not available */
1903 err
= otp_read_pci(sih
, srom
, SROM_MAX
);
1905 /* OTP only contain SROM rev8/rev9 for now */
1906 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
1916 * We want internal/wltest driver to come up with default
1917 * sromvars so we can program a blank SPROM/OTP.
1924 BS_ERROR(("Neither SPROM nor OTP has valid image\n"));
1925 value
= si_getdevpathvar(sih
, "sromrev");
1927 sromrev
= (u8
) simple_strtoul(value
, NULL
, 0);
1932 BS_ERROR(("%s, SROM CRC Error\n", __func__
));
1934 value
= si_getnvramflvar(sih
, "sromrev");
1947 /* Bitmask for the sromrev */
1950 /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
1951 if ((sr
& 0x33e) == 0) {
1956 ASSERT(vars
!= NULL
);
1957 ASSERT(count
!= NULL
);
1959 base
= vp
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
1966 /* read variables from flash */
1968 err
= initvars_flash(sih
, &vp
, MAXSZ_NVRAM_VARS
);
1974 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
1976 /* parse SROM into name=value pairs. */
1977 _initvars_srom_pci(sromrev
, srom
, 0, &b
);
1979 /* final nullbyte terminator */
1980 ASSERT(b
.size
>= 1);
1984 ASSERT((vp
- base
) <= MAXSZ_NVRAM_VARS
);
1987 err
= initvars_table(base
, vp
, vars
, count
);
1999 * Read the SDIO cis and call parsecis to initialize the vars.
2000 * Return 0 on success, nonzero on error.
2002 static int initvars_cis_sdio(char **vars
, uint
*count
)
2004 u8
*cis
[SBSDIO_NUM_FUNCTION
+ 1];
2008 numfn
= bcmsdh_query_iofnum(NULL
);
2009 ASSERT(numfn
<= SDIOD_MAX_IOFUNCS
);
2011 for (fn
= 0; fn
<= numfn
; fn
++) {
2012 cis
[fn
] = kzalloc(SBSDIO_CIS_SIZE_LIMIT
, GFP_ATOMIC
);
2013 if (cis
[fn
] == NULL
) {
2018 if (bcmsdh_cis_read(NULL
, fn
, cis
[fn
], SBSDIO_CIS_SIZE_LIMIT
) !=
2027 rc
= srom_parsecis(cis
, fn
, vars
, count
);
2035 /* set SDIO sprom command register */
2036 static int sprom_cmd_sdio(u8 cmd
)
2039 uint wait_cnt
= 1000;
2041 /* write sprom command register */
2042 bcmsdh_cfg_write(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_CS
, cmd
, NULL
);
2045 while (wait_cnt
--) {
2047 bcmsdh_cfg_read(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_CS
, NULL
);
2048 if (status
& SBSDIO_SPROM_DONE
)
2055 /* read a word from the SDIO srom */
2056 static int sprom_read_sdio(u16 addr
, u16
*data
)
2058 u8 addr_l
, addr_h
, data_l
, data_h
;
2060 addr_l
= (u8
) ((addr
* 2) & 0xff);
2061 addr_h
= (u8
) (((addr
* 2) >> 8) & 0xff);
2064 bcmsdh_cfg_write(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_ADDR_HIGH
, addr_h
,
2066 bcmsdh_cfg_write(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_ADDR_LOW
, addr_l
,
2070 if (sprom_cmd_sdio(SBSDIO_SPROM_READ
))
2075 bcmsdh_cfg_read(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_DATA_HIGH
, NULL
);
2077 bcmsdh_cfg_read(NULL
, SDIO_FUNC_1
, SBSDIO_SPROM_DATA_LOW
, NULL
);
2079 *data
= (data_h
<< 8) | data_l
;
2082 #endif /* BCMSDIO */
2084 static int initvars_srom_si(si_t
*sih
, void *curmap
, char **vars
, uint
*varsz
)
2086 /* Search flash nvram section for srom variables */
2087 return initvars_flash_si(sih
, vars
, varsz
);