Staging: merge 2.6.39-rc3 into staging-next
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / util / bcmsrom.c
blob2f8d7f7dd62d62bb652aaa3bb42cc40415d590bc
1 /*
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>
19 #include <bcmdefs.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <stdarg.h>
23 #include <bcmutils.h>
24 #include <hndsoc.h>
25 #include <sbchipc.h>
26 #include <bcmdevs.h>
27 #include <pcicfg.h>
28 #include <siutils.h>
29 #include <bcmsrom.h>
30 #include <bcmsrom_tbl.h>
32 #include <bcmnvram.h>
33 #include <bcmotp.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))
40 #if defined(BCMDBG)
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 */
43 #endif
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 */
49 } varbuf_t;
50 extern char *_vars;
51 extern uint _varsz;
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);
61 #endif
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,
68 uint len);
70 /* Initialization of varbuf structure */
71 static void varbuf_init(varbuf_t *b, char *buf, uint size)
73 b->size = 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, ...)
80 va_list ap;
81 int r;
82 size_t len;
83 char *s;
85 if (b->size < 2)
86 return 0;
88 va_start(ap, fmt);
89 r = vsnprintf(b->buf, b->size, fmt, ap);
90 va_end(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))) {
100 b->size = 0;
101 return 0;
104 /* Remove any earlier occurrence of the same variable */
105 s = strchr(b->buf, '=');
106 if (s != NULL) {
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] == '=') {
110 len = strlen(s) + 1;
111 memmove(s, (s + len),
112 ((b->buf + r + 1) - (s + len)));
113 b->buf -= len;
114 b->size += (unsigned int)len;
115 break;
118 while (*s++)
123 /* skip over this string's null termination */
124 r++;
125 b->size -= r;
126 b->buf += r;
128 return r;
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)
138 uint len;
140 len = 0;
142 ASSERT(bustype == bustype);
143 if (vars == NULL || count == NULL)
144 return 0;
146 *vars = NULL;
147 *count = 0;
149 switch (bustype) {
150 case SI_BUS:
151 case JTAG_BUS:
152 return initvars_srom_si(sih, curmap, vars, count);
154 case PCI_BUS:
155 ASSERT(curmap != NULL);
156 if (curmap == NULL)
157 return -1;
159 return initvars_srom_pci(sih, curmap, vars, count);
161 default:
162 ASSERT(0);
164 return -1;
167 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
168 * not in the bus cores.
170 static u16
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);
185 while (wait_cnt--) {
186 if ((R_REG(&cc->sromcontrol) & SRC_BUSY) == 0)
187 break;
190 if (!wait_cnt) {
191 return 0xffff;
193 if (cmd == SRC_OP_READ)
194 return (u16) R_REG(&cc->sromdata);
195 else
196 return 0xffff;
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.
215 static int
216 sprom_read_pci(si_t *sih, u16 *sprom, uint wordoff,
217 u16 *buf, uint nwords, bool check_crc)
219 int err = 0;
220 uint i;
221 void *ccregs = NULL;
223 /* read the sprom */
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)
229 return 1;
231 ccregs = (void *)((u8 *) sprom - CC_SROM_OTP);
232 buf[i] =
233 srom_cc_cmd(sih, ccregs, SRC_OP_READ,
234 wordoff + i, 0);
236 } else {
237 if (ISSIM_ENAB(sih))
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 */
246 if (ISSIM_ENAB(sih))
247 return err;
249 if (check_crc) {
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
254 * it bad.
256 return 1;
259 /* fixup the endianness so crc8 will pass */
260 htol16_buf(buf, nwords * 2);
261 if (hndcrc8((u8 *) buf, nwords * 2, CRC8_INIT_VALUE) !=
262 CRC8_GOOD_VALUE) {
263 /* DBG only pci always read srom4 first, then srom8/9 */
264 err = 1;
266 /* now correct the endianness of the byte array */
267 ltoh16_buf(buf, nwords * 2);
269 return err;
272 #if defined(BCMNVRAMR)
273 static int otp_read_pci(si_t *sih, u16 *buf, uint bufsz)
275 u8 *otp;
276 uint sz = OTP_SZ_MAX / 2; /* size in words */
277 int err = 0;
279 ASSERT(bufsz <= OTP_SZ_MAX);
281 otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
282 if (otp == NULL) {
283 return BCME_ERROR;
286 err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
288 memcpy(buf, otp, bufsz);
290 kfree(otp);
292 /* Check CRC */
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
296 * it bad.
298 return 1;
301 /* fixup the endianness so crc8 will pass */
302 htol16_buf(buf, bufsz);
303 if (hndcrc8((u8 *) buf, SROM4_WORDS * 2, CRC8_INIT_VALUE) !=
304 CRC8_GOOD_VALUE) {
305 err = 1;
307 /* now correct the endianness of the byte array */
308 ltoh16_buf(buf, bufsz);
310 return err;
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 */
323 if (c > 1) {
324 char *vp = kmalloc(c, GFP_ATOMIC);
325 ASSERT(vp != NULL);
326 if (!vp)
327 return BCME_NOMEM;
328 memcpy(vp, start, c);
329 *vars = vp;
330 *count = c;
331 } else {
332 *vars = NULL;
333 *count = 0;
336 return 0;
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)
346 char *vp = *base;
347 char *flash;
348 int err;
349 char *s;
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);
355 if (!flash)
356 return BCME_NOMEM;
357 err = nvram_getall(flash, NVRAM_SPACE);
358 if (err)
359 goto exit;
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) {
366 l = strlen(s);
368 /* skip non-matching variable */
369 if (strncmp(s, devpath, dl))
370 continue;
372 /* is there enough room to copy? */
373 copy_len = l - dl + 1;
374 if (len < copy_len) {
375 err = BCME_BUFTOOSHORT;
376 goto exit;
379 /* no prefix, just the name=value */
380 strncpy(vp, &s[dl], copy_len);
381 vp += copy_len;
382 len -= copy_len;
385 /* add null string as terminator */
386 if (len < 1) {
387 err = BCME_BUFTOOSHORT;
388 goto exit;
390 *vp++ = '\0';
392 *base = vp;
394 exit: kfree(flash);
395 return err;
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)
404 char *vp, *base;
405 int err;
407 ASSERT(vars != NULL);
408 ASSERT(count != NULL);
410 base = vp = kmalloc(MAXSZ_NVRAM_VARS, GFP_ATOMIC);
411 ASSERT(vp != NULL);
412 if (!vp)
413 return BCME_NOMEM;
415 err = initvars_flash(sih, &vp, MAXSZ_NVRAM_VARS);
416 if (err == 0)
417 err = initvars_table(base, vp, vars, count);
419 kfree(base);
421 return err;
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)
432 uint i;
433 for (i = 0; i < (sizeof(mask) << 3); i++) {
434 if (mask & (1 << i))
435 return i;
437 ASSERT(mask);
438 return 0;
441 static uint mask_width(u16 mask)
443 int i;
444 for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
445 if (mask & (1 << i))
446 return (uint) (i - mask_shift(mask) + 1);
448 ASSERT(mask);
449 return 0;
452 #if defined(BCMDBG)
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)));
459 #endif /* BCMDBG */
461 static void _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, varbuf_t *b)
463 u16 w;
464 u32 val;
465 const sromvar_t *srv;
466 uint width;
467 uint flags;
468 u32 sr = (1 << sromrev);
470 varbuf_append(b, "sromrev=%d", sromrev);
472 for (srv = pci_sromvars; srv->name != NULL; srv++) {
473 const char *name;
475 if ((srv->revmask & sr) == 0)
476 continue;
478 if (srv->off < off)
479 continue;
481 flags = srv->flags;
482 name = srv->name;
484 /* This entry is for mfgc only. Don't generate param for it, */
485 if (flags & SRFL_NOVAR)
486 continue;
488 if (flags & SRFL_ETHADDR) {
489 u8 ea[ETH_ALEN];
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);
499 } else {
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) {
508 srv++;
509 ASSERT(srv->name != NULL);
511 if (srv->off == 0 || srv->off < off)
512 continue;
514 ASSERT(mask_valid(srv->mask));
515 ASSERT(mask_width(srv->mask));
517 w = srom[srv->off - off];
518 val +=
519 ((w & srv->mask) >> mask_shift(srv->
520 mask)) <<
521 width;
522 width += mask_width(srv->mask);
525 if ((flags & SRFL_NOFFS)
526 && ((int)val == (1 << width) - 1))
527 continue;
529 if (flags & SRFL_CCODE) {
530 if (val == 0)
531 varbuf_append(b, "ccode=");
532 else
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)));
549 else
550 varbuf_append(b, "%s=%u", name, val);
554 if (sromrev >= 4) {
555 /* Do per-path variables */
556 uint p, pb, psz;
558 if (sromrev >= 8) {
559 pb = SROM8_PATH0;
560 psz = SROM8_PATH1 - SROM8_PATH0;
561 } else {
562 pb = SROM4_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;
568 srv++) {
569 if ((srv->revmask & sr) == 0)
570 continue;
572 if (pb + srv->off < off)
573 continue;
575 /* This entry is for mfgc only. Don't generate param for it, */
576 if (srv->flags & SRFL_NOVAR)
577 continue;
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))
589 continue;
591 if (srv->flags & SRFL_PRHEX)
592 varbuf_append(b, "%s%d=0x%x", srv->name,
593 p, val);
594 else
595 varbuf_append(b, "%s%d=%d", srv->name,
596 p, val);
598 pb += psz;
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;
610 u8 sromrev = 0;
611 u32 sr;
612 varbuf_t b;
613 char *vp, *base = NULL;
614 bool flash = false;
615 int err = 0;
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
621 * from flash.
623 srom = kmalloc(SROM_MAX, GFP_ATOMIC);
624 ASSERT(srom != NULL);
625 if (!srom)
626 return -2;
628 sromwindow = (u16 *) SROM_OFFSET(sih);
629 if (si_is_sprom_available(sih)) {
630 err =
631 sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
632 true);
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 */
640 err =
641 sprom_read_pci(sih, sromwindow, 0, srom,
642 SROM4_WORDS, true);
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 */
649 if (sromrev == 0x10)
650 sromrev = 1;
653 #if defined(BCMNVRAMR)
654 /* Use OTP if SPROM not available */
655 else {
656 err = otp_read_pci(sih, srom, SROM_MAX);
657 if (err == 0)
658 /* OTP only contain SROM rev8/rev9 for now */
659 sromrev = srom[SROM4_CRCREV] & 0xff;
660 else
661 err = 1;
663 #else
664 else
665 err = 1;
666 #endif
669 * We want internal/wltest driver to come up with default
670 * sromvars so we can program a blank SPROM/OTP.
672 if (err) {
673 char *value;
674 u32 val;
675 val = 0;
677 value = si_getdevpathvar(sih, "sromrev");
678 if (value) {
679 sromrev = (u8) simple_strtoul(value, NULL, 0);
680 flash = true;
681 goto varscont;
684 value = si_getnvramflvar(sih, "sromrev");
685 if (value) {
686 err = 0;
687 goto errout;
691 err = -1;
692 goto errout;
696 varscont:
697 /* Bitmask for the sromrev */
698 sr = 1 << sromrev;
700 /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
701 if ((sr & 0x33e) == 0) {
702 err = -2;
703 goto errout;
706 ASSERT(vars != NULL);
707 ASSERT(count != NULL);
709 base = vp = kmalloc(MAXSZ_NVRAM_VARS, GFP_ATOMIC);
710 ASSERT(vp != NULL);
711 if (!vp) {
712 err = -2;
713 goto errout;
716 /* read variables from flash */
717 if (flash) {
718 err = initvars_flash(sih, &vp, MAXSZ_NVRAM_VARS);
719 if (err)
720 goto errout;
721 goto varsdone;
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 */
730 ASSERT(b.size >= 1);
731 vp = b.buf;
732 *vp++ = '\0';
734 ASSERT((vp - base) <= MAXSZ_NVRAM_VARS);
736 varsdone:
737 err = initvars_table(base, vp, vars, count);
739 errout:
740 if (base)
741 kfree(base);
743 kfree(srom);
744 return err;
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);