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>
35 #define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
36 (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
37 ((u8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
38 ((u8 *)curmap + PCI_BAR0_SPROM_OFFSET))
41 #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
42 #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
45 typedef struct varbuf
{
46 char *base
; /* pointer to buffer base */
47 char *buf
; /* pointer to current position */
48 unsigned int size
; /* current (residual) size in bytes */
53 static int initvars_srom_si(si_t
*sih
, void *curmap
, char **vars
, uint
*count
);
54 static void _initvars_srom_pci(u8 sromrev
, u16
*srom
, uint off
, varbuf_t
*b
);
55 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
, uint
*count
);
56 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
);
57 static int sprom_read_pci(si_t
*sih
, u16
*sprom
,
58 uint wordoff
, u16
*buf
, uint nwords
, bool check_crc
);
59 #if defined(BCMNVRAMR)
60 static int otp_read_pci(si_t
*sih
, u16
*buf
, uint bufsz
);
62 static u16
srom_cc_cmd(si_t
*sih
, void *ccregs
, u32 cmd
,
63 uint wordoff
, u16 data
);
65 static int initvars_table(char *start
, char *end
,
66 char **vars
, uint
*count
);
67 static int initvars_flash(si_t
*sih
, char **vp
,
70 /* Initialization of varbuf structure */
71 static void varbuf_init(varbuf_t
*b
, char *buf
, uint size
)
74 b
->base
= b
->buf
= buf
;
77 /* append a null terminated var=value string */
78 static int varbuf_append(varbuf_t
*b
, const char *fmt
, ...)
89 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
92 /* C99 snprintf behavior returns r >= size on overflow,
93 * others return -1 on overflow.
94 * All return -1 on format error.
95 * We need to leave room for 2 null terminations, one for the current var
96 * string, and one for final null of the var table. So check that the
97 * strlen written, r, leaves room for 2 chars.
99 if ((r
== -1) || (r
> (int)(b
->size
- 2))) {
104 /* Remove any earlier occurrence of the same variable */
105 s
= strchr(b
->buf
, '=');
107 len
= (size_t) (s
- b
->buf
);
108 for (s
= b
->base
; s
< b
->buf
;) {
109 if ((memcmp(s
, b
->buf
, len
) == 0) && s
[len
] == '=') {
111 memmove(s
, (s
+ len
),
112 ((b
->buf
+ r
+ 1) - (s
+ len
)));
114 b
->size
+= (unsigned int)len
;
123 /* skip over this string's null termination */
132 * Initialize local vars from the right source for this platform.
133 * Return 0 on success, nonzero on error.
135 int srom_var_init(si_t
*sih
, uint bustype
, void *curmap
,
136 char **vars
, uint
*count
)
142 ASSERT(bustype
== bustype
);
143 if (vars
== NULL
|| count
== NULL
)
152 return initvars_srom_si(sih
, curmap
, vars
, count
);
155 ASSERT(curmap
!= NULL
);
159 return initvars_srom_pci(sih
, curmap
, vars
, count
);
167 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
168 * not in the bus cores.
171 srom_cc_cmd(si_t
*sih
, void *ccregs
, u32 cmd
,
172 uint wordoff
, u16 data
)
174 chipcregs_t
*cc
= (chipcregs_t
*) ccregs
;
175 uint wait_cnt
= 1000;
177 if ((cmd
== SRC_OP_READ
) || (cmd
== SRC_OP_WRITE
)) {
178 W_REG(&cc
->sromaddress
, wordoff
* 2);
179 if (cmd
== SRC_OP_WRITE
)
180 W_REG(&cc
->sromdata
, data
);
183 W_REG(&cc
->sromcontrol
, SRC_START
| cmd
);
186 if ((R_REG(&cc
->sromcontrol
) & SRC_BUSY
) == 0)
193 if (cmd
== SRC_OP_READ
)
194 return (u16
) R_REG(&cc
->sromdata
);
199 static inline void ltoh16_buf(u16
*buf
, unsigned int size
)
201 for (size
/= 2; size
; size
--)
202 *(buf
+ size
) = le16_to_cpu(*(buf
+ size
));
205 static inline void htol16_buf(u16
*buf
, unsigned int size
)
207 for (size
/= 2; size
; size
--)
208 *(buf
+ size
) = cpu_to_le16(*(buf
+ size
));
212 * Read in and validate sprom.
213 * Return 0 on success, nonzero on error.
216 sprom_read_pci(si_t
*sih
, u16
*sprom
, uint wordoff
,
217 u16
*buf
, uint nwords
, bool check_crc
)
224 for (i
= 0; i
< nwords
; i
++) {
226 if (sih
->ccrev
> 31 && ISSIM_ENAB(sih
)) {
227 /* use indirect since direct is too slow on QT */
228 if ((sih
->cccaps
& CC_CAP_SROM
) == 0)
231 ccregs
= (void *)((u8
*) sprom
- CC_SROM_OTP
);
233 srom_cc_cmd(sih
, ccregs
, SRC_OP_READ
,
238 buf
[i
] = R_REG(&sprom
[wordoff
+ i
]);
240 buf
[i
] = R_REG(&sprom
[wordoff
+ i
]);
245 /* bypass crc checking for simulation to allow srom hack */
251 if (buf
[0] == 0xffff) {
252 /* The hardware thinks that an srom that starts with 0xffff
253 * is blank, regardless of the rest of the content, so declare
259 /* fixup the endianness so crc8 will pass */
260 htol16_buf(buf
, nwords
* 2);
261 if (hndcrc8((u8
*) buf
, nwords
* 2, CRC8_INIT_VALUE
) !=
263 /* DBG only pci always read srom4 first, then srom8/9 */
266 /* now correct the endianness of the byte array */
267 ltoh16_buf(buf
, nwords
* 2);
272 #if defined(BCMNVRAMR)
273 static int otp_read_pci(si_t
*sih
, u16
*buf
, uint bufsz
)
276 uint sz
= OTP_SZ_MAX
/ 2; /* size in words */
279 ASSERT(bufsz
<= OTP_SZ_MAX
);
281 otp
= kzalloc(OTP_SZ_MAX
, GFP_ATOMIC
);
286 err
= otp_read_region(sih
, OTP_HW_RGN
, (u16
*) otp
, &sz
);
288 memcpy(buf
, otp
, bufsz
);
293 if (buf
[0] == 0xffff) {
294 /* The hardware thinks that an srom that starts with 0xffff
295 * is blank, regardless of the rest of the content, so declare
301 /* fixup the endianness so crc8 will pass */
302 htol16_buf(buf
, bufsz
);
303 if (hndcrc8((u8
*) buf
, SROM4_WORDS
* 2, CRC8_INIT_VALUE
) !=
307 /* now correct the endianness of the byte array */
308 ltoh16_buf(buf
, bufsz
);
312 #endif /* defined(BCMNVRAMR) */
314 * Create variable table from memory.
315 * Return 0 on success, nonzero on error.
317 static int initvars_table(char *start
, char *end
,
318 char **vars
, uint
*count
)
320 int c
= (int)(end
- start
);
322 /* do it only when there is more than just the null string */
324 char *vp
= kmalloc(c
, GFP_ATOMIC
);
328 memcpy(vp
, start
, c
);
340 * Find variables with <devpath> from flash. 'base' points to the beginning
341 * of the table upon enter and to the end of the table upon exit when success.
342 * Return 0 on success, nonzero on error.
344 static int initvars_flash(si_t
*sih
, char **base
, uint len
)
350 uint l
, dl
, copy_len
;
351 char devpath
[SI_DEVPATH_BUFSZ
];
353 /* allocate memory and read in flash */
354 flash
= kmalloc(NVRAM_SPACE
, GFP_ATOMIC
);
357 err
= nvram_getall(flash
, NVRAM_SPACE
);
361 si_devpath(sih
, devpath
, sizeof(devpath
));
363 /* grab vars with the <devpath> prefix in name */
364 dl
= strlen(devpath
);
365 for (s
= flash
; s
&& *s
; s
+= l
+ 1) {
368 /* skip non-matching variable */
369 if (strncmp(s
, devpath
, dl
))
372 /* is there enough room to copy? */
373 copy_len
= l
- dl
+ 1;
374 if (len
< copy_len
) {
375 err
= BCME_BUFTOOSHORT
;
379 /* no prefix, just the name=value */
380 strncpy(vp
, &s
[dl
], copy_len
);
385 /* add null string as terminator */
387 err
= BCME_BUFTOOSHORT
;
399 * Initialize nonvolatile variable table from flash.
400 * Return 0 on success, nonzero on error.
402 static int initvars_flash_si(si_t
*sih
, char **vars
, uint
*count
)
407 ASSERT(vars
!= NULL
);
408 ASSERT(count
!= NULL
);
410 base
= vp
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
415 err
= initvars_flash(sih
, &vp
, MAXSZ_NVRAM_VARS
);
417 err
= initvars_table(base
, vp
, vars
, count
);
424 /* Parse SROM and create name=value pairs. 'srom' points to
425 * the SROM word array. 'off' specifies the offset of the
426 * first word 'srom' points to, which should be either 0 or
427 * SROM3_SWRG_OFF (full SROM or software region).
430 static uint
mask_shift(u16 mask
)
433 for (i
= 0; i
< (sizeof(mask
) << 3); i
++) {
441 static uint
mask_width(u16 mask
)
444 for (i
= (sizeof(mask
) << 3) - 1; i
>= 0; i
--) {
446 return (uint
) (i
- mask_shift(mask
) + 1);
453 static bool mask_valid(u16 mask
)
455 uint shift
= mask_shift(mask
);
456 uint width
= mask_width(mask
);
457 return mask
== ((~0 << shift
) & ~(~0 << (shift
+ width
)));
461 static void _initvars_srom_pci(u8 sromrev
, u16
*srom
, uint off
, varbuf_t
*b
)
465 const sromvar_t
*srv
;
468 u32 sr
= (1 << sromrev
);
470 varbuf_append(b
, "sromrev=%d", sromrev
);
472 for (srv
= pci_sromvars
; srv
->name
!= NULL
; srv
++) {
475 if ((srv
->revmask
& sr
) == 0)
484 /* This entry is for mfgc only. Don't generate param for it, */
485 if (flags
& SRFL_NOVAR
)
488 if (flags
& SRFL_ETHADDR
) {
491 ea
[0] = (srom
[srv
->off
- off
] >> 8) & 0xff;
492 ea
[1] = srom
[srv
->off
- off
] & 0xff;
493 ea
[2] = (srom
[srv
->off
+ 1 - off
] >> 8) & 0xff;
494 ea
[3] = srom
[srv
->off
+ 1 - off
] & 0xff;
495 ea
[4] = (srom
[srv
->off
+ 2 - off
] >> 8) & 0xff;
496 ea
[5] = srom
[srv
->off
+ 2 - off
] & 0xff;
498 varbuf_append(b
, "%s=%pM", name
, ea
);
500 ASSERT(mask_valid(srv
->mask
));
501 ASSERT(mask_width(srv
->mask
));
503 w
= srom
[srv
->off
- off
];
504 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
505 width
= mask_width(srv
->mask
);
507 while (srv
->flags
& SRFL_MORE
) {
509 ASSERT(srv
->name
!= NULL
);
511 if (srv
->off
== 0 || srv
->off
< off
)
514 ASSERT(mask_valid(srv
->mask
));
515 ASSERT(mask_width(srv
->mask
));
517 w
= srom
[srv
->off
- off
];
519 ((w
& srv
->mask
) >> mask_shift(srv
->
522 width
+= mask_width(srv
->mask
);
525 if ((flags
& SRFL_NOFFS
)
526 && ((int)val
== (1 << width
) - 1))
529 if (flags
& SRFL_CCODE
) {
531 varbuf_append(b
, "ccode=");
533 varbuf_append(b
, "ccode=%c%c",
534 (val
>> 8), (val
& 0xff));
536 /* LED Powersave duty cycle has to be scaled:
537 *(oncount >> 24) (offcount >> 8)
539 else if (flags
& SRFL_LEDDC
) {
540 u32 w32
= (((val
>> 8) & 0xff) << 24) | /* oncount */
541 (((val
& 0xff)) << 8); /* offcount */
542 varbuf_append(b
, "leddc=%d", w32
);
543 } else if (flags
& SRFL_PRHEX
)
544 varbuf_append(b
, "%s=0x%x", name
, val
);
545 else if ((flags
& SRFL_PRSIGN
)
546 && (val
& (1 << (width
- 1))))
547 varbuf_append(b
, "%s=%d", name
,
548 (int)(val
| (~0 << width
)));
550 varbuf_append(b
, "%s=%u", name
, val
);
555 /* Do per-path variables */
560 psz
= SROM8_PATH1
- SROM8_PATH0
;
563 psz
= SROM4_PATH1
- SROM4_PATH0
;
566 for (p
= 0; p
< MAX_PATH_SROM
; p
++) {
567 for (srv
= perpath_pci_sromvars
; srv
->name
!= NULL
;
569 if ((srv
->revmask
& sr
) == 0)
572 if (pb
+ srv
->off
< off
)
575 /* This entry is for mfgc only. Don't generate param for it, */
576 if (srv
->flags
& SRFL_NOVAR
)
579 w
= srom
[pb
+ srv
->off
- off
];
581 ASSERT(mask_valid(srv
->mask
));
582 val
= (w
& srv
->mask
) >> mask_shift(srv
->mask
);
583 width
= mask_width(srv
->mask
);
585 /* Cheating: no per-path var is more than 1 word */
587 if ((srv
->flags
& SRFL_NOFFS
)
588 && ((int)val
== (1 << width
) - 1))
591 if (srv
->flags
& SRFL_PRHEX
)
592 varbuf_append(b
, "%s%d=0x%x", srv
->name
,
595 varbuf_append(b
, "%s%d=%d", srv
->name
,
604 * Initialize nonvolatile variable table from sprom.
605 * Return 0 on success, nonzero on error.
607 static int initvars_srom_pci(si_t
*sih
, void *curmap
, char **vars
, uint
*count
)
609 u16
*srom
, *sromwindow
;
613 char *vp
, *base
= NULL
;
618 * Apply CRC over SROM content regardless SROM is present or not,
619 * and use variable <devpath>sromrev's existence in flash to decide
620 * if we should return an error when CRC fails or read SROM variables
623 srom
= kmalloc(SROM_MAX
, GFP_ATOMIC
);
624 ASSERT(srom
!= NULL
);
628 sromwindow
= (u16
*) SROM_OFFSET(sih
);
629 if (si_is_sprom_available(sih
)) {
631 sprom_read_pci(sih
, sromwindow
, 0, srom
, SROM_WORDS
,
634 if ((srom
[SROM4_SIGN
] == SROM4_SIGNATURE
) ||
635 (((sih
->buscoretype
== PCIE_CORE_ID
)
636 && (sih
->buscorerev
>= 6))
637 || ((sih
->buscoretype
== PCI_CORE_ID
)
638 && (sih
->buscorerev
>= 0xe)))) {
639 /* sromrev >= 4, read more */
641 sprom_read_pci(sih
, sromwindow
, 0, srom
,
643 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
644 } else if (err
== 0) {
645 /* srom is good and is rev < 4 */
646 /* top word of sprom contains version and crc8 */
647 sromrev
= srom
[SROM_CRCREV
] & 0xff;
648 /* bcm4401 sroms misprogrammed */
653 #if defined(BCMNVRAMR)
654 /* Use OTP if SPROM not available */
656 err
= otp_read_pci(sih
, srom
, SROM_MAX
);
658 /* OTP only contain SROM rev8/rev9 for now */
659 sromrev
= srom
[SROM4_CRCREV
] & 0xff;
669 * We want internal/wltest driver to come up with default
670 * sromvars so we can program a blank SPROM/OTP.
677 value
= si_getdevpathvar(sih
, "sromrev");
679 sromrev
= (u8
) simple_strtoul(value
, NULL
, 0);
684 value
= si_getnvramflvar(sih
, "sromrev");
697 /* Bitmask for the sromrev */
700 /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
701 if ((sr
& 0x33e) == 0) {
706 ASSERT(vars
!= NULL
);
707 ASSERT(count
!= NULL
);
709 base
= vp
= kmalloc(MAXSZ_NVRAM_VARS
, GFP_ATOMIC
);
716 /* read variables from flash */
718 err
= initvars_flash(sih
, &vp
, MAXSZ_NVRAM_VARS
);
724 varbuf_init(&b
, base
, MAXSZ_NVRAM_VARS
);
726 /* parse SROM into name=value pairs. */
727 _initvars_srom_pci(sromrev
, srom
, 0, &b
);
729 /* final nullbyte terminator */
734 ASSERT((vp
- base
) <= MAXSZ_NVRAM_VARS
);
737 err
= initvars_table(base
, vp
, vars
, count
);
748 static int initvars_srom_si(si_t
*sih
, void *curmap
, char **vars
, uint
*varsz
)
750 /* Search flash nvram section for srom variables */
751 return initvars_flash_si(sih
, vars
, varsz
);