2 * Routines to access SPROM and to parse SROM/CIS variables.
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: bcmsrom.c,v 1.336.8.71 2011-01-28 00:42:43 Exp $
29 #include <bcmendian.h>
34 #include <bcmsrom_tbl.h>
42 #if defined(BCMUSBDEV)
45 #include <sbsdpcmdev.h>
48 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
51 #include <proto/ethernet.h> /* for sprom content groking */
54 #if defined(BCMDBG_ERR) || defined(WLTEST)
55 #define BS_ERROR(args) printf args
57 #define BS_ERROR(args)
60 #define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
61 (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
62 ((uint8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
63 ((uint8 *)curmap + PCI_BAR0_SPROM_OFFSET))
65 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
66 #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
67 #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
70 typedef struct varbuf
{
71 char *base
; /* pointer to buffer base */
72 char *buf
; /* pointer to current position */
73 unsigned int size
; /* current (residual) size in bytes */
78 #define SROM_CIS_SINGLE 1
81 static int initvars_srom_si(si_t
*sih
, osl_t
*osh
, void *curmap
, char **vars
, uint
*count
);
82 static void _initvars_srom_pci(uint8 sromrev
, uint16
*srom
, uint off
, varbuf_t
*b
);
83 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
, uint
*count
);
84 static int initvars_cis_pcmcia(si_t
*sih
, osl_t
*osh
, char **vars
, uint
*count
);
85 #if !defined(BCMUSBDEV)
86 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
);
89 static int initvars_cis_spi(osl_t
*osh
, char **vars
, uint
*count
);
91 static int sprom_cmd_pcmcia(osl_t
*osh
, uint8 cmd
);
92 static int sprom_read_pcmcia(osl_t
*osh
, uint16 addr
, uint16
*data
);
93 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
94 static int sprom_write_pcmcia(osl_t
*osh
, uint16 addr
, uint16 data
);
96 static int sprom_read_pci(osl_t
*osh
, si_t
*sih
, uint16
*sprom
, uint wordoff
, uint16
*buf
,
97 uint nwords
, bool check_crc
);
98 #if defined(BCMNVRAMW) || defined(BCMNVRAMR)
99 static int otp_read_pci(osl_t
*osh
, si_t
*sih
, uint16
*buf
, uint bufsz
);
100 #endif /* defined(BCMNVRAMW) || defined(BCMNVRAMR) */
101 static uint16
srom_cc_cmd(si_t
*sih
, osl_t
*osh
, void *ccregs
, uint32 cmd
, uint wordoff
,
104 static int initvars_table(osl_t
*osh
, char *start
, char *end
, char **vars
, uint
*count
);
105 static int initvars_flash(si_t
*sih
, osl_t
*osh
, char **vp
, uint len
);
107 #if defined(BCMUSBDEV)
108 static int get_si_pcmcia_srom(si_t
*sih
, osl_t
*osh
, uint8
*pcmregs
,
109 uint boff
, uint16
*srom
, uint bsz
, bool check_crc
);
110 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
111 static int set_si_pcmcia_srom(si_t
*sih
, osl_t
*osh
, uint8
*pcmregs
,
112 uint boff
, uint16
*srom
, uint bsz
);
116 #if defined(BCMUSBDEV_BMAC)
117 /* default to bcm94323 P200, other boards should have OTP programmed */
118 static char BCMATTACHDATA(defaultsromvars_4322usb
)[] =
122 "macaddr=00:90:4c:d3:04:73\0"
127 "boardflags2=0x602\0"
194 static char BCMATTACHDATA(defaultsromvars_43234usb
)[] =
198 "macaddr=00:90:4c:03:21:23\0"
232 "ofdm2gpo=0x44444444\0"
294 static char BCMATTACHDATA(defaultsromvars_43235usb
)[] =
298 "macaddr=00:90:4c:05:30:01\0"
347 "temp_hysteresis=5\0"
350 static char BCMATTACHDATA(defaultsromvars_43236usb
)[] =
354 "macaddr=00:90:4c:03:21:23\0"
376 "boardflags2=0x2000\0"
450 "temp_hysteresis=5\0"
453 static char BCMATTACHDATA(defaultsromvars_4319usb
)[] =
459 "boardflags=0x400201\0"
478 "ofdmpo=0x22220000\0"
486 "macaddr=00:90:4c:16:01:23\0"
488 #endif /* BCMUSBDEV_BMAC */
491 /* BCMHOSTVARS is enabled only if WLTEST is enabled or BCMEXTNVM is enabled */
492 #if defined(BCMHOSTVARS)
493 /* Also used by wl_readconfigdata for vars download */
494 char BCMATTACHDATA(mfgsromvars
)[VARS_MAX
];
495 int BCMATTACHDATA(defvarslen
) = 0;
498 /* BCMHOSTVARS is enabled only if WLTEST is enabled or BCMEXTNVM is enabled */
499 #if defined(BCMHOSTVARS)
500 static char BCMATTACHDATA(defaultsromvars_4331
)[] =
506 "boardvendor=0x14e4\0"
508 "macaddr=00:90:4c:1a:20:64\0"
571 "cckbw20ul2gpo=0x0\0"
572 "legofdmbw202gpo=0x0\0"
573 "legofdmbw20ul2gpo=0x0\0"
574 "legofdmbw205glpo=0x0\0"
575 "legofdmbw20ul5glpo=0x0\0"
576 "legofdmbw205gmpo=0x0\0"
577 "legofdmbw20ul5gmpo=0x0\0"
578 "legofdmbw205ghpo=0x0\0"
579 "legofdmbw20ul5ghpo=0x0\0"
581 "mcsbw20ul2gpo=0x0\0"
584 "mcsbw20ul5glpo=0x0\0"
587 "mcsbw20ul5gmpo=0x0\0"
590 "mcsbw20ul5ghpo=0x0\0"
593 "legofdm40duppo=0x0\0"
633 /* BCMHOSTVARS is enabled only if WLTEST is enabled or BCMEXTNVM is enabled */
634 #if defined(BCMHOSTVARS)
635 static char BCMATTACHDATA(defaultsromvars_wltest
)[] =
636 "macaddr=00:90:4c:f8:00:01\0"
637 "et0macaddr=00:11:22:33:44:52\0"
641 "boardvendor=0x14e4\0"
701 /* BCMHOSTVARS is enabled only if WLTEST is enabled or BCMEXTNVM is enabled */
702 #if defined(BCMHOSTVARS) || (defined(BCMUSBDEV_BMAC) || defined(BCM_BMAC_VARS_APPEND))
703 /* It must end with pattern of "END" */
705 BCMATTACHFN(srom_vars_len
)(char *vars
)
711 for (s
= vars
; s
&& *s
;) {
713 if (strcmp(s
, "END") == 0)
719 /* BS_ERROR(("len %d vars[pos] %s\n", pos, s)); */
725 return pos
+ 4; /* include the "END\0" */
729 /* Initialization of varbuf structure */
731 BCMATTACHFN(varbuf_init
)(varbuf_t
*b
, char *buf
, uint size
)
734 b
->base
= b
->buf
= buf
;
737 /* append a null terminated var=value string */
739 BCMATTACHFN(varbuf_append
)(varbuf_t
*b
, const char *fmt
, ...)
750 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
753 /* C99 snprintf behavior returns r >= size on overflow,
754 * others return -1 on overflow.
755 * All return -1 on format error.
756 * We need to leave room for 2 null terminations, one for the current var
757 * string, and one for final null of the var table. So check that the
758 * strlen written, r, leaves room for 2 chars.
760 if ((r
== -1) || (r
> (int)(b
->size
- 2))) {
765 /* Remove any earlier occurrence of the same variable */
766 if ((s
= strchr(b
->buf
, '=')) != NULL
) {
767 len
= (size_t)(s
- b
->buf
);
768 for (s
= b
->base
; s
< b
->buf
;) {
769 if ((bcmp(s
, b
->buf
, len
) == 0) && s
[len
] == '=') {
771 memmove(s
, (s
+ len
), ((b
->buf
+ r
+ 1) - (s
+ len
)));
773 b
->size
+= (unsigned int)len
;
782 /* skip over this string's null termination */
791 * Initialize local vars from the right source for this platform.
792 * Return 0 on success, nonzero on error.
795 BCMATTACHFN(srom_var_init
)(si_t
*sih
, uint bustype
, void *curmap
, osl_t
*osh
,
796 char **vars
, uint
*count
)
802 ASSERT(bustype
== BUSTYPE(bustype
));
803 if (vars
== NULL
|| count
== NULL
)
809 switch (BUSTYPE(bustype
)) {
812 return initvars_srom_si(sih
, osh
, curmap
, vars
, count
);
815 ASSERT(curmap
!= NULL
);
819 return initvars_srom_pci(sih
, curmap
, vars
, count
);
822 return initvars_cis_pcmcia(sih
, osh
, vars
, count
);
827 return initvars_cis_spi(osh
, vars
, count
);
836 /* support only 16-bit word read from srom */
838 srom_read(si_t
*sih
, uint bustype
, void *curmap
, osl_t
*osh
,
839 uint byteoff
, uint nbytes
, uint16
*buf
, bool check_crc
)
843 ASSERT(bustype
== BUSTYPE(bustype
));
845 /* check input - 16-bit access only */
846 if (byteoff
& 1 || nbytes
& 1 || (byteoff
+ nbytes
) > SROM_MAX
)
852 if (BUSTYPE(bustype
) == PCI_BUS
) {
856 if (si_is_sprom_available(sih
)) {
859 srom
= (uint16
*)SROM_OFFSET(sih
);
863 if (sprom_read_pci(osh
, sih
, srom
, off
, buf
, nw
, check_crc
))
866 #if defined(BCMNVRAMW) || defined(BCMNVRAMR)
868 if (otp_read_pci(osh
, sih
, buf
, SROM_MAX
))
872 } else if (BUSTYPE(bustype
) == PCMCIA_BUS
) {
873 for (i
= 0; i
< nw
; i
++) {
874 if (sprom_read_pcmcia(osh
, (uint16
)(off
+ i
), (uint16
*)(buf
+ i
)))
878 } else if (BUSTYPE(bustype
) == SPI_BUS
) {
879 if (bcmsdh_cis_read(NULL
, SDIO_FUNC_1
, (uint8
*)buf
, byteoff
+ nbytes
) != 0)
882 } else if (BUSTYPE(bustype
) == SI_BUS
) {
883 #if defined(BCMUSBDEV)
884 if (SPROMBUS
== PCMCIA_BUS
) {
890 /* Don't bother if we can't talk to SPROM */
891 if (!si_is_sprom_available(sih
))
894 origidx
= si_coreidx(sih
);
895 regs
= si_setcore(sih
, PCMCIA_CORE_ID
, 0);
897 regs
= si_setcore(sih
, SDIOD_CORE_ID
, 0);
898 ASSERT(regs
!= NULL
);
900 if (!(wasup
= si_iscoreup(sih
)))
901 si_core_reset(sih
, 0, 0);
903 rc
= get_si_pcmcia_srom(sih
, osh
, regs
, byteoff
, buf
, nbytes
, check_crc
);
906 si_core_disable(sih
, 0);
908 si_setcoreidx(sih
, origidx
);
921 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
922 /* support only 16-bit word write into srom */
924 srom_write(si_t
*sih
, uint bustype
, void *curmap
, osl_t
*osh
,
925 uint byteoff
, uint nbytes
, uint16
*buf
)
927 uint i
, nw
, crc_range
;
930 volatile uint32 val32
;
933 ASSERT(bustype
== BUSTYPE(bustype
));
935 old
= MALLOC(osh
, SROM_MAXW
* sizeof(uint16
));
936 new = MALLOC(osh
, SROM_MAXW
* sizeof(uint16
));
938 if (old
== NULL
|| new == NULL
)
941 /* check input - 16-bit access only. use byteoff 0x55aa to indicate
944 if ((byteoff
!= 0x55aa) && ((byteoff
& 1) || (nbytes
& 1)))
947 if ((byteoff
!= 0x55aa) && ((byteoff
+ nbytes
) > SROM_MAX
))
950 if (BUSTYPE(bustype
) == PCMCIA_BUS
) {
951 crc_range
= SROM_MAX
;
953 #if defined(BCMUSBDEV)
955 crc_range
= srom_size(sih
, osh
);
959 crc_range
= (SROM8_SIGN
+ 1) * 2; /* must big enough for SROM8 */
964 /* read first small number words from srom, then adjust the length, read all */
965 if (srom_read(sih
, bustype
, curmap
, osh
, 0, crc_range
, old
, FALSE
))
968 BS_ERROR(("%s: old[SROM4_SIGN] 0x%x, old[SROM8_SIGN] 0x%x\n",
969 __FUNCTION__
, old
[SROM4_SIGN
], old
[SROM8_SIGN
]));
970 /* Deal with blank srom */
971 if (old
[0] == 0xffff) {
972 /* see if the input buffer is valid SROM image or not */
973 if ((buf
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
974 (buf
[SROM8_SIGN
] == SROM4_SIGNATURE
)) {
975 BS_ERROR(("%s: buf[SROM4_SIGN] 0x%x, buf[SROM8_SIGN] 0x%x\n",
976 __FUNCTION__
, buf
[SROM4_SIGN
], buf
[SROM8_SIGN
]));
978 /* block invalid buffer size */
979 if (nbytes
< SROM4_WORDS
* 2) {
980 rc
= BCME_BUFTOOSHORT
;
982 } else if (nbytes
> SROM4_WORDS
* 2) {
983 rc
= BCME_BUFTOOLONG
;
988 } else if (nbytes
== SROM_WORDS
* 2){ /* the other possible SROM format */
989 BS_ERROR(("%s: Not SROM4 or SROM8.\n", __FUNCTION__
));
993 BS_ERROR(("%s: Invalid input file signature\n", __FUNCTION__
));
998 if (srom_read(sih
, bustype
, curmap
, osh
, 0, crc_range
, old
, FALSE
))
1000 } else if ((old
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
1001 (old
[SROM8_SIGN
] == SROM4_SIGNATURE
)) {
1004 if (srom_read(sih
, bustype
, curmap
, osh
, 0, crc_range
, old
, FALSE
))
1007 /* Assert that we have already read enough for sromrev 2 */
1008 ASSERT(crc_range
>= SROM_WORDS
* 2);
1013 if (byteoff
== 0x55aa) {
1016 memset((void *)new, 0xff, nw
* 2);
1018 /* Copy old contents */
1019 bcopy((void *)old
, (void *)new, nw
* 2);
1021 bcopy((void *)buf
, (void *)&new[byteoff
/ 2], nbytes
);
1026 htol16_buf(new, crc_range
);
1027 crc
= ~hndcrc8((uint8
*)new, crc_range
- 1, CRC8_INIT_VALUE
);
1028 ltoh16_buf(new, crc_range
);
1029 new[nw
- 1] = (crc
<< 8) | (new[nw
- 1] & 0xff);
1032 if (BUSTYPE(bustype
) == PCI_BUS
) {
1033 uint16
*srom
= NULL
;
1034 void *ccregs
= NULL
;
1037 if ((CHIPID(sih
->chip
) == BCM4331_CHIP_ID
) ||
1038 (CHIPID(sih
->chip
) == BCM43431_CHIP_ID
)) {
1039 /* save current control setting */
1040 ccval
= si_chipcontrl_epa4331_read(sih
);
1041 /* Disable Ext PA lines to allow reading from SROM */
1042 si_chipcontrl_epa4331(sih
, FALSE
);
1045 /* enable writes to the SPROM */
1046 if (sih
->ccrev
> 31) {
1047 ccregs
= (void *)((uint8
*)curmap
+ PCI_16KB0_CCREGS_OFFSET
);
1048 srom
= (uint16
*)((uint8
*)ccregs
+ CC_SROM_OTP
);
1049 (void)srom_cc_cmd(sih
, osh
, ccregs
, SRC_OP_WREN
, 0, 0);
1051 srom
= (uint16
*)((uint8
*)curmap
+ PCI_BAR0_SPROM_OFFSET
);
1052 val32
= OSL_PCI_READ_CONFIG(osh
, PCI_SPROM_CONTROL
, sizeof(uint32
));
1053 val32
|= SPROM_WRITEEN
;
1054 OSL_PCI_WRITE_CONFIG(osh
, PCI_SPROM_CONTROL
, sizeof(uint32
), val32
);
1056 bcm_mdelay(WRITE_ENABLE_DELAY
);
1058 for (i
= 0; i
< nw
; i
++) {
1059 if (old
[i
] != new[i
]) {
1060 if (sih
->ccrev
> 31) {
1061 if ((sih
->cccaps
& CC_CAP_SROM
) == 0) {
1062 /* No srom support in this chip */
1063 BS_ERROR(("srom_write, invalid srom, skip\n"));
1065 (void)srom_cc_cmd(sih
, osh
, ccregs
, SRC_OP_WRITE
,
1068 W_REG(osh
, &srom
[i
], new[i
]);
1070 bcm_mdelay(WRITE_WORD_DELAY
);
1073 /* disable writes to the SPROM */
1074 if (sih
->ccrev
> 31) {
1075 (void)srom_cc_cmd(sih
, osh
, ccregs
, SRC_OP_WRDIS
, 0, 0);
1077 OSL_PCI_WRITE_CONFIG(osh
, PCI_SPROM_CONTROL
, sizeof(uint32
), val32
&
1081 if ((CHIPID(sih
->chip
) == BCM4331_CHIP_ID
) ||
1082 (CHIPID(sih
->chip
) == BCM43431_CHIP_ID
)) {
1083 /* Restore config after reading SROM */
1084 si_chipcontrl_epa4331_restore(sih
, ccval
);
1087 } else if (BUSTYPE(bustype
) == PCMCIA_BUS
) {
1088 /* enable writes to the SPROM */
1089 if (sprom_cmd_pcmcia(osh
, SROM_WEN
))
1091 bcm_mdelay(WRITE_ENABLE_DELAY
);
1093 for (i
= 0; i
< nw
; i
++) {
1094 if (old
[i
] != new[i
]) {
1095 sprom_write_pcmcia(osh
, (uint16
)(i
), new[i
]);
1096 bcm_mdelay(WRITE_WORD_DELAY
);
1099 /* disable writes to the SPROM */
1100 if (sprom_cmd_pcmcia(osh
, SROM_WDS
))
1102 } else if (BUSTYPE(bustype
) == SI_BUS
) {
1103 #if defined(BCMUSBDEV)
1104 if (SPROMBUS
== PCMCIA_BUS
) {
1109 origidx
= si_coreidx(sih
);
1110 regs
= si_setcore(sih
, PCMCIA_CORE_ID
, 0);
1112 regs
= si_setcore(sih
, SDIOD_CORE_ID
, 0);
1113 ASSERT(regs
!= NULL
);
1115 if (!(wasup
= si_iscoreup(sih
)))
1116 si_core_reset(sih
, 0, 0);
1118 rc
= set_si_pcmcia_srom(sih
, osh
, regs
, byteoff
, buf
, nbytes
);
1121 si_core_disable(sih
, 0);
1123 si_setcoreidx(sih
, origidx
);
1132 bcm_mdelay(WRITE_ENABLE_DELAY
);
1137 MFREE(osh
, old
, SROM_MAXW
* sizeof(uint16
));
1139 MFREE(osh
, new, SROM_MAXW
* sizeof(uint16
));
1145 #if defined(BCMUSBDEV)
1146 #define SI_PCMCIA_READ(osh, regs, fcr) \
1147 R_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2)
1148 #define SI_PCMCIA_WRITE(osh, regs, fcr, v) \
1149 W_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2, v)
1151 /* set PCMCIA srom command register */
1153 srom_cmd_si_pcmcia(osl_t
*osh
, uint8
*pcmregs
, uint8 cmd
)
1158 /* write srom command register */
1159 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_CS
, cmd
);
1162 while (++wait_cnt
< 1000000) {
1163 status
= SI_PCMCIA_READ(osh
, pcmregs
, SROM_CS
);
1164 if (status
& SROM_DONE
)
1169 BS_ERROR(("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt
, status
));
1173 /* read a word from the PCMCIA srom over SI */
1175 srom_read_si_pcmcia(osl_t
*osh
, uint8
*pcmregs
, uint16 addr
, uint16
*data
)
1177 uint8 addr_l
, addr_h
, data_l
, data_h
;
1179 addr_l
= (uint8
)((addr
* 2) & 0xff);
1180 addr_h
= (uint8
)(((addr
* 2) >> 8) & 0xff);
1183 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_ADDRH
, addr_h
);
1184 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_ADDRL
, addr_l
);
1187 if (srom_cmd_si_pcmcia(osh
, pcmregs
, SROM_READ
))
1191 data_h
= SI_PCMCIA_READ(osh
, pcmregs
, SROM_DATAH
);
1192 data_l
= SI_PCMCIA_READ(osh
, pcmregs
, SROM_DATAL
);
1193 *data
= ((uint16
)data_h
<< 8) | data_l
;
1198 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
1199 /* write a word to the PCMCIA srom over SI */
1201 srom_write_si_pcmcia(osl_t
*osh
, uint8
*pcmregs
, uint16 addr
, uint16 data
)
1203 uint8 addr_l
, addr_h
, data_l
, data_h
;
1206 addr_l
= (uint8
)((addr
* 2) & 0xff);
1207 addr_h
= (uint8
)(((addr
* 2) >> 8) & 0xff);
1210 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_ADDRH
, addr_h
);
1211 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_ADDRL
, addr_l
);
1213 data_l
= (uint8
)(data
& 0xff);
1214 data_h
= (uint8
)((data
>> 8) & 0xff);
1217 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_DATAH
, data_h
);
1218 SI_PCMCIA_WRITE(osh
, pcmregs
, SROM_DATAL
, data_l
);
1221 rc
= srom_cmd_si_pcmcia(osh
, pcmregs
, SROM_WRITE
);
1228 * Read the srom for the pcmcia-srom over si case.
1229 * Return 0 on success, nonzero on error.
1232 get_si_pcmcia_srom(si_t
*sih
, osl_t
*osh
, uint8
*pcmregs
,
1233 uint boff
, uint16
*srom
, uint bsz
, bool check_crc
)
1235 uint i
, nw
, woff
, wsz
;
1238 /* read must be at word boundary */
1239 ASSERT((boff
& 1) == 0 && (bsz
& 1) == 0);
1241 /* read sprom size and validate the parms */
1242 if ((nw
= srom_size(sih
, osh
)) == 0) {
1243 BS_ERROR(("get_si_pcmcia_srom: sprom size unknown\n"));
1247 if (boff
+ bsz
> 2 * nw
) {
1248 BS_ERROR(("get_si_pcmcia_srom: sprom size exceeded\n"));
1253 /* read in sprom contents */
1254 for (woff
= boff
/ 2, wsz
= bsz
/ 2, i
= 0;
1255 woff
< nw
&& i
< wsz
; woff
++, i
++) {
1256 if (srom_read_si_pcmcia(osh
, pcmregs
, (uint16
)woff
, &srom
[i
])) {
1257 BS_ERROR(("get_si_pcmcia_srom: sprom read failed\n"));
1264 if (srom
[0] == 0xffff) {
1265 /* The hardware thinks that an srom that starts with 0xffff
1266 * is blank, regardless of the rest of the content, so declare
1269 BS_ERROR(("%s: srom[0] == 0xffff, assuming unprogrammed srom\n",
1275 /* fixup the endianness so crc8 will pass */
1276 htol16_buf(srom
, nw
* 2);
1277 if (hndcrc8((uint8
*)srom
, nw
* 2, CRC8_INIT_VALUE
) != CRC8_GOOD_VALUE
) {
1278 BS_ERROR(("%s: bad crc\n", __FUNCTION__
));
1281 /* now correct the endianness of the byte array */
1282 ltoh16_buf(srom
, nw
* 2);
1289 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
1291 * Write the srom for the pcmcia-srom over si case.
1292 * Return 0 on success, nonzero on error.
1295 set_si_pcmcia_srom(si_t
*sih
, osl_t
*osh
, uint8
*pcmregs
,
1296 uint boff
, uint16
*srom
, uint bsz
)
1298 uint i
, nw
, woff
, wsz
;
1303 /* write must be at word boundary */
1304 ASSERT((boff
& 1) == 0 && (bsz
& 1) == 0);
1306 /* read sprom size and validate the parms */
1307 if ((nw
= srom_size(sih
, osh
)) == 0) {
1308 BS_ERROR(("set_si_pcmcia_srom: sprom size unknown\n"));
1312 if (boff
+ bsz
> 2 * nw
) {
1313 BS_ERROR(("set_si_pcmcia_srom: sprom size exceeded\n"));
1319 if (srom_cmd_si_pcmcia(osh
, pcmregs
, SROM_WEN
)) {
1320 BS_ERROR(("set_si_pcmcia_srom: sprom wen failed\n"));
1325 /* write buffer to sprom */
1326 for (woff
= boff
/ 2, wsz
= bsz
/ 2, i
= 0;
1327 woff
< nw
&& i
< wsz
; woff
++, i
++) {
1328 if (srom_write_si_pcmcia(osh
, pcmregs
, (uint16
)woff
, srom
[i
])) {
1329 BS_ERROR(("set_si_pcmcia_srom: sprom write failed\n"));
1336 crc
= CRC8_INIT_VALUE
;
1337 for (woff
= 0; woff
< nw
; woff
++) {
1338 if (srom_read_si_pcmcia(osh
, pcmregs
, (uint16
)woff
, &word
)) {
1339 BS_ERROR(("set_si_pcmcia_srom: sprom fix crc read failed\n"));
1343 word
= htol16(word
);
1344 crc
= hndcrc8((uint8
*)&word
, woff
!= nw
- 1 ? 2 : 1, crc
);
1346 word
= (~crc
<< 8) + (ltoh16(word
) & 0xff);
1347 if (srom_write_si_pcmcia(osh
, pcmregs
, (uint16
)(woff
- 1), word
)) {
1348 BS_ERROR(("set_si_pcmcia_srom: sprom fix crc write failed\n"));
1354 if (srom_cmd_si_pcmcia(osh
, pcmregs
, SROM_WDS
)) {
1355 BS_ERROR(("set_si_pcmcia_srom: sprom wds failed\n"));
1366 static const char BCMATTACHDATA(vstr_manf
)[] = "manf=%s";
1367 static const char BCMATTACHDATA(vstr_productname
)[] = "productname=%s";
1368 static const char BCMATTACHDATA(vstr_manfid
)[] = "manfid=0x%x";
1369 static const char BCMATTACHDATA(vstr_prodid
)[] = "prodid=0x%x";
1370 static const char BCMATTACHDATA(vstr_regwindowsz
)[] = "regwindowsz=%d";
1371 static const char BCMATTACHDATA(vstr_sromrev
)[] = "sromrev=%d";
1372 static const char BCMATTACHDATA(vstr_chiprev
)[] = "chiprev=%d";
1373 static const char BCMATTACHDATA(vstr_subvendid
)[] = "subvendid=0x%x";
1374 static const char BCMATTACHDATA(vstr_subdevid
)[] = "subdevid=0x%x";
1375 static const char BCMATTACHDATA(vstr_boardrev
)[] = "boardrev=0x%x";
1376 static const char BCMATTACHDATA(vstr_aa2g
)[] = "aa2g=0x%x";
1377 static const char BCMATTACHDATA(vstr_aa5g
)[] = "aa5g=0x%x";
1378 static const char BCMATTACHDATA(vstr_ag
)[] = "ag%d=0x%x";
1379 static const char BCMATTACHDATA(vstr_cc
)[] = "cc=%d";
1380 static const char BCMATTACHDATA(vstr_opo
)[] = "opo=%d";
1381 static const char BCMATTACHDATA(vstr_pa0b
)[][9] = { "pa0b0=%d", "pa0b1=%d", "pa0b2=%d" };
1382 static const char BCMATTACHDATA(vstr_pa0itssit
)[] = "pa0itssit=%d";
1383 static const char BCMATTACHDATA(vstr_pa0maxpwr
)[] = "pa0maxpwr=%d";
1384 static const char BCMATTACHDATA(vstr_pa1b
)[][9] = { "pa1b0=%d", "pa1b1=%d", "pa1b2=%d" };
1385 static const char BCMATTACHDATA(vstr_pa1lob
)[][11] =
1386 { "pa1lob0=%d", "pa1lob1=%d", "pa1lob2=%d" };
1387 static const char BCMATTACHDATA(vstr_pa1hib
)[][11] =
1388 { "pa1hib0=%d", "pa1hib1=%d", "pa1hib2=%d" };
1389 static const char BCMATTACHDATA(vstr_pa1itssit
)[] = "pa1itssit=%d";
1390 static const char BCMATTACHDATA(vstr_pa1maxpwr
)[] = "pa1maxpwr=%d";
1391 static const char BCMATTACHDATA(vstr_pa1lomaxpwr
)[] = "pa1lomaxpwr=%d";
1392 static const char BCMATTACHDATA(vstr_pa1himaxpwr
)[] = "pa1himaxpwr=%d";
1393 static const char BCMATTACHDATA(vstr_oem
)[] = "oem=%02x%02x%02x%02x%02x%02x%02x%02x";
1394 static const char BCMATTACHDATA(vstr_boardflags
)[] = "boardflags=0x%x";
1395 static const char BCMATTACHDATA(vstr_boardflags2
)[] = "boardflags2=0x%x";
1396 static const char BCMATTACHDATA(vstr_ledbh
)[] = "ledbh%d=0x%x";
1397 static const char BCMATTACHDATA(vstr_noccode
)[] = "ccode=0x0";
1398 static const char BCMATTACHDATA(vstr_ccode
)[] = "ccode=%c%c";
1399 static const char BCMATTACHDATA(vstr_cctl
)[] = "cctl=0x%x";
1400 static const char BCMATTACHDATA(vstr_cckpo
)[] = "cckpo=0x%x";
1401 static const char BCMATTACHDATA(vstr_ofdmpo
)[] = "ofdmpo=0x%x";
1402 static const char BCMATTACHDATA(vstr_rdlid
)[] = "rdlid=0x%x";
1403 static const char BCMATTACHDATA(vstr_rdlrndis
)[] = "rdlrndis=%d";
1404 static const char BCMATTACHDATA(vstr_rdlrwu
)[] = "rdlrwu=%d";
1405 static const char BCMATTACHDATA(vstr_usbfs
)[] = "usbfs=%d";
1406 static const char BCMATTACHDATA(vstr_wpsgpio
)[] = "wpsgpio=%d";
1407 static const char BCMATTACHDATA(vstr_wpsled
)[] = "wpsled=%d";
1408 static const char BCMATTACHDATA(vstr_rdlsn
)[] = "rdlsn=%d";
1409 static const char BCMATTACHDATA(vstr_rssismf2g
)[] = "rssismf2g=%d";
1410 static const char BCMATTACHDATA(vstr_rssismc2g
)[] = "rssismc2g=%d";
1411 static const char BCMATTACHDATA(vstr_rssisav2g
)[] = "rssisav2g=%d";
1412 static const char BCMATTACHDATA(vstr_bxa2g
)[] = "bxa2g=%d";
1413 static const char BCMATTACHDATA(vstr_rssismf5g
)[] = "rssismf5g=%d";
1414 static const char BCMATTACHDATA(vstr_rssismc5g
)[] = "rssismc5g=%d";
1415 static const char BCMATTACHDATA(vstr_rssisav5g
)[] = "rssisav5g=%d";
1416 static const char BCMATTACHDATA(vstr_bxa5g
)[] = "bxa5g=%d";
1417 static const char BCMATTACHDATA(vstr_tri2g
)[] = "tri2g=%d";
1418 static const char BCMATTACHDATA(vstr_tri5gl
)[] = "tri5gl=%d";
1419 static const char BCMATTACHDATA(vstr_tri5g
)[] = "tri5g=%d";
1420 static const char BCMATTACHDATA(vstr_tri5gh
)[] = "tri5gh=%d";
1421 static const char BCMATTACHDATA(vstr_rxpo2g
)[] = "rxpo2g=%d";
1422 static const char BCMATTACHDATA(vstr_rxpo5g
)[] = "rxpo5g=%d";
1423 static const char BCMATTACHDATA(vstr_boardtype
)[] = "boardtype=0x%x";
1424 static const char BCMATTACHDATA(vstr_leddc
)[] = "leddc=0x%04x";
1425 static const char BCMATTACHDATA(vstr_vendid
)[] = "vendid=0x%x";
1426 static const char BCMATTACHDATA(vstr_devid
)[] = "devid=0x%x";
1427 static const char BCMATTACHDATA(vstr_xtalfreq
)[] = "xtalfreq=%d";
1428 static const char BCMATTACHDATA(vstr_txchain
)[] = "txchain=0x%x";
1429 static const char BCMATTACHDATA(vstr_rxchain
)[] = "rxchain=0x%x";
1430 static const char BCMATTACHDATA(vstr_antswitch
)[] = "antswitch=0x%x";
1431 static const char BCMATTACHDATA(vstr_regrev
)[] = "regrev=0x%x";
1432 static const char BCMATTACHDATA(vstr_antswctl2g
)[] = "antswctl2g=0x%x";
1433 static const char BCMATTACHDATA(vstr_triso2g
)[] = "triso2g=0x%x";
1434 static const char BCMATTACHDATA(vstr_pdetrange2g
)[] = "pdetrange2g=0x%x";
1435 static const char BCMATTACHDATA(vstr_extpagain2g
)[] = "extpagain2g=0x%x";
1436 static const char BCMATTACHDATA(vstr_tssipos2g
)[] = "tssipos2g=0x%x";
1437 static const char BCMATTACHDATA(vstr_antswctl5g
)[] = "antswctl5g=0x%x";
1438 static const char BCMATTACHDATA(vstr_triso5g
)[] = "triso5g=0x%x";
1439 static const char BCMATTACHDATA(vstr_pdetrange5g
)[] = "pdetrange5g=0x%x";
1440 static const char BCMATTACHDATA(vstr_extpagain5g
)[] = "extpagain5g=0x%x";
1441 static const char BCMATTACHDATA(vstr_tssipos5g
)[] = "tssipos5g=0x%x";
1442 static const char BCMATTACHDATA(vstr_maxp2ga0
)[] = "maxp2ga0=0x%x";
1443 static const char BCMATTACHDATA(vstr_itt2ga0
)[] = "itt2ga0=0x%x";
1444 static const char BCMATTACHDATA(vstr_pa
)[] = "pa%dgw%da%d=0x%x";
1445 static const char BCMATTACHDATA(vstr_pahl
)[] = "pa%dg%cw%da%d=0x%x";
1446 static const char BCMATTACHDATA(vstr_maxp5ga0
)[] = "maxp5ga0=0x%x";
1447 static const char BCMATTACHDATA(vstr_itt5ga0
)[] = "itt5ga0=0x%x";
1448 static const char BCMATTACHDATA(vstr_maxp5gha0
)[] = "maxp5gha0=0x%x";
1449 static const char BCMATTACHDATA(vstr_maxp5gla0
)[] = "maxp5gla0=0x%x";
1450 static const char BCMATTACHDATA(vstr_maxp2ga1
)[] = "maxp2ga1=0x%x";
1451 static const char BCMATTACHDATA(vstr_itt2ga1
)[] = "itt2ga1=0x%x";
1452 static const char BCMATTACHDATA(vstr_maxp5ga1
)[] = "maxp5ga1=0x%x";
1453 static const char BCMATTACHDATA(vstr_itt5ga1
)[] = "itt5ga1=0x%x";
1454 static const char BCMATTACHDATA(vstr_maxp5gha1
)[] = "maxp5gha1=0x%x";
1455 static const char BCMATTACHDATA(vstr_maxp5gla1
)[] = "maxp5gla1=0x%x";
1456 static const char BCMATTACHDATA(vstr_cck2gpo
)[] = "cck2gpo=0x%x";
1457 static const char BCMATTACHDATA(vstr_ofdm2gpo
)[] = "ofdm2gpo=0x%x";
1458 static const char BCMATTACHDATA(vstr_ofdm5gpo
)[] = "ofdm5gpo=0x%x";
1459 static const char BCMATTACHDATA(vstr_ofdm5glpo
)[] = "ofdm5glpo=0x%x";
1460 static const char BCMATTACHDATA(vstr_ofdm5ghpo
)[] = "ofdm5ghpo=0x%x";
1461 static const char BCMATTACHDATA(vstr_cddpo
)[] = "cddpo=0x%x";
1462 static const char BCMATTACHDATA(vstr_stbcpo
)[] = "stbcpo=0x%x";
1463 static const char BCMATTACHDATA(vstr_bw40po
)[] = "bw40po=0x%x";
1464 static const char BCMATTACHDATA(vstr_bwduppo
)[] = "bwduppo=0x%x";
1465 static const char BCMATTACHDATA(vstr_mcspo
)[] = "mcs%dgpo%d=0x%x";
1466 static const char BCMATTACHDATA(vstr_mcspohl
)[] = "mcs%dg%cpo%d=0x%x";
1467 static const char BCMATTACHDATA(vstr_custom
)[] = "customvar%d=0x%x";
1468 static const char BCMATTACHDATA(vstr_cckdigfilttype
)[] = "cckdigfilttype=%d";
1469 #ifdef BCM_BOOTLOADER
1470 static const char BCMATTACHDATA(vstr_brmin
)[] = "brmin=0x%x";
1471 static const char BCMATTACHDATA(vstr_brmax
)[] = "brmax=0x%x";
1472 #endif /* BCM_BOOTLOADER */
1473 static const char BCMATTACHDATA(vstr_boardnum
)[] = "boardnum=%d";
1474 static const char BCMATTACHDATA(vstr_macaddr
)[] = "macaddr=%s";
1475 static const char BCMATTACHDATA(vstr_usbepnum
)[] = "usbepnum=0x%x";
1477 /* Power per rate for SROM V9 */
1478 static const char BCMATTACHDATA(vstr_cckbw202gpo
)[][19] =
1479 { "cckbw202gpo=0x%x", "cckbw20ul2gpo=0x%x" };
1480 static const char BCMATTACHDATA(vstr_legofdmbw202gpo
)[][22] =
1481 { "legofdmbw202gpo=0x%x", "legofdmbw20ul2gpo=0x%x" };
1482 static const char BCMATTACHDATA(vstr_legofdmbw205gpo
)[][24] =
1483 { "legofdmbw205glpo=0x%x", "legofdmbw20ul5glpo=0x%x",
1484 "legofdmbw205gmpo=0x%x", "legofdmbw20ul5gmpo=0x%x",
1485 "legofdmbw205ghpo=0x%x", "legofdmbw20ul5ghpo=0x%x" };
1487 static const char BCMATTACHDATA(vstr_mcs2gpo
)[][19] =
1488 { "mcsbw202gpo=0x%x", "mcsbw20ul2gpo=0x%x", "mcsbw402gpo=0x%x"};
1490 static const char BCMATTACHDATA(vstr_mcs5glpo
)[][20] =
1491 { "mcsbw205glpo=0x%x", "mcsbw20ul5glpo=0x%x", "mcsbw405glpo=0x%x"};
1493 static const char BCMATTACHDATA(vstr_mcs5gmpo
)[][20] =
1494 { "mcsbw205gmpo=0x%x", "mcsbw20ul5gmpo=0x%x", "mcsbw405gmpo=0x%x"};
1496 static const char BCMATTACHDATA(vstr_mcs5ghpo
)[][20] =
1497 { "mcsbw205ghpo=0x%x", "mcsbw20ul5ghpo=0x%x", "mcsbw405ghpo=0x%x"};
1499 static const char BCMATTACHDATA(vstr_mcs32po
)[] = "mcs32po=0x%x";
1500 static const char BCMATTACHDATA(vstr_legofdm40duppo
)[] = "legofdm40duppo=0x%x";
1502 static const char BCMATTACHDATA(vstr_tempthresh
)[] = "tempthresh=%d";
1503 static const char BCMATTACHDATA(vstr_temps_period
)[] = "temps_period=%d";
1504 static const char BCMATTACHDATA(vstr_temp_hysteresis
)[] = "temp_hysteresis=%d";
1506 static const char BCMATTACHDATA(vstr_uuid
)[] = "uuid=%s";
1508 static const char BCMATTACHDATA(vstr_end
)[] = "END\0";
1510 uint8 patch_pair
= 0;
1512 /* For dongle HW, accept partial calibration parameters */
1513 #if defined(BCMUSBDEV)
1514 #define BCMDONGLECASE(n) case n:
1516 #define BCMDONGLECASE(n)
1520 BCMATTACHFN(srom_parsecis
)(osl_t
*osh
, uint8
*pcis
[], uint ciscnt
, char **vars
, uint
*count
)
1525 uint8
*cis
, tup
, tlen
, sromrev
= 1;
1527 #ifndef BCM_BOOTLOADER
1528 bool ag_init
= FALSE
;
1537 ASSERT(vars
!= NULL
);
1538 ASSERT(count
!= NULL
);
1542 base
= MALLOC(osh
, MAXSZ_NVRAM_VARS
);
1543 ASSERT(base
!= NULL
);
1547 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
1548 bzero(base
, MAXSZ_NVRAM_VARS
);
1549 #ifdef BCM_BMAC_VARS_APPEND
1550 /* 43236 use defaultsromvars_43236usb as the base,
1551 * then append and update it with the content from OTP.
1552 * Only revision/board specfic content or updates used to override
1553 * the driver default will be stored in OTP
1555 *count
-= (strlen(vstr_end
) + 1 + 1); /* back off the termnating END\0\0 from fakenvram */
1556 bcopy(*vars
, base
, *count
);
1558 #endif /* BCM_BMAC_VARS_APPEND */
1560 for (cisnum
= 0; cisnum
< ciscnt
; cisnum
++) {
1564 standard_cis
= TRUE
;
1568 if (tup
== CISTPL_NULL
|| tup
== CISTPL_END
)
1573 if (cis
[i
] == CISTPL_NULL
|| cis
[i
] == CISTPL_END
) {
1578 tup
= CISTPL_BRCM_HNBU
;
1582 if ((i
+ tlen
) >= CIS_SIZE
)
1587 /* assume the strings are good if the version field checks out */
1588 if (((cis
[i
+ 1] << 8) + cis
[i
]) >= 0x0008) {
1589 varbuf_append(&b
, vstr_manf
, &cis
[i
+ 2]);
1590 varbuf_append(&b
, vstr_productname
,
1591 &cis
[i
+ 3 + strlen((char *)&cis
[i
+ 2])]);
1596 varbuf_append(&b
, vstr_manfid
, (cis
[i
+ 1] << 8) + cis
[i
]);
1597 varbuf_append(&b
, vstr_prodid
, (cis
[i
+ 3] << 8) + cis
[i
+ 2]);
1606 case CISTPL_FID_SDIO
:
1610 /* set macaddr if HNBU_MACADDR not seen yet */
1611 if (eabuf
[0] == '\0' && cis
[i
] == LAN_NID
&&
1612 !(ETHER_ISNULLADDR(&cis
[i
+ 2])) &&
1613 !(ETHER_ISMULTI(&cis
[i
+ 2]))) {
1614 ASSERT(cis
[i
+ 1] == ETHER_ADDR_LEN
);
1615 bcm_ether_ntoa((struct ether_addr
*)&cis
[i
+ 2],
1618 /* set boardnum if HNBU_BOARDNUM not seen yet */
1620 boardnum
= (cis
[i
+ 6] << 8) + cis
[i
+ 7];
1626 case CISTPL_CFTABLE
:
1627 varbuf_append(&b
, vstr_regwindowsz
, (cis
[i
+ 7] << 8) | cis
[i
+ 6]);
1630 case CISTPL_BRCM_HNBU
:
1633 sromrev
= cis
[i
+ 1];
1634 varbuf_append(&b
, vstr_sromrev
, sromrev
);
1638 varbuf_append(&b
, vstr_xtalfreq
,
1639 (cis
[i
+ 4] << 24) |
1640 (cis
[i
+ 3] << 16) |
1646 varbuf_append(&b
, vstr_vendid
, (cis
[i
+ 2] << 8) +
1648 varbuf_append(&b
, vstr_devid
, (cis
[i
+ 4] << 8) +
1651 varbuf_append(&b
, vstr_chiprev
,
1652 (cis
[i
+ 6] << 8) + cis
[i
+ 5]);
1655 varbuf_append(&b
, vstr_subvendid
,
1656 (cis
[i
+ 8] << 8) + cis
[i
+ 7]);
1659 varbuf_append(&b
, vstr_subdevid
,
1660 (cis
[i
+ 10] << 8) + cis
[i
+ 9]);
1661 /* subdevid doubles for boardtype */
1662 varbuf_append(&b
, vstr_boardtype
,
1663 (cis
[i
+ 10] << 8) + cis
[i
+ 9]);
1668 boardnum
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
1673 char vstr_paddr
[16];
1674 char vstr_pdata
[16];
1676 /* retrieve the patch pairs
1677 * from tlen/6; where 6 is
1678 * sizeof(patch addr(2)) +
1679 * sizeof(patch data(4)).
1681 patch_pair
= tlen
/6;
1683 for (j
= 0; j
< patch_pair
; j
++) {
1684 snprintf(vstr_paddr
, sizeof(vstr_paddr
),
1686 snprintf(vstr_pdata
, sizeof(vstr_pdata
),
1689 varbuf_append(&b
, vstr_paddr
,
1690 (cis
[i
+ (j
*6) + 2] << 8) |
1691 cis
[i
+ (j
*6) + 1]);
1693 varbuf_append(&b
, vstr_pdata
,
1694 (cis
[i
+ (j
*6) + 6] << 24) |
1695 (cis
[i
+ (j
*6) + 5] << 16) |
1696 (cis
[i
+ (j
*6) + 4] << 8) |
1697 cis
[i
+ (j
*6) + 3]);
1704 varbuf_append(&b
, vstr_boardrev
, cis
[i
+ 1]);
1706 varbuf_append(&b
, vstr_boardrev
,
1707 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
1710 case HNBU_BOARDFLAGS
:
1711 w32
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
1713 w32
|= ((cis
[i
+ 4] << 24) + (cis
[i
+ 3] << 16));
1714 varbuf_append(&b
, vstr_boardflags
, w32
);
1717 w32
= (cis
[i
+ 6] << 8) + cis
[i
+ 5];
1719 w32
|= ((cis
[i
+ 8] << 24) +
1720 (cis
[i
+ 7] << 16));
1721 varbuf_append(&b
, vstr_boardflags2
, w32
);
1726 varbuf_append(&b
, vstr_usbfs
, cis
[i
+ 1]);
1729 case HNBU_BOARDTYPE
:
1730 varbuf_append(&b
, vstr_boardtype
,
1731 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
1736 * what follows is a nonstandard HNBU CIS
1737 * that lacks CISTPL_BRCM_HNBU tags
1739 * skip 0xff (end of standard CIS)
1743 standard_cis
= FALSE
;
1747 varbuf_append(&b
, vstr_usbepnum
,
1748 (cis
[i
+ 2] << 8) | cis
[i
+ 1]);
1751 #ifdef BCM_BOOTLOADER
1753 varbuf_append(&b
, vstr_brmin
,
1754 (cis
[i
+ 4] << 24) |
1755 (cis
[i
+ 3] << 16) |
1761 varbuf_append(&b
, vstr_brmax
,
1762 (cis
[i
+ 4] << 24) |
1763 (cis
[i
+ 3] << 16) |
1767 #endif /* BCM_BOOTLOADER */
1770 varbuf_append(&b
, vstr_rdlid
,
1771 (cis
[i
+ 2] << 8) | cis
[i
+ 1]);
1774 #ifdef BCM_BOOTLOADER
1776 varbuf_append(&b
, vstr_rdlrndis
, cis
[i
+ 1]);
1780 varbuf_append(&b
, vstr_rdlrwu
, cis
[i
+ 1]);
1785 varbuf_append(&b
, vstr_rdlsn
,
1786 (cis
[i
+ 4] << 24) |
1787 (cis
[i
+ 3] << 16) |
1791 varbuf_append(&b
, vstr_rdlsn
,
1798 varbuf_append(&b
, vstr_aa2g
, cis
[i
+ 1]);
1800 varbuf_append(&b
, vstr_aa5g
, cis
[i
+ 2]);
1804 varbuf_append(&b
, vstr_ag
, 0, cis
[i
+ 1]);
1806 varbuf_append(&b
, vstr_ag
, 1, cis
[i
+ 2]);
1808 varbuf_append(&b
, vstr_ag
, 2, cis
[i
+ 3]);
1810 varbuf_append(&b
, vstr_ag
, 3, cis
[i
+ 4]);
1815 varbuf_append(&b
, vstr_aa5g
, cis
[i
+ 1]);
1816 varbuf_append(&b
, vstr_ag
, 1, cis
[i
+ 2]);
1820 ASSERT(sromrev
== 1);
1821 varbuf_append(&b
, vstr_cc
, cis
[i
+ 1]);
1827 ASSERT(sromrev
== 1);
1828 varbuf_append(&b
, vstr_pa0maxpwr
, cis
[i
+ 1]);
1831 ASSERT(sromrev
>= 2);
1832 varbuf_append(&b
, vstr_opo
, cis
[i
+ 9]);
1835 varbuf_append(&b
, vstr_pa0maxpwr
, cis
[i
+ 8]);
1838 varbuf_append(&b
, vstr_pa0itssit
, cis
[i
+ 7]);
1841 for (j
= 0; j
< 3; j
++) {
1842 varbuf_append(&b
, vstr_pa0b
[j
],
1843 (cis
[i
+ (j
* 2) + 2] << 8) +
1844 cis
[i
+ (j
* 2) + 1]);
1848 ASSERT((tlen
== 2) || (tlen
== 9) || (tlen
== 10));
1853 case HNBU_PAPARMS5G
:
1854 ASSERT((sromrev
== 2) || (sromrev
== 3));
1857 varbuf_append(&b
, vstr_pa1himaxpwr
, cis
[i
+ 22]);
1858 varbuf_append(&b
, vstr_pa1lomaxpwr
, cis
[i
+ 21]);
1859 varbuf_append(&b
, vstr_pa1maxpwr
, cis
[i
+ 20]);
1862 varbuf_append(&b
, vstr_pa1itssit
, cis
[i
+ 19]);
1865 for (j
= 0; j
< 3; j
++) {
1866 varbuf_append(&b
, vstr_pa1b
[j
],
1867 (cis
[i
+ (j
* 2) + 2] << 8) +
1868 cis
[i
+ (j
* 2) + 1]);
1870 for (j
= 3; j
< 6; j
++) {
1871 varbuf_append(&b
, vstr_pa1lob
[j
- 3],
1872 (cis
[i
+ (j
* 2) + 2] << 8) +
1873 cis
[i
+ (j
* 2) + 1]);
1875 for (j
= 6; j
< 9; j
++) {
1876 varbuf_append(&b
, vstr_pa1hib
[j
- 6],
1877 (cis
[i
+ (j
* 2) + 2] << 8) +
1878 cis
[i
+ (j
* 2) + 1]);
1882 ASSERT((tlen
== 19) ||
1883 (tlen
== 20) || (tlen
== 23));
1889 ASSERT(sromrev
== 1);
1890 varbuf_append(&b
, vstr_oem
,
1891 cis
[i
+ 1], cis
[i
+ 2],
1892 cis
[i
+ 3], cis
[i
+ 4],
1893 cis
[i
+ 5], cis
[i
+ 6],
1894 cis
[i
+ 7], cis
[i
+ 8]);
1898 for (j
= 1; j
<= 4; j
++) {
1899 if (cis
[i
+ j
] != 0xff) {
1900 varbuf_append(&b
, vstr_ledbh
, j
-1,
1907 ASSERT(sromrev
> 1);
1908 if ((cis
[i
+ 1] == 0) || (cis
[i
+ 2] == 0))
1909 varbuf_append(&b
, vstr_noccode
);
1911 varbuf_append(&b
, vstr_ccode
,
1912 cis
[i
+ 1], cis
[i
+ 2]);
1913 varbuf_append(&b
, vstr_cctl
, cis
[i
+ 3]);
1917 ASSERT(sromrev
> 2);
1918 varbuf_append(&b
, vstr_cckpo
,
1919 (cis
[i
+ 2] << 8) | cis
[i
+ 1]);
1923 ASSERT(sromrev
> 2);
1924 varbuf_append(&b
, vstr_ofdmpo
,
1925 (cis
[i
+ 4] << 24) |
1926 (cis
[i
+ 3] << 16) |
1932 varbuf_append(&b
, vstr_wpsgpio
, cis
[i
+ 1]);
1934 varbuf_append(&b
, vstr_wpsled
, cis
[i
+ 2]);
1937 case HNBU_RSSISMBXA2G
:
1938 ASSERT(sromrev
== 3);
1939 varbuf_append(&b
, vstr_rssismf2g
, cis
[i
+ 1] & 0xf);
1940 varbuf_append(&b
, vstr_rssismc2g
, (cis
[i
+ 1] >> 4) & 0xf);
1941 varbuf_append(&b
, vstr_rssisav2g
, cis
[i
+ 2] & 0x7);
1942 varbuf_append(&b
, vstr_bxa2g
, (cis
[i
+ 2] >> 3) & 0x3);
1945 case HNBU_RSSISMBXA5G
:
1946 ASSERT(sromrev
== 3);
1947 varbuf_append(&b
, vstr_rssismf5g
, cis
[i
+ 1] & 0xf);
1948 varbuf_append(&b
, vstr_rssismc5g
, (cis
[i
+ 1] >> 4) & 0xf);
1949 varbuf_append(&b
, vstr_rssisav5g
, cis
[i
+ 2] & 0x7);
1950 varbuf_append(&b
, vstr_bxa5g
, (cis
[i
+ 2] >> 3) & 0x3);
1954 ASSERT(sromrev
== 3);
1955 varbuf_append(&b
, vstr_tri2g
, cis
[i
+ 1]);
1959 ASSERT(sromrev
== 3);
1960 varbuf_append(&b
, vstr_tri5gl
, cis
[i
+ 1]);
1961 varbuf_append(&b
, vstr_tri5g
, cis
[i
+ 2]);
1962 varbuf_append(&b
, vstr_tri5gh
, cis
[i
+ 3]);
1966 ASSERT(sromrev
== 3);
1967 varbuf_append(&b
, vstr_rxpo2g
, cis
[i
+ 1]);
1971 ASSERT(sromrev
== 3);
1972 varbuf_append(&b
, vstr_rxpo5g
, cis
[i
+ 1]);
1976 if (!(ETHER_ISNULLADDR(&cis
[i
+1])) &&
1977 !(ETHER_ISMULTI(&cis
[i
+1]))) {
1978 bcm_ether_ntoa((struct ether_addr
*)&cis
[i
+ 1],
1981 /* set boardnum if HNBU_BOARDNUM not seen yet */
1983 boardnum
= (cis
[i
+ 5] << 8) + cis
[i
+ 6];
1988 /* CIS leddc only has 16bits, convert it to 32bits */
1989 w32
= ((cis
[i
+ 2] << 24) | /* oncount */
1990 (cis
[i
+ 1] << 8)); /* offcount */
1991 varbuf_append(&b
, vstr_leddc
, w32
);
1994 case HNBU_CHAINSWITCH
:
1995 varbuf_append(&b
, vstr_txchain
, cis
[i
+ 1]);
1996 varbuf_append(&b
, vstr_rxchain
, cis
[i
+ 2]);
1997 varbuf_append(&b
, vstr_antswitch
,
1998 (cis
[i
+ 4] << 8) + cis
[i
+ 3]);
2002 varbuf_append(&b
, vstr_regrev
, cis
[i
+ 1]);
2006 uint16 fem
= (cis
[i
+ 2] << 8) + cis
[i
+ 1];
2007 varbuf_append(&b
, vstr_antswctl2g
, (fem
&
2008 SROM8_FEM_ANTSWLUT_MASK
) >>
2009 SROM8_FEM_ANTSWLUT_SHIFT
);
2010 varbuf_append(&b
, vstr_triso2g
, (fem
&
2011 SROM8_FEM_TR_ISO_MASK
) >>
2012 SROM8_FEM_TR_ISO_SHIFT
);
2013 varbuf_append(&b
, vstr_pdetrange2g
, (fem
&
2014 SROM8_FEM_PDET_RANGE_MASK
) >>
2015 SROM8_FEM_PDET_RANGE_SHIFT
);
2016 varbuf_append(&b
, vstr_extpagain2g
, (fem
&
2017 SROM8_FEM_EXTPA_GAIN_MASK
) >>
2018 SROM8_FEM_EXTPA_GAIN_SHIFT
);
2019 varbuf_append(&b
, vstr_tssipos2g
, (fem
&
2020 SROM8_FEM_TSSIPOS_MASK
) >>
2021 SROM8_FEM_TSSIPOS_SHIFT
);
2022 if (tlen
< 5) break;
2024 fem
= (cis
[i
+ 4] << 8) + cis
[i
+ 3];
2025 varbuf_append(&b
, vstr_antswctl5g
, (fem
&
2026 SROM8_FEM_ANTSWLUT_MASK
) >>
2027 SROM8_FEM_ANTSWLUT_SHIFT
);
2028 varbuf_append(&b
, vstr_triso5g
, (fem
&
2029 SROM8_FEM_TR_ISO_MASK
) >>
2030 SROM8_FEM_TR_ISO_SHIFT
);
2031 varbuf_append(&b
, vstr_pdetrange5g
, (fem
&
2032 SROM8_FEM_PDET_RANGE_MASK
) >>
2033 SROM8_FEM_PDET_RANGE_SHIFT
);
2034 varbuf_append(&b
, vstr_extpagain5g
, (fem
&
2035 SROM8_FEM_EXTPA_GAIN_MASK
) >>
2036 SROM8_FEM_EXTPA_GAIN_SHIFT
);
2037 varbuf_append(&b
, vstr_tssipos5g
, (fem
&
2038 SROM8_FEM_TSSIPOS_MASK
) >>
2039 SROM8_FEM_TSSIPOS_SHIFT
);
2043 case HNBU_PAPARMS_C0
:
2044 varbuf_append(&b
, vstr_maxp2ga0
, cis
[i
+ 1]);
2045 varbuf_append(&b
, vstr_itt2ga0
, cis
[i
+ 2]);
2046 varbuf_append(&b
, vstr_pa
, 2, 0, 0,
2047 (cis
[i
+ 4] << 8) + cis
[i
+ 3]);
2048 varbuf_append(&b
, vstr_pa
, 2, 1, 0,
2049 (cis
[i
+ 6] << 8) + cis
[i
+ 5]);
2050 varbuf_append(&b
, vstr_pa
, 2, 2, 0,
2051 (cis
[i
+ 8] << 8) + cis
[i
+ 7]);
2052 if (tlen
< 31) break;
2054 varbuf_append(&b
, vstr_maxp5ga0
, cis
[i
+ 9]);
2055 varbuf_append(&b
, vstr_itt5ga0
, cis
[i
+ 10]);
2056 varbuf_append(&b
, vstr_maxp5gha0
, cis
[i
+ 11]);
2057 varbuf_append(&b
, vstr_maxp5gla0
, cis
[i
+ 12]);
2058 varbuf_append(&b
, vstr_pa
, 5, 0, 0,
2059 (cis
[i
+ 14] << 8) + cis
[i
+ 13]);
2060 varbuf_append(&b
, vstr_pa
, 5, 1, 0,
2061 (cis
[i
+ 16] << 8) + cis
[i
+ 15]);
2062 varbuf_append(&b
, vstr_pa
, 5, 2, 0,
2063 (cis
[i
+ 18] << 8) + cis
[i
+ 17]);
2064 varbuf_append(&b
, vstr_pahl
, 5, 'l', 0, 0,
2065 (cis
[i
+ 20] << 8) + cis
[i
+ 19]);
2066 varbuf_append(&b
, vstr_pahl
, 5, 'l', 1, 0,
2067 (cis
[i
+ 22] << 8) + cis
[i
+ 21]);
2068 varbuf_append(&b
, vstr_pahl
, 5, 'l', 2, 0,
2069 (cis
[i
+ 24] << 8) + cis
[i
+ 23]);
2070 varbuf_append(&b
, vstr_pahl
, 5, 'h', 0, 0,
2071 (cis
[i
+ 26] << 8) + cis
[i
+ 25]);
2072 varbuf_append(&b
, vstr_pahl
, 5, 'h', 1, 0,
2073 (cis
[i
+ 28] << 8) + cis
[i
+ 27]);
2074 varbuf_append(&b
, vstr_pahl
, 5, 'h', 2, 0,
2075 (cis
[i
+ 30] << 8) + cis
[i
+ 29]);
2078 case HNBU_PAPARMS_C1
:
2079 varbuf_append(&b
, vstr_maxp2ga1
, cis
[i
+ 1]);
2080 varbuf_append(&b
, vstr_itt2ga1
, cis
[i
+ 2]);
2081 varbuf_append(&b
, vstr_pa
, 2, 0, 1,
2082 (cis
[i
+ 4] << 8) + cis
[i
+ 3]);
2083 varbuf_append(&b
, vstr_pa
, 2, 1, 1,
2084 (cis
[i
+ 6] << 8) + cis
[i
+ 5]);
2085 varbuf_append(&b
, vstr_pa
, 2, 2, 1,
2086 (cis
[i
+ 8] << 8) + cis
[i
+ 7]);
2087 if (tlen
< 31) break;
2089 varbuf_append(&b
, vstr_maxp5ga1
, cis
[i
+ 9]);
2090 varbuf_append(&b
, vstr_itt5ga1
, cis
[i
+ 10]);
2091 varbuf_append(&b
, vstr_maxp5gha1
, cis
[i
+ 11]);
2092 varbuf_append(&b
, vstr_maxp5gla1
, cis
[i
+ 12]);
2093 varbuf_append(&b
, vstr_pa
, 5, 0, 1,
2094 (cis
[i
+ 14] << 8) + cis
[i
+ 13]);
2095 varbuf_append(&b
, vstr_pa
, 5, 1, 1,
2096 (cis
[i
+ 16] << 8) + cis
[i
+ 15]);
2097 varbuf_append(&b
, vstr_pa
, 5, 2, 1,
2098 (cis
[i
+ 18] << 8) + cis
[i
+ 17]);
2099 varbuf_append(&b
, vstr_pahl
, 5, 'l', 0, 1,
2100 (cis
[i
+ 20] << 8) + cis
[i
+ 19]);
2101 varbuf_append(&b
, vstr_pahl
, 5, 'l', 1, 1,
2102 (cis
[i
+ 22] << 8) + cis
[i
+ 21]);
2103 varbuf_append(&b
, vstr_pahl
, 5, 'l', 2, 1,
2104 (cis
[i
+ 24] << 8) + cis
[i
+ 23]);
2105 varbuf_append(&b
, vstr_pahl
, 5, 'h', 0, 1,
2106 (cis
[i
+ 26] << 8) + cis
[i
+ 25]);
2107 varbuf_append(&b
, vstr_pahl
, 5, 'h', 1, 1,
2108 (cis
[i
+ 28] << 8) + cis
[i
+ 27]);
2109 varbuf_append(&b
, vstr_pahl
, 5, 'h', 2, 1,
2110 (cis
[i
+ 30] << 8) + cis
[i
+ 29]);
2113 case HNBU_PO_CCKOFDM
:
2114 varbuf_append(&b
, vstr_cck2gpo
,
2115 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2116 varbuf_append(&b
, vstr_ofdm2gpo
,
2117 (cis
[i
+ 6] << 24) + (cis
[i
+ 5] << 16) +
2118 (cis
[i
+ 4] << 8) + cis
[i
+ 3]);
2119 if (tlen
< 19) break;
2121 varbuf_append(&b
, vstr_ofdm5gpo
,
2122 (cis
[i
+ 10] << 24) + (cis
[i
+ 9] << 16) +
2123 (cis
[i
+ 8] << 8) + cis
[i
+ 7]);
2124 varbuf_append(&b
, vstr_ofdm5glpo
,
2125 (cis
[i
+ 14] << 24) + (cis
[i
+ 13] << 16) +
2126 (cis
[i
+ 12] << 8) + cis
[i
+ 11]);
2127 varbuf_append(&b
, vstr_ofdm5ghpo
,
2128 (cis
[i
+ 18] << 24) + (cis
[i
+ 17] << 16) +
2129 (cis
[i
+ 16] << 8) + cis
[i
+ 15]);
2133 for (j
= 0; j
<= (tlen
/2); j
++) {
2134 varbuf_append(&b
, vstr_mcspo
, 2, j
,
2135 (cis
[i
+ 2 + 2*j
] << 8) + cis
[i
+ 1 + 2*j
]);
2139 case HNBU_PO_MCS5GM
:
2140 for (j
= 0; j
<= (tlen
/2); j
++) {
2141 varbuf_append(&b
, vstr_mcspo
, 5, j
,
2142 (cis
[i
+ 2 + 2*j
] << 8) + cis
[i
+ 1 + 2*j
]);
2146 case HNBU_PO_MCS5GLH
:
2147 for (j
= 0; j
<= (tlen
/4); j
++) {
2148 varbuf_append(&b
, vstr_mcspohl
, 5, 'l', j
,
2149 (cis
[i
+ 2 + 2*j
] << 8) + cis
[i
+ 1 + 2*j
]);
2152 for (j
= 0; j
<= (tlen
/4); j
++) {
2153 varbuf_append(&b
, vstr_mcspohl
, 5, 'h', j
,
2154 (cis
[i
+ ((tlen
/2)+2) + 2*j
] << 8) +
2155 cis
[i
+ ((tlen
/2)+1) + 2*j
]);
2161 varbuf_append(&b
, vstr_cddpo
,
2162 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2166 varbuf_append(&b
, vstr_stbcpo
,
2167 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2171 varbuf_append(&b
, vstr_bw40po
,
2172 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2175 case HNBU_PO_40MDUP
:
2176 varbuf_append(&b
, vstr_bwduppo
,
2177 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2181 varbuf_append(&b
, vstr_ofdm5gpo
,
2182 (cis
[i
+ 4] << 24) + (cis
[i
+ 3] << 16) +
2183 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2184 varbuf_append(&b
, vstr_ofdm5glpo
,
2185 (cis
[i
+ 8] << 24) + (cis
[i
+ 7] << 16) +
2186 (cis
[i
+ 6] << 8) + cis
[i
+ 5]);
2187 varbuf_append(&b
, vstr_ofdm5ghpo
,
2188 (cis
[i
+ 12] << 24) + (cis
[i
+ 11] << 16) +
2189 (cis
[i
+ 10] << 8) + cis
[i
+ 9]);
2191 /* Power per rate for SROM V9 */
2192 case HNBU_CCKBW202GPO
:
2193 varbuf_append(&b
, vstr_cckbw202gpo
[0],
2194 ((cis
[i
+ 2] << 8) + cis
[i
+ 1]));
2196 varbuf_append(&b
, vstr_cckbw202gpo
[1],
2197 ((cis
[i
+ 4] << 8) + cis
[i
+ 3]));
2200 case HNBU_LEGOFDMBW202GPO
:
2201 varbuf_append(&b
, vstr_legofdmbw202gpo
[0],
2202 ((cis
[i
+ 4] << 24) + (cis
[i
+ 3] << 16) +
2203 (cis
[i
+ 2] << 8) + cis
[i
+ 1]));
2205 varbuf_append(&b
, vstr_legofdmbw202gpo
[1],
2206 ((cis
[i
+ 8] << 24) + (cis
[i
+ 7] << 16) +
2207 (cis
[i
+ 6] << 8) + cis
[i
+ 5]));
2211 case HNBU_LEGOFDMBW205GPO
:
2212 for (j
= 0; j
< 6; j
++) {
2213 if (tlen
< (2 + 4 * j
))
2215 varbuf_append(&b
, vstr_legofdmbw205gpo
[j
],
2216 ((cis
[4 * j
+ i
+ 4] << 24)
2217 + (cis
[4 * j
+ i
+ 3] << 16)
2218 + (cis
[4 * j
+ i
+ 2] << 8)
2219 + cis
[4 * j
+ i
+ 1]));
2224 for (j
= 0; j
< 3; j
++) {
2225 if (tlen
< (2 + 4 * j
))
2227 varbuf_append(&b
, vstr_mcs2gpo
[j
],
2228 ((cis
[4 * j
+ i
+ 4] << 24)
2229 + (cis
[4 * j
+ i
+ 3] << 16)
2230 + (cis
[4 * j
+ i
+ 2] << 8)
2231 + cis
[4 * j
+ i
+ 1]));
2236 for (j
= 0; j
< 3; j
++) {
2237 if (tlen
< (2 + 4 * j
))
2239 varbuf_append(&b
, vstr_mcs5glpo
[j
],
2240 ((cis
[4 * j
+ i
+ 4] << 24)
2241 + (cis
[4 * j
+ i
+ 3] << 16)
2242 + (cis
[4 * j
+ i
+ 2] << 8)
2243 + cis
[4 * j
+ i
+ 1]));
2248 for (j
= 0; j
< 3; j
++) {
2249 if (tlen
< (2 + 4 * j
))
2251 varbuf_append(&b
, vstr_mcs5gmpo
[j
],
2252 ((cis
[4 * j
+ i
+ 4] << 24)
2253 + (cis
[4 * j
+ i
+ 3] << 16)
2254 + (cis
[4 * j
+ i
+ 2] << 8)
2255 + cis
[4 * j
+ i
+ 1]));
2260 for (j
= 0; j
< 3; j
++) {
2261 if (tlen
< (2 + 4 * j
))
2263 varbuf_append(&b
, vstr_mcs5ghpo
[j
],
2264 ((cis
[4 * j
+ i
+ 4] << 24)
2265 + (cis
[4 * j
+ i
+ 3] << 16)
2266 + (cis
[4 * j
+ i
+ 2] << 8)
2267 + cis
[4 * j
+ i
+ 1]));
2272 varbuf_append(&b
, vstr_mcs32po
,
2273 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2276 case HNBU_LEG40DUPPO
:
2277 varbuf_append(&b
, vstr_legofdm40duppo
,
2278 (cis
[i
+ 2] << 8) + cis
[i
+ 1]);
2282 varbuf_append(&b
, vstr_custom
, 1, ((cis
[i
+ 4] << 24) +
2283 (cis
[i
+ 3] << 16) + (cis
[i
+ 2] << 8) +
2287 #if defined(BCMCCISSR3)
2288 case HNBU_SROM3SWRGN
:
2291 uint8 srev
= cis
[i
+ 1 + 70];
2293 /* make tuple value 16-bit aligned and parse it */
2294 bcopy(&cis
[i
+ 1], srom
, sizeof(srom
));
2295 _initvars_srom_pci(srev
, srom
, SROM3_SWRGN_OFF
, &b
);
2296 /* 2.4G antenna gain is included in SROM */
2298 /* Ethernet MAC address is included in SROM */
2302 /* create extra variables */
2304 varbuf_append(&b
, vstr_vendid
,
2305 (cis
[i
+ 1 + 73] << 8) +
2308 varbuf_append(&b
, vstr_devid
,
2309 (cis
[i
+ 1 + 75] << 8) +
2312 varbuf_append(&b
, vstr_xtalfreq
,
2313 (cis
[i
+ 1 + 77] << 8) +
2318 case HNBU_CCKFILTTYPE
:
2319 varbuf_append(&b
, vstr_cckdigfilttype
,
2323 case HNBU_TEMPTHRESH
:
2324 varbuf_append(&b
, vstr_tempthresh
,
2326 /* period in msb nibble */
2327 varbuf_append(&b
, vstr_temps_period
,
2329 /* hysterisis in lsb nibble */
2330 varbuf_append(&b
, vstr_temp_hysteresis
,
2331 (cis
[i
+ 2] & 0xF));
2335 /* uuid format 12345678-1234-5678-1234-567812345678 */
2337 char uuidstr
[37]; /* 32 ids, 4 '-', 1 Null */
2339 snprintf(uuidstr
, sizeof(uuidstr
),
2340 "%02X%02X%02X%02X-%02X%02X-%02X%02X-"
2341 "%02X%02X-%02X%02X%02X%02X%02X%02X",
2342 cis
[i
+ 1], cis
[i
+ 2], cis
[i
+ 3], cis
[i
+ 4],
2343 cis
[i
+ 5], cis
[i
+ 6], cis
[i
+ 7], cis
[i
+ 8],
2344 cis
[i
+ 9], cis
[i
+ 10], cis
[i
+ 11], cis
[i
+ 12],
2345 cis
[i
+ 13], cis
[i
+ 14], cis
[i
+ 15], cis
[i
+ 16]);
2347 varbuf_append(&b
, vstr_uuid
, uuidstr
);
2351 #endif /* !BCM_BOOTLOADER */
2357 } while (tup
!= CISTPL_END
);
2360 if (boardnum
!= -1) {
2361 varbuf_append(&b
, vstr_boardnum
, boardnum
);
2365 varbuf_append(&b
, vstr_macaddr
, eabuf
);
2368 #ifndef BCM_BOOTLOADER
2369 /* if there is no antenna gain field, set default */
2370 if (getvar(NULL
, "ag0") == NULL
&& ag_init
== FALSE
) {
2371 varbuf_append(&b
, vstr_ag
, 0, 0xff);
2375 #if defined(BCMUSBDEV_BMAC) || defined(BCM_BMAC_VARS_APPEND)
2376 varbuf_append(&b
, vstr_end
, NULL
);
2377 #endif /* BCMUSBDEV_BMAC */
2379 /* final nullbyte terminator */
2380 ASSERT(b
.size
>= 1);
2383 ASSERT(b
.buf
- base
<= MAXSZ_NVRAM_VARS
);
2384 err
= initvars_table(osh
, base
, b
.buf
, vars
, count
);
2386 MFREE(osh
, base
, MAXSZ_NVRAM_VARS
);
2390 /* set PCMCIA sprom command register */
2392 sprom_cmd_pcmcia(osl_t
*osh
, uint8 cmd
)
2395 uint wait_cnt
= 1000;
2397 /* write sprom command register */
2398 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_CS
, &cmd
, 1);
2401 while (wait_cnt
--) {
2402 OSL_PCMCIA_READ_ATTR(osh
, SROM_CS
, &status
, 1);
2403 if (status
& SROM_DONE
)
2410 /* read a word from the PCMCIA srom */
2412 sprom_read_pcmcia(osl_t
*osh
, uint16 addr
, uint16
*data
)
2414 uint8 addr_l
, addr_h
, data_l
, data_h
;
2416 addr_l
= (uint8
)((addr
* 2) & 0xff);
2417 addr_h
= (uint8
)(((addr
* 2) >> 8) & 0xff);
2420 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRH
, &addr_h
, 1);
2421 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRL
, &addr_l
, 1);
2424 if (sprom_cmd_pcmcia(osh
, SROM_READ
))
2428 data_h
= data_l
= 0;
2429 OSL_PCMCIA_READ_ATTR(osh
, SROM_DATAH
, &data_h
, 1);
2430 OSL_PCMCIA_READ_ATTR(osh
, SROM_DATAL
, &data_l
, 1);
2432 *data
= (data_h
<< 8) | data_l
;
2436 #if defined(WLTEST) || defined(DHD_SPROM) || defined(BCMDBG)
2437 /* write a word to the PCMCIA srom */
2439 sprom_write_pcmcia(osl_t
*osh
, uint16 addr
, uint16 data
)
2441 uint8 addr_l
, addr_h
, data_l
, data_h
;
2443 addr_l
= (uint8
)((addr
* 2) & 0xff);
2444 addr_h
= (uint8
)(((addr
* 2) >> 8) & 0xff);
2445 data_l
= (uint8
)(data
& 0xff);
2446 data_h
= (uint8
)((data
>> 8) & 0xff);
2449 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRH
, &addr_h
, 1);
2450 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_ADDRL
, &addr_l
, 1);
2453 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_DATAH
, &data_h
, 1);
2454 OSL_PCMCIA_WRITE_ATTR(osh
, SROM_DATAL
, &data_l
, 1);
2457 return sprom_cmd_pcmcia(osh
, SROM_WRITE
);
2461 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
2462 * not in the bus cores.
2465 srom_cc_cmd(si_t
*sih
, osl_t
*osh
, void *ccregs
, uint32 cmd
, uint wordoff
, uint16 data
)
2467 chipcregs_t
*cc
= (chipcregs_t
*)ccregs
;
2468 uint wait_cnt
= 1000;
2470 if ((cmd
== SRC_OP_READ
) || (cmd
== SRC_OP_WRITE
)) {
2471 W_REG(osh
, &cc
->sromaddress
, wordoff
* 2);
2472 if (cmd
== SRC_OP_WRITE
)
2473 W_REG(osh
, &cc
->sromdata
, data
);
2476 W_REG(osh
, &cc
->sromcontrol
, SRC_START
| cmd
);
2478 while (wait_cnt
--) {
2479 if ((R_REG(osh
, &cc
->sromcontrol
) & SRC_BUSY
) == 0)
2484 BS_ERROR(("%s: Command 0x%x timed out\n", __FUNCTION__
, cmd
));
2487 if (cmd
== SRC_OP_READ
)
2488 return (uint16
)R_REG(osh
, &cc
->sromdata
);
2494 * Read in and validate sprom.
2495 * Return 0 on success, nonzero on error.
2498 sprom_read_pci(osl_t
*osh
, si_t
*sih
, uint16
*sprom
, uint wordoff
, uint16
*buf
, uint nwords
,
2503 void *ccregs
= NULL
;
2506 if ((CHIPID(sih
->chip
) == BCM4331_CHIP_ID
) ||
2507 (CHIPID(sih
->chip
) == BCM43431_CHIP_ID
)) {
2508 /* save current control setting */
2509 ccval
= si_chipcontrl_epa4331_read(sih
);
2510 /* Disable Ext PA lines to allow reading from SROM */
2511 si_chipcontrl_epa4331(sih
, FALSE
);
2514 /* read the sprom */
2515 for (i
= 0; i
< nwords
; i
++) {
2517 if (sih
->ccrev
> 31 && ISSIM_ENAB(sih
)) {
2518 /* use indirect since direct is too slow on QT */
2519 if ((sih
->cccaps
& CC_CAP_SROM
) == 0) {
2524 ccregs
= (void *)((uint8
*)sprom
- CC_SROM_OTP
);
2525 buf
[i
] = srom_cc_cmd(sih
, osh
, ccregs
, SRC_OP_READ
, wordoff
+ i
, 0);
2528 if (ISSIM_ENAB(sih
))
2529 buf
[i
] = R_REG(osh
, &sprom
[wordoff
+ i
]);
2531 buf
[i
] = R_REG(osh
, &sprom
[wordoff
+ i
]);
2536 /* bypass crc checking for simulation to allow srom hack */
2537 if (ISSIM_ENAB(sih
))
2542 if (buf
[0] == 0xffff) {
2543 /* The hardware thinks that an srom that starts with 0xffff
2544 * is blank, regardless of the rest of the content, so declare
2547 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__
, buf
[0]));
2552 /* fixup the endianness so crc8 will pass */
2553 htol16_buf(buf
, nwords
* 2);
2554 if (hndcrc8((uint8
*)buf
, nwords
* 2, CRC8_INIT_VALUE
) != CRC8_GOOD_VALUE
) {
2555 /* DBG only pci always read srom4 first, then srom8/9 */
2556 /* BS_ERROR(("%s: bad crc\n", __FUNCTION__)); */
2559 /* now correct the endianness of the byte array */
2560 ltoh16_buf(buf
, nwords
* 2);
2564 if ((CHIPID(sih
->chip
) == BCM4331_CHIP_ID
) ||
2565 (CHIPID(sih
->chip
) == BCM43431_CHIP_ID
)) {
2566 /* Restore config after reading SROM */
2567 si_chipcontrl_epa4331_restore(sih
, ccval
);
2573 #if defined(BCMNVRAMW) || defined(BCMNVRAMR)
2575 otp_read_pci(osl_t
*osh
, si_t
*sih
, uint16
*buf
, uint bufsz
)
2578 uint sz
= OTP_SZ_MAX
/2; /* size in words */
2581 ASSERT(bufsz
<= OTP_SZ_MAX
);
2583 if ((otp
= MALLOC(osh
, OTP_SZ_MAX
)) == NULL
) {
2587 bzero(otp
, OTP_SZ_MAX
);
2589 err
= otp_read_region(sih
, OTP_HW_RGN
, (uint16
*)otp
, &sz
);
2591 bcopy(otp
, buf
, bufsz
);
2594 MFREE(osh
, otp
, OTP_SZ_MAX
);
2597 if (buf
[0] == 0xffff) {
2598 /* The hardware thinks that an srom that starts with 0xffff
2599 * is blank, regardless of the rest of the content, so declare
2602 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__
, buf
[0]));
2606 /* fixup the endianness so crc8 will pass */
2607 htol16_buf(buf
, bufsz
);
2608 if (hndcrc8((uint8
*)buf
, SROM4_WORDS
* 2, CRC8_INIT_VALUE
) != CRC8_GOOD_VALUE
) {
2609 BS_ERROR(("%s: bad crc\n", __FUNCTION__
));
2612 /* now correct the endianness of the byte array */
2613 ltoh16_buf(buf
, bufsz
);
2617 #endif /* defined(BCMNVRAMW) || defined(BCMNVRAMR) */
2619 #if defined(WLTEST) || defined(BCMDBG)
2621 srom_otp_write_region_crc(si_t
*sih
, uint nbytes
, uint16
* buf16
, bool write
)
2623 int err
= 0, crc
= 0;
2626 /* Check nbytes is not odd or too big */
2627 if ((nbytes
& 1) || (nbytes
> SROM_MAX
))
2630 /* block invalid buffer size */
2631 if (nbytes
< SROM4_WORDS
* 2)
2632 return BCME_BUFTOOSHORT
;
2633 else if (nbytes
> SROM4_WORDS
* 2)
2634 return BCME_BUFTOOLONG
;
2636 /* Verify signatures */
2637 if (!((buf16
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
2638 (buf16
[SROM8_SIGN
] == SROM4_SIGNATURE
))) {
2639 BS_ERROR(("%s: wrong signature SROM4_SIGN %x SROM8_SIGN %x\n",
2640 __FUNCTION__
, buf16
[SROM4_SIGN
], buf16
[SROM8_SIGN
]));
2645 if (buf16
[0] == 0xffff) {
2646 /* The hardware thinks that an srom that starts with 0xffff
2647 * is blank, regardless of the rest of the content, so declare
2650 BS_ERROR(("%s: invalid buf16[0] = 0x%x\n", __FUNCTION__
, buf16
[0]));
2654 buf8
= (uint8
*)buf16
;
2655 /* fixup the endianness and then calculate crc */
2656 htol16_buf(buf8
, nbytes
);
2657 crc
= ~hndcrc8(buf8
, nbytes
- 1, CRC8_INIT_VALUE
);
2658 /* now correct the endianness of the byte array */
2659 ltoh16_buf(buf8
, nbytes
);
2660 buf16
[SROM4_CRCREV
] = (crc
<< 8) | (buf16
[SROM4_CRCREV
] & 0xff);
2663 /* Write the CRC back */
2665 err
= otp_cis_append_region(sih
, OTP_HW_RGN
, (char*)buf8
, (int)nbytes
);
2666 #endif /* BCMNVRAMW */
2669 return write
? err
: crc
;
2674 * Create variable table from memory.
2675 * Return 0 on success, nonzero on error.
2678 BCMATTACHFN(initvars_table
)(osl_t
*osh
, char *start
, char *end
, char **vars
, uint
*count
)
2680 int c
= (int)(end
- start
);
2682 /* do it only when there is more than just the null string */
2684 char *vp
= MALLOC(osh
, c
);
2688 bcopy(start
, vp
, c
);
2701 * Find variables with <devpath> from flash. 'base' points to the beginning
2702 * of the table upon enter and to the end of the table upon exit when success.
2703 * Return 0 on success, nonzero on error.
2706 BCMATTACHFN(initvars_flash
)(si_t
*sih
, osl_t
*osh
, char **base
, uint len
)
2712 uint l
, dl
, copy_len
;
2713 char devpath
[SI_DEVPATH_BUFSZ
];
2714 char coded_name
[SI_DEVPATH_BUFSZ
] = {0};
2715 int path_len
, coded_len
, devid_len
;
2717 /* allocate memory and read in flash */
2718 if (!(flash
= MALLOC(osh
, NVRAM_SPACE
)))
2720 if ((err
= nvram_getall(flash
, NVRAM_SPACE
)))
2723 /* create legacy devpath prefix */
2724 si_devpath(sih
, devpath
, sizeof(devpath
));
2725 path_len
= strlen(devpath
);
2727 /* create coded devpath prefix */
2728 si_coded_devpathvar(sih
, coded_name
, sizeof(coded_name
), "devid");
2730 /* coded_name now is 'xx:devid, eat ending 'devid' */
2732 devid_len
= strlen("devid");
2733 coded_len
= strlen(coded_name
);
2734 if (coded_len
> devid_len
) {
2735 coded_name
[coded_len
- devid_len
] = '\0';
2736 coded_len
-= devid_len
;
2741 /* grab vars with the <devpath> prefix or <coded_name> previx in name */
2742 for (s
= flash
; s
&& *s
; s
+= l
+ 1) {
2745 /* skip non-matching variable */
2746 if (strncmp(s
, devpath
, path_len
) == 0)
2748 else if (coded_len
&& strncmp(s
, coded_name
, coded_len
) == 0)
2753 /* is there enough room to copy? */
2754 copy_len
= l
- dl
+ 1;
2755 if (len
< copy_len
) {
2756 err
= BCME_BUFTOOSHORT
;
2760 /* no prefix, just the name=value */
2761 strncpy(vp
, &s
[dl
], copy_len
);
2766 /* add null string as terminator */
2768 err
= BCME_BUFTOOSHORT
;
2775 exit
: MFREE(osh
, flash
, NVRAM_SPACE
);
2779 #if !defined(BCMUSBDEV)
2781 * Initialize nonvolatile variable table from flash.
2782 * Return 0 on success, nonzero on error.
2785 BCMATTACHFN(initvars_flash_si
)(si_t
*sih
, char **vars
, uint
*count
)
2787 osl_t
*osh
= si_osh(sih
);
2791 ASSERT(vars
!= NULL
);
2792 ASSERT(count
!= NULL
);
2794 base
= vp
= MALLOC(osh
, MAXSZ_NVRAM_VARS
);
2799 if ((err
= initvars_flash(sih
, osh
, &vp
, MAXSZ_NVRAM_VARS
)) == 0)
2800 err
= initvars_table(osh
, base
, vp
, vars
, count
);
2802 MFREE(osh
, base
, MAXSZ_NVRAM_VARS
);
2808 /* Parse SROM and create name=value pairs. 'srom' points to
2809 * the SROM word array. 'off' specifies the offset of the
2810 * first word 'srom' points to, which should be either 0 or
2811 * SROM3_SWRG_OFF (full SROM or software region).
2815 mask_shift(uint16 mask
)
2818 for (i
= 0; i
< (sizeof(mask
) << 3); i
++) {
2819 if (mask
& (1 << i
))
2827 mask_width(uint16 mask
)
2830 for (i
= (sizeof(mask
) << 3) - 1; i
>= 0; i
--) {
2831 if (mask
& (1 << i
))
2832 return (uint
)(i
- mask_shift(mask
) + 1);
2838 #ifdef BCMASSERT_SUPPORT
2840 mask_valid(uint16 mask
)
2842 uint shift
= mask_shift(mask
);
2843 uint width
= mask_width(mask
);
2844 return mask
== ((~0 << shift
) & ~(~0 << (shift
+ width
)));
2849 BCMATTACHFN(_initvars_srom_pci
)(uint8 sromrev
, uint16
*srom
, uint off
, varbuf_t
*b
)
2853 const sromvar_t
*srv
;
2856 uint32 sr
= (1 << sromrev
);
2858 varbuf_append(b
, "sromrev=%d", sromrev
);
2860 for (srv
= pci_sromvars
; srv
->name
!= NULL
; srv
++) {
2863 if ((srv
->revmask
& sr
) == 0)
2872 /* This entry is for mfgc only. Don't generate param for it, */
2873 if (flags
& SRFL_NOVAR
)
2876 if (flags
& SRFL_ETHADDR
) {
2877 char eabuf
[ETHER_ADDR_STR_LEN
];
2878 struct ether_addr ea
;
2880 ea
.octet
[0] = (srom
[srv
->off
- off
] >> 8) & 0xff;
2881 ea
.octet
[1] = srom
[srv
->off
- off
] & 0xff;
2882 ea
.octet
[2] = (srom
[srv
->off
+ 1 - off
] >> 8) & 0xff;
2883 ea
.octet
[3] = srom
[srv
->off
+ 1 - off
] & 0xff;
2884 ea
.octet
[4] = (srom
[srv
->off
+ 2 - off
] >> 8) & 0xff;
2885 ea
.octet
[5] = srom
[srv
->off
+ 2 - off
] & 0xff;
2886 bcm_ether_ntoa(&ea
, eabuf
);
2888 varbuf_append(b
, "%s=%s", name
, eabuf
);
2891 ASSERT(mask_valid(srv
->mask
));
2892 ASSERT(mask_width(srv
->mask
));
2894 w
= srom
[srv
->off
- off
];
2895 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
2896 width
= mask_width(srv
->mask
);
2898 while (srv
->flags
& SRFL_MORE
) {
2900 ASSERT(srv
->name
!= NULL
);
2902 if (srv
->off
== 0 || srv
->off
< off
)
2905 ASSERT(mask_valid(srv
->mask
));
2906 ASSERT(mask_width(srv
->mask
));
2908 w
= srom
[srv
->off
- off
];
2909 val
+= ((w
& srv
->mask
) >> mask_shift(srv
->mask
)) << width
;
2910 width
+= mask_width(srv
->mask
);
2913 if ((flags
& SRFL_NOFFS
) && ((int)val
== (1 << width
) - 1))
2916 if (flags
& SRFL_CCODE
) {
2918 varbuf_append(b
, "ccode=");
2920 varbuf_append(b
, "ccode=%c%c", (val
>> 8), (val
& 0xff));
2922 /* LED Powersave duty cycle has to be scaled:
2923 *(oncount >> 24) (offcount >> 8)
2925 else if (flags
& SRFL_LEDDC
) {
2926 uint32 w32
= (((val
>> 8) & 0xff) << 24) | /* oncount */
2927 (((val
& 0xff)) << 8); /* offcount */
2928 varbuf_append(b
, "leddc=%d", w32
);
2930 else if (flags
& SRFL_PRHEX
)
2931 varbuf_append(b
, "%s=0x%x", name
, val
);
2932 else if ((flags
& SRFL_PRSIGN
) && (val
& (1 << (width
- 1))))
2933 varbuf_append(b
, "%s=%d", name
, (int)(val
| (~0 << width
)));
2935 varbuf_append(b
, "%s=%u", name
, val
);
2940 /* Do per-path variables */
2945 psz
= SROM8_PATH1
- SROM8_PATH0
;
2948 psz
= SROM4_PATH1
- SROM4_PATH0
;
2951 for (p
= 0; p
< MAX_PATH_SROM
; p
++) {
2952 for (srv
= perpath_pci_sromvars
; srv
->name
!= NULL
; srv
++) {
2953 if ((srv
->revmask
& sr
) == 0)
2956 if (pb
+ srv
->off
< off
)
2959 /* This entry is for mfgc only. Don't generate param for it, */
2960 if (srv
->flags
& SRFL_NOVAR
)
2963 w
= srom
[pb
+ srv
->off
- off
];
2965 ASSERT(mask_valid(srv
->mask
));
2966 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
2967 width
= mask_width(srv
->mask
);
2969 /* Cheating: no per-path var is more than 1 word */
2971 if ((srv
->flags
& SRFL_NOFFS
) && ((int)val
== (1 << width
) - 1))
2974 if (srv
->flags
& SRFL_PRHEX
)
2975 varbuf_append(b
, "%s%d=0x%x", srv
->name
, p
, val
);
2977 varbuf_append(b
, "%s%d=%d", srv
->name
, p
, val
);
2985 * Initialize nonvolatile variable table from sprom.
2986 * Return 0 on success, nonzero on error.
2989 BCMATTACHFN(initvars_srom_pci
)(si_t
*sih
, void *curmap
, char **vars
, uint
*count
)
2991 uint16
*srom
, *sromwindow
;
2995 char *vp
, *base
= NULL
;
2996 osl_t
*osh
= si_osh(sih
);
3001 * Apply CRC over SROM content regardless SROM is present or not,
3002 * and use variable <devpath>sromrev's existance in flash to decide
3003 * if we should return an error when CRC fails or read SROM variables
3006 srom
= MALLOC(osh
, SROM_MAX
);
3007 ASSERT(srom
!= NULL
);
3011 sromwindow
= (uint16
*)SROM_OFFSET(sih
);
3012 if (si_is_sprom_available(sih
)) {
3013 err
= sprom_read_pci(osh
, sih
, sromwindow
, 0, srom
, SROM_WORDS
, TRUE
);
3015 if ((srom
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
3016 (((sih
->buscoretype
== PCIE_CORE_ID
) && (sih
->buscorerev
>= 6)) ||
3017 ((sih
->buscoretype
== PCI_CORE_ID
) && (sih
->buscorerev
>= 0xe)))) {
3018 /* sromrev >= 4, read more */
3019 err
= sprom_read_pci(osh
, sih
, sromwindow
, 0, srom
, SROM4_WORDS
, TRUE
);
3020 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
3022 BS_ERROR(("%s: srom %d, bad crc\n", __FUNCTION__
, sromrev
));
3024 } else if (err
== 0) {
3025 /* srom is good and is rev < 4 */
3026 /* top word of sprom contains version and crc8 */
3027 sromrev
= srom
[SROM_CRCREV
] & 0xff;
3028 /* bcm4401 sroms misprogrammed */
3029 if (sromrev
== 0x10)
3034 #if defined(BCMNVRAMW) || defined(BCMNVRAMR)
3035 /* Use OTP if SPROM not available */
3036 else if ((err
= otp_read_pci(osh
, sih
, srom
, SROM_MAX
)) == 0) {
3037 /* OTP only contain SROM rev8/rev9 for now */
3038 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
3040 #endif /* defined(BCMNVRAMW) || defined(BCMNVRAMR) */
3043 BS_ERROR(("Neither SPROM nor OTP has valid image\n"));
3047 /* We want internal/wltest driver to come up with default sromvars so we can
3048 * program a blank SPROM/OTP.
3055 if ((value
= si_getdevpathvar(sih
, "sromrev"))) {
3056 sromrev
= (uint8
)bcm_strtoul(value
, NULL
, 0);
3061 BS_ERROR(("%s, SROM CRC Error\n", __FUNCTION__
));
3064 if ((value
= si_getnvramflvar(sih
, "sromrev"))) {
3069 /* BCMHOSTVARS is enabled only if WLTEST is enabled or BCMEXTNVM is enabled */
3070 #if defined(BCMHOSTVARS)
3071 val
= OSL_PCI_READ_CONFIG(osh
, PCI_SPROM_CONTROL
, sizeof(uint32
));
3072 if ((si_is_sprom_available(sih
) && srom
[0] == 0xffff) ||
3073 (val
& SPROM_OTPIN_USE
)) {
3074 vp
= base
= mfgsromvars
;
3076 if (defvarslen
== 0) {
3077 BS_ERROR(("No nvm file, use generic default (for programming"
3078 " SPROM/OTP only)\n"));
3080 if (((sih
->chip
== BCM4331_CHIP_ID
) ||
3081 (sih
->chip
== BCM43431_CHIP_ID
)) &&
3082 (sih
->chiprev
< 3)) {
3084 defvarslen
= srom_vars_len(defaultsromvars_4331
);
3085 bcopy(defaultsromvars_4331
, vp
, defvarslen
);
3088 /* For 4311 A1 there is no signature to indicate that OTP is
3089 * programmed, so can't really verify the OTP is
3090 * unprogrammed or a bad OTP.
3092 if (sih
->chip
== BCM4311_CHIP_ID
) {
3093 const char *devid
= "devid=0x4311";
3094 const size_t devid_strlen
= strlen(devid
);
3095 BS_ERROR(("setting the devid to be 4311\n"));
3096 bcopy(devid
, vp
, devid_strlen
+ 1);
3097 vp
+= devid_strlen
+ 1;
3099 defvarslen
= srom_vars_len(defaultsromvars_wltest
);
3100 bcopy(defaultsromvars_wltest
, vp
, defvarslen
);
3103 BS_ERROR(("Use nvm file as default\n"));
3107 /* add final null terminator */
3110 BS_ERROR(("Used %d bytes of defaultsromvars\n", defvarslen
));
3113 } else if (((sih
->chip
== BCM4331_CHIP_ID
) ||
3114 (sih
->chip
== BCM43431_CHIP_ID
)) &&
3115 (sih
->chiprev
< 3)) {
3116 base
= vp
= mfgsromvars
;
3118 BS_ERROR(("4331 BOOT w/o SPROM or OTP\n"));
3120 defvarslen
= srom_vars_len(defaultsromvars_4331
);
3121 bcopy(defaultsromvars_4331
, vp
, defvarslen
);
3134 /* Bitmask for the sromrev */
3137 /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, SROM_MAXREV */
3138 if ((sr
& 0x33e) == 0) {
3143 ASSERT(vars
!= NULL
);
3144 ASSERT(count
!= NULL
);
3146 base
= vp
= MALLOC(osh
, MAXSZ_NVRAM_VARS
);
3153 /* read variables from flash */
3155 if ((err
= initvars_flash(sih
, osh
, &vp
, MAXSZ_NVRAM_VARS
)))
3160 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
3162 /* parse SROM into name=value pairs. */
3163 _initvars_srom_pci(sromrev
, srom
, 0, &b
);
3166 /* final nullbyte terminator */
3167 ASSERT(b
.size
>= 1);
3171 ASSERT((vp
- base
) <= MAXSZ_NVRAM_VARS
);
3174 err
= initvars_table(osh
, base
, vp
, vars
, count
);
3177 /* BCMHOSTVARS are enabled only if WLTEST is enabled or BCMEXTNVM is enabled */
3178 #if defined(BCMHOSTVARS)
3179 if (base
&& (base
!= mfgsromvars
))
3183 MFREE(osh
, base
, MAXSZ_NVRAM_VARS
);
3185 MFREE(osh
, srom
, SROM_MAX
);
3190 * Read the cis and call parsecis to initialize the vars.
3191 * Return 0 on success, nonzero on error.
3194 BCMATTACHFN(initvars_cis_pcmcia
)(si_t
*sih
, osl_t
*osh
, char **vars
, uint
*count
)
3200 data_sz
= (sih
->buscorerev
== 1) ? SROM_MAX
: CIS_SIZE
;
3202 if ((cis
= MALLOC(osh
, data_sz
)) == NULL
)
3205 if (sih
->buscorerev
== 1) {
3206 if (srom_read(sih
, PCMCIA_BUS
, (void *)NULL
, osh
, 0, data_sz
, (uint16
*)cis
,
3208 MFREE(osh
, cis
, data_sz
);
3211 /* fix up endianess for 16-bit data vs 8-bit parsing */
3212 htol16_buf((uint16
*)cis
, data_sz
);
3214 OSL_PCMCIA_READ_ATTR(osh
, 0, cis
, data_sz
);
3216 rc
= srom_parsecis(osh
, &cis
, SROM_CIS_SINGLE
, vars
, count
);
3218 MFREE(osh
, cis
, data_sz
);
3226 * Read the SPI cis and call parsecis to initialize the vars.
3227 * Return 0 on success, nonzero on error.
3230 BCMATTACHFN(initvars_cis_spi
)(osl_t
*osh
, char **vars
, uint
*count
)
3235 #if defined(NDIS) && !defined(UNDER_CE)
3236 uint8 cisd
[SBSDIO_CIS_SIZE_LIMIT
];
3239 if ((cis
= MALLOC(osh
, SBSDIO_CIS_SIZE_LIMIT
)) == NULL
) {
3242 #endif /* defined(NDIS) && (!defined(UNDER_CE)) */
3244 bzero(cis
, SBSDIO_CIS_SIZE_LIMIT
);
3246 if (bcmsdh_cis_read(NULL
, SDIO_FUNC_1
, cis
, SBSDIO_CIS_SIZE_LIMIT
) != 0) {
3247 #if defined(NDIS) && !defined(UNDER_CE)
3250 MFREE(osh
, cis
, SBSDIO_CIS_SIZE_LIMIT
);
3251 #endif /* defined(NDIS) && (!defined(UNDER_CE)) */
3255 rc
= srom_parsecis(osh
, &cis
, SDIO_FUNC_1
, vars
, count
);
3257 #if defined(NDIS) && !defined(UNDER_CE)
3258 /* nothing to do here */
3260 MFREE(osh
, cis
, SBSDIO_CIS_SIZE_LIMIT
);
3267 #if defined(BCMUSBDEV)
3268 /* Return sprom size in 16-bit words */
3270 srom_size(si_t
*sih
, osl_t
*osh
)
3273 if (SPROMBUS
== PCMCIA_BUS
) {
3275 sdpcmd_regs_t
*pcmregs
;
3278 origidx
= si_coreidx(sih
);
3279 pcmregs
= si_setcore(sih
, PCMCIA_CORE_ID
, 0);
3281 pcmregs
= si_setcore(sih
, SDIOD_CORE_ID
, 0);
3284 if (!(wasup
= si_iscoreup(sih
)))
3285 si_core_reset(sih
, 0, 0);
3287 /* not worry about earlier core revs */
3288 /* valid for only pcmcia core */
3289 if (si_coreid(sih
) == PCMCIA_CORE_ID
)
3290 if (si_corerev(sih
) < 8)
3294 switch (SI_PCMCIA_READ(osh
, pcmregs
, SROM_INFO
) & SRI_SZ_MASK
) {
3296 size
= 256; /* SROM_INFO == 1 means 4kbit */
3299 size
= 1024; /* SROM_INFO == 2 means 16kbit */
3307 si_core_disable(sih
, 0);
3309 si_setcoreidx(sih
, origidx
);
3316 * initvars are different for BCMUSBDEV and BCMSDIODEV. This is OK when supporting both at
3317 * the same time, but only because all of the code is in attach functions and not in ROM.
3320 #if defined(BCMUSBDEV)
3321 #if defined(BCMUSBDEV_BMAC) || defined(BCM_BMAC_VARS_APPEND)
3323 * Read the USB cis and call parsecis to initialize the vars.
3324 * Return 0 on success, nonzero on error.
3327 BCMATTACHFN(initvars_cis_usbdriver
)(si_t
*sih
, osl_t
*osh
, char **vars
, uint
*count
)
3330 uint sz
= OTP_SZ_MAX
/2; /* size in words */
3333 if ((cis
= MALLOC(osh
, OTP_SZ_MAX
)) == NULL
) {
3337 bzero(cis
, OTP_SZ_MAX
);
3339 if (otp_read_region(sih
, OTP_SW_RGN
, (uint16
*)cis
, &sz
)) {
3340 BS_ERROR(("%s: OTP read SW region failure.\n*", __FUNCTION__
));
3343 BS_ERROR(("%s: OTP programmed. use OTP for srom vars\n*", __FUNCTION__
));
3344 rc
= srom_parsecis(osh
, &cis
, SROM_CIS_SINGLE
, vars
, count
);
3347 MFREE(osh
, cis
, OTP_SZ_MAX
);
3352 /* For driver(not bootloader), if nvram is not downloadable or missing, use default */
3354 BCMATTACHFN(initvars_srom_si_usbdriver
)(si_t
*sih
, osl_t
*osh
, char **vars
, uint
*varsz
)
3360 static bool srvars
= FALSE
; /* Use OTP/SROM as global variables */
3362 base
= fakevars
= NULL
;
3364 switch (CHIPID(sih
->chip
)) {
3365 case BCM4322_CHIP_ID
: case BCM43221_CHIP_ID
: case BCM43231_CHIP_ID
:
3366 fakevars
= defaultsromvars_4322usb
;
3368 case BCM43236_CHIP_ID
: case BCM43235_CHIP_ID
: case BCM43238_CHIP_ID
:
3369 case BCM43234_CHIP_ID
:
3370 /* check against real chipid instead of compile time flag */
3371 if (sih
->chip
== BCM43234_CHIP_ID
) {
3372 fakevars
= defaultsromvars_43234usb
;
3373 } else if (sih
->chip
== BCM43235_CHIP_ID
) {
3374 fakevars
= defaultsromvars_43235usb
;
3376 fakevars
= defaultsromvars_43236usb
;
3379 case BCM4319_CHIP_ID
:
3380 fakevars
= defaultsromvars_4319usb
;
3387 #ifndef BCM_BMAC_VARS_APPEND
3388 if (BCME_OK
== initvars_cis_usbdriver(sih
, osh
, vars
, varsz
)) {
3389 /* Make OTP/SROM variables global */
3390 if (srvars
== FALSE
)
3391 nvram_append((void *)sih
, *vars
, *varsz
);
3394 #endif /* BCM_BMAC_VARS_APPEND */
3396 /* NO OTP, if nvram downloaded, use it */
3397 if ((_varsz
!= 0) && (_vars
!= NULL
)) {
3398 len
= _varsz
+ (strlen(vstr_end
));
3399 base
= MALLOC(osh
, len
+ 2); /* plus 2 terminating \0 */
3401 BS_ERROR(("initvars_srom_si: MALLOC failed.\n"));
3404 bzero(base
, len
+ 2);
3406 /* make a copy of the _vars, _vars is at the top of the memory, cannot append
3407 * END\0\0 to it. copy the download vars to base, back of the terminating \0,
3408 * then append END\0\0
3410 bcopy((void *)_vars
, base
, _varsz
);
3411 /* backoff all the terminating \0s except the one the for the last string */
3413 while (!base
[len
- 1])
3415 len
++; /* \0 for the last string */
3416 /* append END\0\0 to the end */
3417 bcopy((void *)vstr_end
, (base
+ len
), strlen(vstr_end
));
3418 len
+= (strlen(vstr_end
) + 2);
3422 BS_ERROR(("%s USB nvram downloaded %d bytes\n", __FUNCTION__
, _varsz
));
3424 /* Fall back to fake srom vars if OTP not programmed */
3425 len
= srom_vars_len(fakevars
);
3426 base
= MALLOC(osh
, (len
+ 1));
3428 BS_ERROR(("initvars_srom_si: MALLOC failed.\n"));
3431 bzero(base
, (len
+ 1));
3432 bcopy(fakevars
, base
, len
);
3433 *(base
+ len
) = '\0'; /* add final nullbyte terminator */
3436 BS_ERROR(("initvars_srom_usbdriver: faked nvram %d bytes\n", len
));
3439 #ifdef BCM_BMAC_VARS_APPEND
3440 if (BCME_OK
== initvars_cis_usbdriver(sih
, osh
, vars
, varsz
)) {
3442 MFREE(osh
, base
, (len
+ 1));
3444 #endif /* BCM_BMAC_VARS_APPEND */
3445 /* Make OTP/SROM variables global */
3446 if (srvars
== FALSE
) {
3447 nvram_append((void *)sih
, *vars
, *varsz
);
3453 #endif /* BCMUSBDEV_BMAC || BCM_BMAC_VARS_APPEND */
3455 #ifdef BCM_DONGLEVARS
3457 BCMATTACHFN(initvars_srom_si_bl
)(si_t
*sih
, osl_t
*osh
, void *curmap
, char **vars
, uint
*varsz
)
3459 int sel
= 0; /* where to read srom/cis: 0 - none, 1 - otp, 2 - sprom */
3460 uint sz
= 0; /* srom size in bytes */
3464 if ((oh
= otp_init(sih
)) != NULL
&& (otp_status(oh
) & OTPS_GUP_SW
)) {
3465 /* Access OTP if it is present, powered on, and programmed */
3468 } else if ((sz
= srom_size(sih
, osh
)) != 0) {
3469 /* Access the SPROM if it is present */
3474 /* Read CIS in OTP/SPROM */
3482 /* Allocate memory */
3483 if ((srom
= (uint16
*)MALLOC(osh
, sz
)) == NULL
)
3489 rc
= otp_read_region(sih
, OTP_SW_RGN
, srom
, &otpsz
);
3491 body
= (uint8
*)srom
;
3494 rc
= srom_read(sih
, SI_BUS
, curmap
, osh
, 0, sz
, srom
, TRUE
);
3495 /* sprom has 8 byte h/w header */
3496 body
= (uint8
*)srom
+ SBSDIO_SPROM_CIS_OFFSET
;
3499 /* impossible to come here */
3505 if (rc
== BCME_OK
) {
3506 /* each word is in host endian */
3507 htol16_buf((uint8
*)srom
, sz
);
3509 rc
= srom_parsecis(osh
, &body
, SROM_CIS_SINGLE
, vars
, varsz
);
3512 MFREE(osh
, srom
, sz
); /* Clean up */
3514 /* Make SROM variables global */
3516 nvram_append((void *)sih
, *vars
, *varsz
);
3521 #endif /* #ifdef BCM_DONGLEVARS */
3524 BCMATTACHFN(initvars_srom_si
)(si_t
*sih
, osl_t
*osh
, void *curmap
, char **vars
, uint
*varsz
)
3526 static bool srvars
= FALSE
; /* Use OTP/SPROM as global variables */
3528 /* Bail out if we've dealt with OTP/SPROM before! */
3532 #if defined(BCMUSBDEV_BMAC) || defined(BCM_BMAC_VARS_APPEND)
3533 /* read OTP or use faked var array */
3534 switch (CHIPID(sih
->chip
)) {
3535 case BCM4322_CHIP_ID
: case BCM43221_CHIP_ID
: case BCM43231_CHIP_ID
:
3536 case BCM43236_CHIP_ID
: case BCM43235_CHIP_ID
: case BCM43238_CHIP_ID
:
3537 case BCM43234_CHIP_ID
:
3538 case BCM4319_CHIP_ID
:
3539 if (BCME_OK
!= initvars_srom_si_usbdriver(sih
, osh
, vars
, varsz
))
3543 UNUSED_PARAMETER(defaultsromvars_4322usb
);
3544 UNUSED_PARAMETER(defaultsromvars_43234usb
);
3545 UNUSED_PARAMETER(defaultsromvars_43235usb
);
3546 UNUSED_PARAMETER(defaultsromvars_43236usb
);
3547 UNUSED_PARAMETER(defaultsromvars_4319usb
);
3549 #endif /* BCMUSBDEV_BMAC || BCM_BMAC_VARS_APPEND */
3551 #ifdef BCM_DONGLEVARS /* this flag should be defined for usb bootloader, to read \
3553 if (BCME_OK
!= initvars_srom_si_bl(sih
, osh
, curmap
, vars
, varsz
))
3557 /* update static local var to skip for next call */
3561 /* Tell the caller there is no individual SROM variables */
3565 /* return OK so the driver will load & use defaults if bad srom/otp */
3569 #else /* !BCMUSBDEV && !BCMSDIODEV */
3572 BCMATTACHFN(initvars_srom_si
)(si_t
*sih
, osl_t
*osh
, void *curmap
, char **vars
, uint
*varsz
)
3574 /* Search flash nvram section for srom variables */
3575 return initvars_flash_si(sih
, vars
, varsz
);