1/* 2 * Routines to access SPROM and to parse SROM/CIS variables. 3 * 4 * Copyright 2007, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * $Id: bcmsrom.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $ 12 */ 13 14#include <typedefs.h> 15#include <bcmdefs.h> 16#include <osl.h> 17#include <stdarg.h> 18#include <bcmutils.h> 19#include <sbchipc.h> 20#include <bcmdevs.h> 21#include <bcmendian.h> 22#include <sbpcmcia.h> 23#include <pcicfg.h> 24#include <sbconfig.h> 25#include <sbutils.h> 26#include <bcmsrom.h> 27 28#include <bcmnvram.h> 29#include <bcmotp.h> 30 31#if defined(BCMUSBDEV) 32#include <sbsdio.h> 33#include <sbhnddma.h> 34#include <sbsdpcmdev.h> 35#endif 36 37#ifdef WLTEST 38#include <sbsprom.h> 39#endif /* WLTEST */ 40#include <proto/ethernet.h> /* for sprom content groking */ 41 42/* debug/trace */ 43#if defined(WLTEST) 44#define BS_ERROR(args) printf args 45#else 46#define BS_ERROR(args) 47#endif 48 49#define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */ 50#define WRITE_WORD_DELAY 20 /* 20 ms between each word write */ 51 52typedef struct varbuf { 53 char *buf; /* pointer to current position */ 54 unsigned int size; /* current (residual) size in bytes */ 55} varbuf_t; 56 57static int initvars_srom_sb(sb_t *sbh, osl_t *osh, void *curmap, char **vars, uint *count); 58static void _initvars_srom_pci(uint8 sromrev, uint16 *srom, uint off, varbuf_t *b); 59static int initvars_srom_pci(sb_t *sbh, void *curmap, char **vars, uint *count); 60static int initvars_cis_pcmcia(sb_t *sbh, osl_t *osh, char **vars, uint *count); 61#if !defined(BCMUSBDEV) 62static int initvars_flash_sb(sb_t *sbh, char **vars, uint *count); 63#endif 64static int sprom_cmd_pcmcia(osl_t *osh, uint8 cmd); 65static int sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data); 66static int sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data); 67static int sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, 68 bool check_crc); 69 70static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count); 71static int initvars_flash(sb_t *sbh, osl_t *osh, char **vp, uint len); 72 73#ifdef BCMUSBDEV 74static int get_sb_pcmcia_srom(sb_t *sbh, osl_t *osh, uint8 *pcmregs, 75 uint boff, uint16 *srom, uint bsz); 76static int set_sb_pcmcia_srom(sb_t *sbh, osl_t *osh, uint8 *pcmregs, 77 uint boff, uint16 *srom, uint bsz); 78static uint srom_size(sb_t *sbh, osl_t *osh); 79#endif /* def BCMUSBDEV */ 80 81/* Initialization of varbuf structure */ 82static void 83varbuf_init(varbuf_t *b, char *buf, uint size) 84{ 85 b->size = size; 86 b->buf = buf; 87} 88 89/* append a null terminated var=value string */ 90static int 91varbuf_append(varbuf_t *b, const char *fmt, ...) 92{ 93 va_list ap; 94 int r; 95 96 if (b->size < 2) 97 return 0; 98 99 va_start(ap, fmt); 100 r = vsnprintf(b->buf, b->size, fmt, ap); 101 va_end(ap); 102 103 /* C99 snprintf behavior returns r >= size on overflow, 104 * others return -1 on overflow. 105 * All return -1 on format error. 106 * We need to leave room for 2 null terminations, one for the current var 107 * string, and one for final null of the var table. So check that the 108 * strlen written, r, leaves room for 2 chars. 109 */ 110 if ((r == -1) || (r > (int)(b->size - 2))) { 111 b->size = 0; 112 return 0; 113 } 114 115 /* skip over this string's null termination */ 116 r++; 117 b->size -= r; 118 b->buf += r; 119 120 return r; 121} 122 123/* 124 * Initialize local vars from the right source for this platform. 125 * Return 0 on success, nonzero on error. 126 */ 127int 128BCMINITFN(srom_var_init)(sb_t *sbh, uint bustype, void *curmap, osl_t *osh, 129 char **vars, uint *count) 130{ 131 ASSERT(bustype == BUSTYPE(bustype)); 132 if (vars == NULL || count == NULL) 133 return (0); 134 135 *vars = NULL; 136 *count = 0; 137 138 switch (BUSTYPE(bustype)) { 139 case SB_BUS: 140 case JTAG_BUS: 141 return initvars_srom_sb(sbh, osh, curmap, vars, count); 142 143 case PCI_BUS: 144 ASSERT(curmap); /* can not be NULL */ 145 return initvars_srom_pci(sbh, curmap, vars, count); 146 147 case PCMCIA_BUS: 148 return initvars_cis_pcmcia(sbh, osh, vars, count); 149 150 151 default: 152 ASSERT(0); 153 } 154 return (-1); 155} 156 157/* support only 16-bit word read from srom */ 158int 159srom_read(sb_t *sbh, uint bustype, void *curmap, osl_t *osh, 160 uint byteoff, uint nbytes, uint16 *buf) 161{ 162 void *srom; 163 uint i, off, nw; 164 165 ASSERT(bustype == BUSTYPE(bustype)); 166 167 /* check input - 16-bit access only */ 168 if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) 169 return 1; 170 171 off = byteoff / 2; 172 nw = nbytes / 2; 173 174 if (BUSTYPE(bustype) == PCI_BUS) { 175 if (!curmap) 176 return 1; 177 srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET; 178 if (sprom_read_pci(osh, srom, off, buf, nw, FALSE)) 179 return 1; 180 } else if (BUSTYPE(bustype) == PCMCIA_BUS) { 181 for (i = 0; i < nw; i++) { 182 if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16 *)(buf + i))) 183 return 1; 184 } 185 } else if (BUSTYPE(bustype) == SB_BUS) { 186#ifdef BCMUSBDEV 187 if (SPROMBUS == PCMCIA_BUS) { 188 uint origidx; 189 void *regs; 190 int rc; 191 bool wasup; 192 193 origidx = sb_coreidx(sbh); 194 regs = sb_setcore(sbh, SB_PCMCIA, 0); 195 ASSERT(regs != NULL); 196 197 if (!(wasup = sb_iscoreup(sbh))) 198 sb_core_reset(sbh, 0, 0); 199 200 rc = get_sb_pcmcia_srom(sbh, osh, regs, byteoff, buf, nbytes); 201 202 if (!wasup) 203 sb_core_disable(sbh, 0); 204 205 sb_setcoreidx(sbh, origidx); 206 return rc; 207 } 208#endif /* def BCMUSBDEV */ 209 210 return 1; 211 } else { 212 return 1; 213 } 214 215 return 0; 216} 217 218/* support only 16-bit word write into srom */ 219int 220srom_write(sb_t *sbh, uint bustype, void *curmap, osl_t *osh, 221 uint byteoff, uint nbytes, uint16 *buf) 222{ 223 uint16 *srom; 224 uint i, nw, crc_range; 225 uint16 image[SPROM_SIZE]; 226 uint8 crc; 227 volatile uint32 val32; 228 229 ASSERT(bustype == BUSTYPE(bustype)); 230 231 /* check input - 16-bit access only */ 232 if ((byteoff & 1) || (nbytes & 1)) 233 return 1; 234 235 if (byteoff == 0x55aa) { 236 /* Erase request */ 237 crc_range = 0; 238 memset((void *)image, 0xff, nbytes); 239 nw = nbytes / 2; 240 } else if ((byteoff == 0) && 241 ((nbytes == SPROM_SIZE * 2) || 242 (nbytes == (SPROM_CRC_RANGE * 2)) || 243 (nbytes == (SROM4_WORDS * 2)))) { 244 /* Are we writing the whole thing at once? */ 245 crc_range = nbytes; 246 bcopy((void *)buf, (void *)image, nbytes); 247 nw = nbytes / 2; 248 } else { 249 if ((byteoff + nbytes) > (SPROM_SIZE * 2)) 250 return 1; 251 252 if (BUSTYPE(bustype) == PCMCIA_BUS) { 253 crc_range = SPROM_SIZE * 2; 254 } 255 else { 256 crc_range = SPROM_CRC_RANGE * 2; /* Tentative */ 257 } 258 259 nw = crc_range / 2; 260 /* read first 64 words from srom */ 261 if (srom_read(sbh, bustype, curmap, osh, 0, crc_range, image)) 262 return 1; 263 if (image[SROM4_SIGN] == SROM4_SIGNATURE) { 264 nw = SROM4_WORDS; 265 crc_range = nw * 2; 266 if (srom_read(sbh, bustype, curmap, osh, 0, crc_range, image)) 267 return 1; 268 } 269 /* make changes */ 270 bcopy((void *)buf, (void *)&image[byteoff / 2], nbytes); 271 } 272 273 if (crc_range) { 274 /* calculate crc */ 275 htol16_buf(image, crc_range); 276 crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE); 277 ltoh16_buf(image, crc_range); 278 image[nw - 1] = (crc << 8) | (image[nw - 1] & 0xff); 279 } 280 281 if (BUSTYPE(bustype) == PCI_BUS) { 282 srom = (uint16 *)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET); 283 /* enable writes to the SPROM */ 284 val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); 285 val32 |= SPROM_WRITEEN; 286 OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); 287 bcm_mdelay(WRITE_ENABLE_DELAY); 288 /* write srom */ 289 for (i = 0; i < nw; i++) { 290 W_REG(osh, &srom[i], image[i]); 291 bcm_mdelay(WRITE_WORD_DELAY); 292 } 293 /* disable writes to the SPROM */ 294 OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & 295 ~SPROM_WRITEEN); 296 } else if (BUSTYPE(bustype) == PCMCIA_BUS) { 297 /* enable writes to the SPROM */ 298 if (sprom_cmd_pcmcia(osh, SROM_WEN)) 299 return 1; 300 bcm_mdelay(WRITE_ENABLE_DELAY); 301 /* write srom */ 302 for (i = 0; i < nw; i++) { 303 sprom_write_pcmcia(osh, (uint16)(i), image[i]); 304 bcm_mdelay(WRITE_WORD_DELAY); 305 } 306 /* disable writes to the SPROM */ 307 if (sprom_cmd_pcmcia(osh, SROM_WDS)) 308 return 1; 309 } else if (BUSTYPE(bustype) == SB_BUS) { 310#ifdef BCMUSBDEV 311 if (SPROMBUS == PCMCIA_BUS) { 312 uint origidx; 313 void *regs; 314 int rc; 315 bool wasup; 316 317 origidx = sb_coreidx(sbh); 318 regs = sb_setcore(sbh, SB_PCMCIA, 0); 319 ASSERT(regs != NULL); 320 321 if (!(wasup = sb_iscoreup(sbh))) 322 sb_core_reset(sbh, 0, 0); 323 324 rc = set_sb_pcmcia_srom(sbh, osh, regs, byteoff, buf, nbytes); 325 326 if (!wasup) 327 sb_core_disable(sbh, 0); 328 329 sb_setcoreidx(sbh, origidx); 330 return rc; 331 } 332#endif /* def BCMUSBDEV */ 333 return 1; 334 } else { 335 return 1; 336 } 337 338 bcm_mdelay(WRITE_ENABLE_DELAY); 339 return 0; 340} 341 342#ifdef BCMUSBDEV 343#define SB_PCMCIA_READ(osh, regs, fcr) \ 344 R_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2) 345#define SB_PCMCIA_WRITE(osh, regs, fcr, v) \ 346 W_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2, v) 347 348/* set PCMCIA srom command register */ 349static int 350srom_cmd_sb_pcmcia(osl_t *osh, uint8 *pcmregs, uint8 cmd) 351{ 352 uint8 status = 0; 353 uint wait_cnt = 0; 354 355 /* write srom command register */ 356 SB_PCMCIA_WRITE(osh, pcmregs, SROM_CS, cmd); 357 358 /* wait status */ 359 while (++wait_cnt < 1000000) { 360 status = SB_PCMCIA_READ(osh, pcmregs, SROM_CS); 361 if (status & SROM_DONE) 362 return 0; 363 OSL_DELAY(1); 364 } 365 366 BS_ERROR(("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt, status)); 367 return 1; 368} 369 370/* read a word from the PCMCIA srom over SB */ 371static int 372srom_read_sb_pcmcia(osl_t *osh, uint8 *pcmregs, uint16 addr, uint16 *data) 373{ 374 uint8 addr_l, addr_h, data_l, data_h; 375 376 addr_l = (uint8)((addr * 2) & 0xff); 377 addr_h = (uint8)(((addr * 2) >> 8) & 0xff); 378 379 /* set address */ 380 SB_PCMCIA_WRITE(osh, pcmregs, SROM_ADDRH, addr_h); 381 SB_PCMCIA_WRITE(osh, pcmregs, SROM_ADDRL, addr_l); 382 383 /* do read */ 384 if (srom_cmd_sb_pcmcia(osh, pcmregs, SROM_READ)) 385 return 1; 386 387 /* read data */ 388 data_h = SB_PCMCIA_READ(osh, pcmregs, SROM_DATAH); 389 data_l = SB_PCMCIA_READ(osh, pcmregs, SROM_DATAL); 390 *data = ((uint16)data_h << 8) | data_l; 391 392 return 0; 393} 394 395/* write a word to the PCMCIA srom over SB */ 396static int 397srom_write_sb_pcmcia(osl_t *osh, uint8 *pcmregs, uint16 addr, uint16 data) 398{ 399 uint8 addr_l, addr_h, data_l, data_h; 400 int rc; 401 402 addr_l = (uint8)((addr * 2) & 0xff); 403 addr_h = (uint8)(((addr * 2) >> 8) & 0xff); 404 405 /* set address */ 406 SB_PCMCIA_WRITE(osh, pcmregs, SROM_ADDRH, addr_h); 407 SB_PCMCIA_WRITE(osh, pcmregs, SROM_ADDRL, addr_l); 408 409 data_l = (uint8)(data & 0xff); 410 data_h = (uint8)((data >> 8) & 0xff); 411 412 /* write data */ 413 SB_PCMCIA_WRITE(osh, pcmregs, SROM_DATAH, data_h); 414 SB_PCMCIA_WRITE(osh, pcmregs, SROM_DATAL, data_l); 415 416 /* do write */ 417 rc = srom_cmd_sb_pcmcia(osh, pcmregs, SROM_WRITE); 418 OSL_DELAY(20000); 419 return rc; 420} 421 422/* 423 * Read the srom for the pcmcia-srom over sb case. 424 * Return 0 on success, nonzero on error. 425 */ 426static int 427get_sb_pcmcia_srom(sb_t *sbh, osl_t *osh, uint8 *pcmregs, 428 uint boff, uint16 *srom, uint bsz) 429{ 430 uint i, nw, woff, wsz; 431 int err = 0; 432 433 /* read must be at word boundary */ 434 ASSERT((boff & 1) == 0 && (bsz & 1) == 0); 435 436 /* read sprom size and validate the parms */ 437 if ((nw = srom_size(sbh, osh)) == 0) { 438 BS_ERROR(("get_sb_pcmcia_srom: sprom size unknown\n")); 439 err = -1; 440 goto out; 441 } 442 if (boff + bsz > 2 * nw) { 443 BS_ERROR(("get_sb_pcmcia_srom: sprom size exceeded\n")); 444 err = -2; 445 goto out; 446 } 447 448 /* read in sprom contents */ 449 for (woff = boff / 2, wsz = bsz / 2, i = 0; 450 woff < nw && i < wsz; woff ++, i ++) { 451 if (srom_read_sb_pcmcia(osh, pcmregs, (uint16)woff, &srom[i])) { 452 BS_ERROR(("get_sb_pcmcia_srom: sprom read failed\n")); 453 err = -3; 454 goto out; 455 } 456 } 457 458out: 459 return err; 460} 461 462/* 463 * Write the srom for the pcmcia-srom over sb case. 464 * Return 0 on success, nonzero on error. 465 */ 466static int 467set_sb_pcmcia_srom(sb_t *sbh, osl_t *osh, uint8 *pcmregs, 468 uint boff, uint16 *srom, uint bsz) 469{ 470 uint i, nw, woff, wsz; 471 uint16 word; 472 uint8 crc; 473 int err = 0; 474 475 /* write must be at word boundary */ 476 ASSERT((boff & 1) == 0 && (bsz & 1) == 0); 477 478 /* read sprom size and validate the parms */ 479 if ((nw = srom_size(sbh, osh)) == 0) { 480 BS_ERROR(("set_sb_pcmcia_srom: sprom size unknown\n")); 481 err = -1; 482 goto out; 483 } 484 if (boff + bsz > 2 * nw) { 485 BS_ERROR(("set_sb_pcmcia_srom: sprom size exceeded\n")); 486 err = -2; 487 goto out; 488 } 489 490 /* enable write */ 491 if (srom_cmd_sb_pcmcia(osh, pcmregs, SROM_WEN)) { 492 BS_ERROR(("set_sb_pcmcia_srom: sprom wen failed\n")); 493 err = -3; 494 goto out; 495 } 496 497 /* write buffer to sprom */ 498 for (woff = boff / 2, wsz = bsz / 2, i = 0; 499 woff < nw && i < wsz; woff ++, i ++) { 500 if (srom_write_sb_pcmcia(osh, pcmregs, (uint16)woff, srom[i])) { 501 BS_ERROR(("set_sb_pcmcia_srom: sprom write failed\n")); 502 err = -4; 503 goto out; 504 } 505 } 506 507 /* fix crc */ 508 crc = CRC8_INIT_VALUE; 509 for (woff = 0; woff < nw; woff ++) { 510 if (srom_read_sb_pcmcia(osh, pcmregs, (uint16)woff, &word)) { 511 BS_ERROR(("set_sb_pcmcia_srom: sprom fix crc read failed\n")); 512 err = -5; 513 goto out; 514 } 515 word = htol16(word); 516 crc = hndcrc8((uint8 *)&word, woff != nw - 1 ? 2 : 1, crc); 517 } 518 word = (~crc << 8) + (ltoh16(word) & 0xff); 519 if (srom_write_sb_pcmcia(osh, pcmregs, (uint16)(woff - 1), word)) { 520 BS_ERROR(("set_sb_pcmcia_srom: sprom fix crc write failed\n")); 521 err = -6; 522 goto out; 523 } 524 525 /* disable write */ 526 if (srom_cmd_sb_pcmcia(osh, pcmregs, SROM_WDS)) { 527 BS_ERROR(("set_sb_pcmcia_srom: sprom wds failed\n")); 528 err = -7; 529 goto out; 530 } 531 532out: 533 return err; 534} 535#endif /* def BCMUSBDEV */ 536 537int 538srom_parsecis(osl_t *osh, uint8 *pcis[], uint ciscnt, char **vars, uint *count) 539{ 540 char eabuf[32]; 541 char *base; 542 varbuf_t b; 543 uint8 *cis, tup, tlen, sromrev = 1; 544 int i, j; 545 uint varsize; 546 bool ag_init = FALSE; 547 uint32 w32; 548 uint funcid; 549 uint cisnum; 550 int32 boardnum = -1; 551 552 ASSERT(vars); 553 ASSERT(count); 554 555 base = MALLOC(osh, MAXSZ_NVRAM_VARS); 556 ASSERT(base); 557 if (!base) 558 return -2; 559 560 varbuf_init(&b, base, MAXSZ_NVRAM_VARS); 561 562 eabuf[0] = '\0'; 563 for (cisnum = 0; cisnum < ciscnt; cisnum++) { 564 cis = *pcis++; 565 i = 0; 566 funcid = 0; 567 do { 568 tup = cis[i++]; 569 tlen = cis[i++]; 570 if ((i + tlen) >= CIS_SIZE) 571 break; 572 573 switch (tup) { 574 case CISTPL_VERS_1: 575 /* assume the strings are good if the version field checks out */ 576 if (((cis[i + 1] << 8) + cis[i]) >= 0x0008) { 577 varbuf_append(&b, "manf=%s", &cis[i + 2]); 578 varbuf_append(&b, "productname=%s", 579 &cis[i + 3 + strlen((char *)&cis[i + 2])]); 580 break; 581 } 582 583 case CISTPL_MANFID: 584 varbuf_append(&b, "manfid=0x%x", (cis[i + 1] << 8) + cis[i]); 585 varbuf_append(&b, "prodid=0x%x", (cis[i + 3] << 8) + cis[i + 2]); 586 break; 587 588 case CISTPL_FUNCID: 589 funcid = cis[i]; 590 break; 591 592 case CISTPL_FUNCE: 593 switch (funcid) { 594 default: 595 /* set macaddr if HNBU_MACADDR not seen yet */ 596 if (eabuf[0] == '\0' && cis[i] == LAN_NID) { 597 ASSERT(cis[i + 1] == ETHER_ADDR_LEN); 598 bcm_ether_ntoa((struct ether_addr *)&cis[i + 2], 599 eabuf); 600 } 601 /* set boardnum if HNBU_BOARDNUM not seen yet */ 602 if (boardnum == -1) 603 boardnum = (cis[i + 6] << 8) + cis[i + 7]; 604 break; 605 } 606 break; 607 608 case CISTPL_CFTABLE: 609 varbuf_append(&b, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]); 610 break; 611 612 case CISTPL_BRCM_HNBU: 613 switch (cis[i]) { 614 case HNBU_SROMREV: 615 sromrev = cis[i + 1]; 616 varbuf_append(&b, "sromrev=%d", sromrev); 617 break; 618 619 case HNBU_CHIPID: 620 varbuf_append(&b, "vendid=0x%x", (cis[i + 2] << 8) + 621 cis[i + 1]); 622 varbuf_append(&b, "devid=0x%x", (cis[i + 4] << 8) + 623 cis[i + 3]); 624 if (tlen >= 7) { 625 varbuf_append(&b, "chiprev=%d", 626 (cis[i + 6] << 8) + cis[i + 5]); 627 } 628 if (tlen >= 9) { 629 varbuf_append(&b, "subvendid=0x%x", 630 (cis[i + 8] << 8) + cis[i + 7]); 631 } 632 if (tlen >= 11) { 633 varbuf_append(&b, "subdevid=0x%x", 634 (cis[i + 10] << 8) + cis[i + 9]); 635 /* subdevid doubles for boardtype */ 636 varbuf_append(&b, "boardtype=0x%x", 637 (cis[i + 10] << 8) + cis[i + 9]); 638 } 639 break; 640 641 case HNBU_BOARDREV: 642 varbuf_append(&b, "boardrev=0x%x", cis[i + 1]); 643 break; 644 645 case HNBU_AA: 646 varbuf_append(&b, "aa2g=%d", cis[i + 1]); 647 break; 648 649 case HNBU_AG: 650 varbuf_append(&b, "ag0=%d", cis[i + 1]); 651 ag_init = TRUE; 652 break; 653 654 case HNBU_ANT5G: 655 varbuf_append(&b, "aa5g=%d", cis[i + 1]); 656 varbuf_append(&b, "ag1=%d", cis[i + 2]); 657 break; 658 659 case HNBU_CC: 660 ASSERT(sromrev == 1); 661 varbuf_append(&b, "cc=%d", cis[i + 1]); 662 break; 663 664 case HNBU_PAPARMS: 665 if (tlen == 2) { 666 ASSERT(sromrev == 1); 667 varbuf_append(&b, "pa0maxpwr=%d", cis[i + 1]); 668 } else if (tlen >= 9) { 669 if (tlen == 10) { 670 ASSERT(sromrev >= 2); 671 varbuf_append(&b, "opo=%d", cis[i + 9]); 672 } else 673 ASSERT(tlen == 9); 674 675 for (j = 0; j < 3; j++) { 676 varbuf_append(&b, "pa0b%d=%d", j, 677 (cis[i + (j * 2) + 2] << 8) + 678 cis[i + (j * 2) + 1]); 679 } 680 varbuf_append(&b, "pa0itssit=%d", cis[i + 7]); 681 varbuf_append(&b, "pa0maxpwr=%d", cis[i + 8]); 682 } else 683 ASSERT(tlen >= 9); 684 break; 685 686 case HNBU_PAPARMS5G: 687 ASSERT((sromrev == 2) || (sromrev == 3)); 688 for (j = 0; j < 3; j++) { 689 varbuf_append(&b, "pa1b%d=%d", j, 690 (cis[i + (j * 2) + 2] << 8) + 691 cis[i + (j * 2) + 1]); 692 } 693 for (j = 3; j < 6; j++) { 694 varbuf_append(&b, "pa1lob%d=%d", j - 3, 695 (cis[i + (j * 2) + 2] << 8) + 696 cis[i + (j * 2) + 1]); 697 } 698 for (j = 6; j < 9; j++) { 699 varbuf_append(&b, "pa1hib%d=%d", j - 6, 700 (cis[i + (j * 2) + 2] << 8) + 701 cis[i + (j * 2) + 1]); 702 } 703 varbuf_append(&b, "pa1itssit=%d", cis[i + 19]); 704 varbuf_append(&b, "pa1maxpwr=%d", cis[i + 20]); 705 varbuf_append(&b, "pa1lomaxpwr=%d", cis[i + 21]); 706 varbuf_append(&b, "pa1himaxpwr=%d", cis[i + 22]); 707 break; 708 709 case HNBU_OEM: 710 ASSERT(sromrev == 1); 711 varbuf_append(&b, "oem=%02x%02x%02x%02x%02x%02x%02x%02x", 712 cis[i + 1], cis[i + 2], 713 cis[i + 3], cis[i + 4], 714 cis[i + 5], cis[i + 6], 715 cis[i + 7], cis[i + 8]); 716 break; 717 718 case HNBU_BOARDFLAGS: 719 w32 = (cis[i + 2] << 8) + cis[i + 1]; 720 if (tlen == 5) 721 w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16); 722 varbuf_append(&b, "boardflags=0x%x", w32); 723 break; 724 725 case HNBU_LEDS: 726 if (cis[i + 1] != 0xff) { 727 varbuf_append(&b, "ledbh0=%d", cis[i + 1]); 728 } 729 if (cis[i + 2] != 0xff) { 730 varbuf_append(&b, "ledbh1=%d", cis[i + 2]); 731 } 732 if (cis[i + 3] != 0xff) { 733 varbuf_append(&b, "ledbh2=%d", cis[i + 3]); 734 } 735 if (cis[i + 4] != 0xff) { 736 varbuf_append(&b, "ledbh3=%d", cis[i + 4]); 737 } 738 break; 739 740 case HNBU_CCODE: 741 ASSERT(sromrev > 1); 742 if ((cis[i + 1] == 0) || (cis[i + 2] == 0)) 743 varbuf_append(&b, "ccode="); 744 else 745 varbuf_append(&b, "ccode=%c%c", 746 cis[i + 1], cis[i + 2]); 747 varbuf_append(&b, "cctl=0x%x", cis[i + 3]); 748 break; 749 750 case HNBU_CCKPO: 751 ASSERT(sromrev > 2); 752 varbuf_append(&b, "cckpo=0x%x", 753 (cis[i + 2] << 8) | cis[i + 1]); 754 break; 755 756 case HNBU_OFDMPO: 757 ASSERT(sromrev > 2); 758 varbuf_append(&b, "ofdmpo=0x%x", 759 (cis[i + 4] << 24) | 760 (cis[i + 3] << 16) | 761 (cis[i + 2] << 8) | 762 cis[i + 1]); 763 break; 764 765 case HNBU_RDLID: 766 varbuf_append(&b, "rdlid=0x%x", 767 (cis[i + 2] << 8) | cis[i + 1]); 768 break; 769 770 case HNBU_RDLRNDIS: 771 varbuf_append(&b, "rdlrndis=%d", cis[i + 1]); 772 break; 773 774 case HNBU_RDLRWU: 775 varbuf_append(&b, "rdlrwu=%d", cis[i + 1]); 776 break; 777 778 case HNBU_RDLSN: 779 varbuf_append(&b, "rdlsn=%d", 780 (cis[i + 2] << 8) | cis[i + 1]); 781 break; 782 783 case HNBU_XTALFREQ: 784 varbuf_append(&b, "xtalfreq=%d", 785 (cis[i + 4] << 24) | 786 (cis[i + 3] << 16) | 787 (cis[i + 2] << 8) | 788 cis[i + 1]); 789 break; 790 791 case HNBU_RSSISMBXA2G: 792 ASSERT(sromrev == 3); 793 varbuf_append(&b, "rssismf2g=%d", cis[i + 1] & 0xf); 794 varbuf_append(&b, "rssismc2g=%d", (cis[i + 1] >> 4) & 0xf); 795 varbuf_append(&b, "rssisav2g=%d", cis[i + 2] & 0x7); 796 varbuf_append(&b, "bxa2g=%d", (cis[i + 2] >> 3) & 0x3); 797 break; 798 799 case HNBU_RSSISMBXA5G: 800 ASSERT(sromrev == 3); 801 varbuf_append(&b, "rssismf5g=%d", cis[i + 1] & 0xf); 802 varbuf_append(&b, "rssismc5g=%d", (cis[i + 1] >> 4) & 0xf); 803 varbuf_append(&b, "rssisav5g=%d", cis[i + 2] & 0x7); 804 varbuf_append(&b, "bxa5g=%d", (cis[i + 2] >> 3) & 0x3); 805 break; 806 807 case HNBU_TRI2G: 808 ASSERT(sromrev == 3); 809 varbuf_append(&b, "tri2g=%d", cis[i + 1]); 810 break; 811 812 case HNBU_TRI5G: 813 ASSERT(sromrev == 3); 814 varbuf_append(&b, "tri5gl=%d", cis[i + 1]); 815 varbuf_append(&b, "tri5g=%d", cis[i + 2]); 816 varbuf_append(&b, "tri5gh=%d", cis[i + 3]); 817 break; 818 819 case HNBU_RXPO2G: 820 ASSERT(sromrev == 3); 821 varbuf_append(&b, "rxpo2g=%d", cis[i + 1]); 822 break; 823 824 case HNBU_RXPO5G: 825 ASSERT(sromrev == 3); 826 varbuf_append(&b, "rxpo5g=%d", cis[i + 1]); 827 break; 828 829 case HNBU_BOARDNUM: 830 boardnum = (cis[i + 2] << 8) + cis[i + 1]; 831 break; 832 833 case HNBU_MACADDR: 834 bcm_ether_ntoa((struct ether_addr *)&cis[i + 1], 835 eabuf); 836 break; 837 838 case HNBU_BOARDTYPE: 839 varbuf_append(&b, "boardtype=0x%x", 840 (cis[i + 2] << 8) + cis[i + 1]); 841 break; 842 843#if defined(BCMCCISSR3) 844 case HNBU_SROM3SWRGN: { 845 uint16 srom[35]; 846 uint8 srev = cis[i + 1 + 70]; 847 ASSERT(srev == 3); 848 /* make tuple value 16-bit aligned and parse it */ 849 bcopy(&cis[i + 1], srom, sizeof(srom)); 850 _initvars_srom_pci(srev, srom, SROM3_SWRGN_OFF, &b); 851 /* create extra variables */ 852 varbuf_append(&b, "vendid=0x%x", 853 (cis[i + 1 + 73] << 8) + cis[i + 1 + 72]); 854 varbuf_append(&b, "devid=0x%x", 855 (cis[i + 1 + 75] << 8) + cis[i + 1 + 74]); 856 varbuf_append(&b, "xtalfreq=%d", 857 (cis[i + 1 + 77] << 8) + cis[i + 1 + 76]); 858 /* 2.4G antenna gain is included in SROM */ 859 ag_init = TRUE; 860 /* Ethernet MAC address is included in SROM */ 861 eabuf[0] = 0; 862 boardnum = -1; 863 break; 864 } 865#endif 866 } 867 break; 868 } 869 i += tlen; 870 } while (tup != CISTPL_END); 871 } 872 873 if (boardnum != -1) { 874 varbuf_append(&b, "boardnum=%d", boardnum); 875 } 876 877 if (eabuf[0]) { 878 varbuf_append(&b, "macaddr=%s", eabuf); 879 } 880 881 /* if there is no antenna gain field, set default */ 882 if (ag_init == FALSE) { 883 varbuf_append(&b, "ag0=%d", 0xff); 884 } 885 886 /* final nullbyte terminator */ 887 ASSERT(b.size >= 1); 888 *b.buf++ = '\0'; 889 varsize = (uint)(b.buf - base); 890 ASSERT(varsize < MAXSZ_NVRAM_VARS); 891 if (varsize < MAXSZ_NVRAM_VARS) { 892 char* new_buf; 893 new_buf = (char*)MALLOC(osh, varsize); 894 ASSERT(new_buf); 895 if (new_buf) { 896 bcopy(base, new_buf, varsize); 897 MFREE(osh, base, MAXSZ_NVRAM_VARS); 898 base = new_buf; 899 } 900 } 901 902 *vars = base; 903 *count = varsize; 904 905 return (0); 906} 907 908 909/* set PCMCIA sprom command register */ 910static int 911sprom_cmd_pcmcia(osl_t *osh, uint8 cmd) 912{ 913 uint8 status = 0; 914 uint wait_cnt = 1000; 915 916 /* write sprom command register */ 917 OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1); 918 919 /* wait status */ 920 while (wait_cnt--) { 921 OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1); 922 if (status & SROM_DONE) 923 return 0; 924 } 925 926 return 1; 927} 928 929/* read a word from the PCMCIA srom */ 930static int 931sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data) 932{ 933 uint8 addr_l, addr_h, data_l, data_h; 934 935 addr_l = (uint8)((addr * 2) & 0xff); 936 addr_h = (uint8)(((addr * 2) >> 8) & 0xff); 937 938 /* set address */ 939 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1); 940 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1); 941 942 /* do read */ 943 if (sprom_cmd_pcmcia(osh, SROM_READ)) 944 return 1; 945 946 /* read data */ 947 data_h = data_l = 0; 948 OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1); 949 OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1); 950 951 *data = (data_h << 8) | data_l; 952 return 0; 953} 954 955/* write a word to the PCMCIA srom */ 956static int 957sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data) 958{ 959 uint8 addr_l, addr_h, data_l, data_h; 960 961 addr_l = (uint8)((addr * 2) & 0xff); 962 addr_h = (uint8)(((addr * 2) >> 8) & 0xff); 963 data_l = (uint8)(data & 0xff); 964 data_h = (uint8)((data >> 8) & 0xff); 965 966 /* set address */ 967 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1); 968 OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1); 969 970 /* write data */ 971 OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1); 972 OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1); 973 974 /* do write */ 975 return sprom_cmd_pcmcia(osh, SROM_WRITE); 976} 977 978/* 979 * Read in and validate sprom. 980 * Return 0 on success, nonzero on error. 981 */ 982static int 983sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc) 984{ 985 int err = 0; 986 uint i; 987 988 /* read the sprom */ 989 for (i = 0; i < nwords; i++) { 990#ifdef BCMQT 991 buf[i] = R_REG(osh, &sprom[wordoff + i]); 992#endif 993 buf[i] = R_REG(osh, &sprom[wordoff + i]); 994 } 995 996 if (check_crc) { 997 if (buf[0] == 0xffff) { 998 /* The hardware thinks that an srom that starts with 0xffff 999 * is blank, regardless of the rest of the content, so declare 1000 * it bad. 1001 */ 1002 BS_ERROR(("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__, buf[0])); 1003 return 1; 1004 } 1005 1006 /* fixup the endianness so crc8 will pass */ 1007 htol16_buf(buf, nwords * 2); 1008 if (hndcrc8((uint8 *)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) 1009 err = 1; 1010 /* now correct the endianness of the byte array */ 1011 ltoh16_buf(buf, nwords * 2); 1012 } 1013 1014 return err; 1015} 1016 1017/* 1018* Create variable table from memory. 1019* Return 0 on success, nonzero on error. 1020*/ 1021static int 1022BCMINITFN(initvars_table)(osl_t *osh, char *start, char *end, char **vars, uint *count) 1023{ 1024 int c = (int)(end - start); 1025 1026 /* do it only when there is more than just the null string */ 1027 if (c > 1) { 1028 char *vp = MALLOC(osh, c); 1029 ASSERT(vp); 1030 if (!vp) 1031 return BCME_NOMEM; 1032 bcopy(start, vp, c); 1033 *vars = vp; 1034 *count = c; 1035 } 1036 else { 1037 *vars = NULL; 1038 *count = 0; 1039 } 1040 1041 return 0; 1042} 1043 1044/* 1045 * Find variables with <devpath> from flash. 'base' points to the beginning 1046 * of the table upon enter and to the end of the table upon exit when success. 1047 * Return 0 on success, nonzero on error. 1048 */ 1049static int 1050initvars_flash(sb_t *sbh, osl_t *osh, char **base, uint len) 1051{ 1052 char *vp = *base; 1053 char *flash; 1054 int err; 1055 char *s; 1056 uint l, dl, copy_len; 1057 char devpath[SB_DEVPATH_BUFSZ]; 1058 1059 /* allocate memory and read in flash */ 1060 if (!(flash = MALLOC(osh, NVRAM_SPACE))) 1061 return BCME_NOMEM; 1062 if ((err = nvram_getall(flash, NVRAM_SPACE))) 1063 goto exit; 1064 1065 sb_devpath(sbh, devpath, sizeof(devpath)); 1066 1067 /* grab vars with the <devpath> prefix in name */ 1068 dl = strlen(devpath); 1069 for (s = flash; s && *s; s += l + 1) { 1070 l = strlen(s); 1071 1072 /* skip non-matching variable */ 1073 if (strncmp(s, devpath, dl)) 1074 continue; 1075 1076 /* is there enough room to copy? */ 1077 copy_len = l - dl + 1; 1078 if (len < copy_len) { 1079 err = BCME_BUFTOOSHORT; 1080 goto exit; 1081 } 1082 1083 /* no prefix, just the name=value */ 1084 strncpy(vp, &s[dl], copy_len); 1085 vp += copy_len; 1086 len -= copy_len; 1087 } 1088 1089 /* add null string as terminator */ 1090 if (len < 1) { 1091 err = BCME_BUFTOOSHORT; 1092 goto exit; 1093 } 1094 *vp++ = '\0'; 1095 1096 *base = vp; 1097 1098exit: MFREE(osh, flash, NVRAM_SPACE); 1099 return err; 1100} 1101 1102#if !defined(BCMUSBDEV) 1103/* 1104 * Initialize nonvolatile variable table from flash. 1105 * Return 0 on success, nonzero on error. 1106 */ 1107static int 1108initvars_flash_sb(sb_t *sbh, char **vars, uint *count) 1109{ 1110 osl_t *osh = sb_osh(sbh); 1111 char *vp, *base; 1112 int err; 1113 1114 ASSERT(vars); 1115 ASSERT(count); 1116 1117 base = vp = MALLOC(osh, MAXSZ_NVRAM_VARS); 1118 ASSERT(vp); 1119 if (!vp) 1120 return BCME_NOMEM; 1121 1122 if ((err = initvars_flash(sbh, osh, &vp, MAXSZ_NVRAM_VARS)) == 0) 1123 err = initvars_table(osh, base, vp, vars, count); 1124 1125 MFREE(osh, base, MAXSZ_NVRAM_VARS); 1126 1127 return err; 1128} 1129#endif 1130 1131#ifdef WLTEST 1132char mfgsromvars[256]; 1133char *defaultsromvars = "il0macaddr=00:11:22:33:44:51\0" 1134 "et0macaddr=00:11:22:33:44:52\0" 1135 "et1macaddr=00:11:22:33:44:53\0" 1136 "boardtype=0xffff\0" 1137 "boardrev=0x10\0" 1138 "boardflags=8\0" 1139 "sromrev=2\0" 1140 "aa2g=3\0" 1141 "\0"; 1142#define MFGSROM_DEFVARSLEN 149 /* default srom len */ 1143#endif /* WL_TEST */ 1144 1145/* 1146 * Initialize nonvolatile variable table from sprom. 1147 * Return 0 on success, nonzero on error. 1148 */ 1149 1150typedef struct { 1151 const char *name; 1152 uint32 revmask; 1153 uint32 flags; 1154 uint16 off; 1155 uint16 mask; 1156} sromvar_t; 1157 1158#define SRFL_MORE 1 /* value continues as described by the next entry */ 1159#define SRFL_NOFFS 2 /* value bits can't be all one's */ 1160#define SRFL_PRHEX 4 /* value is in hexdecimal format */ 1161#define SRFL_PRSIGN 8 /* value is in signed decimal format */ 1162#define SRFL_CCODE 0x10 /* value is in country code format */ 1163#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ 1164#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ 1165 1166/* Assumptions: 1167 * - Ethernet address spins across 3 consective words 1168 * 1169 * Table rules: 1170 * - Add multiple entries next to each other if a value spins across multiple words 1171 * (even multiple fields in the same word) with each entry except the last having 1172 * it's SRFL_MORE bit set. 1173 * - Ethernet address entry does not follow above rule and must not have SRFL_MORE 1174 * bit set. Its SRFL_ETHADDR bit implies it takes multiple words. 1175 * - The last entry's name field must be NULL to indicate the end of the table. Other 1176 * entries must have non-NULL name. 1177 */ 1178 1179static const sromvar_t pci_sromvars[] = { 1180 {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, 1181 {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, 1182 {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, 1183 {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, 1184 {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, 1185 {"", 0, 0, SROM_BFL2, 0xffff}, 1186 {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, 1187 {"", 0, 0, SROM3_BFL2, 0xffff}, 1188 {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, 1189 {"", 0, 0, SROM4_BFL1, 0xffff}, 1190 {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, 1191 {"", 0, 0, SROM5_BFL1, 0xffff}, 1192 {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, 1193 {"", 0, 0, SROM8_BFL1, 0xffff}, 1194 {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, 1195 {"", 0, 0, SROM4_BFL3, 0xffff}, 1196 {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, 1197 {"", 0, 0, SROM5_BFL3, 0xffff}, 1198 {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, 1199 {"", 0, 0, SROM8_BFL3, 0xffff}, 1200 {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, 1201 {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, 1202 {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, 1203 {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, 1204 {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, 1205 {"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff}, 1206 {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, 1207 {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, 1208 {"regrev", 0x00000010, 0, SROM4_REGREV, 0xff}, 1209 {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xff}, 1210 {"regrev", 0xffffff00, 0, SROM8_REGREV, 0xff}, 1211 {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff}, 1212 {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, 1213 {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff}, 1214 {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, 1215 {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff}, 1216 {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, 1217 {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff}, 1218 {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, 1219 {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff}, 1220 {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, 1221 {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff}, 1222 {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, 1223 {"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff}, 1224 {"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, 1225 {"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff}, 1226 {"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, 1227 {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, 1228 {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, 1229 {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, 1230 {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0xff}, 1231 {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff}, 1232 {"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, 1233 {"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, 1234 {"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, 1235 {"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00}, 1236 {"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff}, 1237 {"opo", 0x0000000c, 0, SROM_OPO, 0xff}, 1238 {"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0xff}, 1239 {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, 1240 {"aa2g", 0x000000f0, 0, SROM4_AA, 0xff}, 1241 {"aa2g", 0xffffff00, 0, SROM8_AA, 0xff}, 1242 {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, 1243 {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, 1244 {"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00}, 1245 {"ag0", 0x0000000e, 0, SROM_AG10, 0xff}, 1246 {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, 1247 {"ag0", 0x000000f0, 0, SROM4_AG10, 0xff}, 1248 {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, 1249 {"ag2", 0x000000f0, 0, SROM4_AG32, 0xff}, 1250 {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, 1251 {"ag0", 0xffffff00, 0, SROM8_AG10, 0xff}, 1252 {"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00}, 1253 {"ag2", 0xffffff00, 0, SROM8_AG32, 0xff}, 1254 {"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00}, 1255 {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, 1256 {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, 1257 {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, 1258 {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, 1259 {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, 1260 {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, 1261 {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, 1262 {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, 1263 {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, 1264 {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, 1265 {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, 1266 {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, 1267 {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff}, 1268 {"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, 1269 {"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, 1270 {"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, 1271 {"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, 1272 {"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, 1273 {"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, 1274 {"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, 1275 {"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, 1276 {"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, 1277 {"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00}, 1278 {"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff}, 1279 {"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00}, 1280 {"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff}, 1281 {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, 1282 {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, 1283 {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, 1284 {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, 1285 {"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800}, 1286 {"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700}, 1287 {"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0}, 1288 {"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f}, 1289 {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, 1290 {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, 1291 {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, 1292 {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, 1293 {"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800}, 1294 {"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700}, 1295 {"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0}, 1296 {"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f}, 1297 {"tri2g", 0x00000008, 0, SROM_TRI52G, 0xff}, 1298 {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, 1299 {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0xff}, 1300 {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, 1301 {"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0xff}, 1302 {"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00}, 1303 {"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0xff}, 1304 {"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00}, 1305 {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff}, 1306 {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, 1307 {"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff}, 1308 {"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, 1309 {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, 1310 {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, 1311 {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, 1312 {"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, 1313 {"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, 1314 {"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, 1315 {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0xff}, 1316 {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, 1317 {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff}, 1318 {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, 1319 {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0xff}, 1320 {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, 1321 {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff}, 1322 {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, 1323 {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0xff}, 1324 {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, 1325 {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff}, 1326 {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, 1327 {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0xff}, 1328 {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, 1329 {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff}, 1330 {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, 1331 {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, 1332 {"cck2gpo", 0xffffff00, 0, SROM8_2G_CCKPO, 0xffff}, 1333 {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, 1334 {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, 1335 {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, 1336 {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, 1337 {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, 1338 {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, 1339 {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, 1340 {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, 1341 {"ofdm2gpo", 0xffffff00, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, 1342 {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, 1343 {"ofdm5gpo", 0xffffff00, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, 1344 {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, 1345 {"ofdm5glpo", 0xffffff00, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, 1346 {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, 1347 {"ofdm5ghpo", 0xffffff00, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, 1348 {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, 1349 {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, 1350 {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, 1351 {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, 1352 {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, 1353 {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, 1354 {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, 1355 {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, 1356 {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, 1357 {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, 1358 {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, 1359 {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, 1360 {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, 1361 {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, 1362 {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, 1363 {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, 1364 {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, 1365 {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, 1366 {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, 1367 {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, 1368 {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, 1369 {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, 1370 {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, 1371 {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, 1372 {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, 1373 {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, 1374 {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, 1375 {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, 1376 {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, 1377 {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, 1378 {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, 1379 {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, 1380 {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, 1381 {"mcs2gpo0", 0xffffff00, 0, SROM8_2G_MCSPO, 0xffff}, 1382 {"mcs2gpo1", 0xffffff00, 0, SROM8_2G_MCSPO + 1, 0xffff}, 1383 {"mcs2gpo2", 0xffffff00, 0, SROM8_2G_MCSPO + 2, 0xffff}, 1384 {"mcs2gpo3", 0xffffff00, 0, SROM8_2G_MCSPO + 3, 0xffff}, 1385 {"mcs2gpo4", 0xffffff00, 0, SROM8_2G_MCSPO + 4, 0xffff}, 1386 {"mcs2gpo5", 0xffffff00, 0, SROM8_2G_MCSPO + 5, 0xffff}, 1387 {"mcs2gpo6", 0xffffff00, 0, SROM8_2G_MCSPO + 6, 0xffff}, 1388 {"mcs2gpo7", 0xffffff00, 0, SROM8_2G_MCSPO + 7, 0xffff}, 1389 {"mcs5gpo0", 0xffffff00, 0, SROM8_5G_MCSPO, 0xffff}, 1390 {"mcs5gpo1", 0xffffff00, 0, SROM8_5G_MCSPO + 1, 0xffff}, 1391 {"mcs5gpo2", 0xffffff00, 0, SROM8_5G_MCSPO + 2, 0xffff}, 1392 {"mcs5gpo3", 0xffffff00, 0, SROM8_5G_MCSPO + 3, 0xffff}, 1393 {"mcs5gpo4", 0xffffff00, 0, SROM8_5G_MCSPO + 4, 0xffff}, 1394 {"mcs5gpo5", 0xffffff00, 0, SROM8_5G_MCSPO + 5, 0xffff}, 1395 {"mcs5gpo6", 0xffffff00, 0, SROM8_5G_MCSPO + 6, 0xffff}, 1396 {"mcs5gpo7", 0xffffff00, 0, SROM8_5G_MCSPO + 7, 0xffff}, 1397 {"mcs5glpo0", 0xffffff00, 0, SROM8_5GL_MCSPO, 0xffff}, 1398 {"mcs5glpo1", 0xffffff00, 0, SROM8_5GL_MCSPO + 1, 0xffff}, 1399 {"mcs5glpo2", 0xffffff00, 0, SROM8_5GL_MCSPO + 2, 0xffff}, 1400 {"mcs5glpo3", 0xffffff00, 0, SROM8_5GL_MCSPO + 3, 0xffff}, 1401 {"mcs5glpo4", 0xffffff00, 0, SROM8_5GL_MCSPO + 4, 0xffff}, 1402 {"mcs5glpo5", 0xffffff00, 0, SROM8_5GL_MCSPO + 5, 0xffff}, 1403 {"mcs5glpo6", 0xffffff00, 0, SROM8_5GL_MCSPO + 6, 0xffff}, 1404 {"mcs5glpo7", 0xffffff00, 0, SROM8_5GL_MCSPO + 7, 0xffff}, 1405 {"mcs5ghpo0", 0xffffff00, 0, SROM8_5GH_MCSPO, 0xffff}, 1406 {"mcs5ghpo1", 0xffffff00, 0, SROM8_5GH_MCSPO + 1, 0xffff}, 1407 {"mcs5ghpo2", 0xffffff00, 0, SROM8_5GH_MCSPO + 2, 0xffff}, 1408 {"mcs5ghpo3", 0xffffff00, 0, SROM8_5GH_MCSPO + 3, 0xffff}, 1409 {"mcs5ghpo4", 0xffffff00, 0, SROM8_5GH_MCSPO + 4, 0xffff}, 1410 {"mcs5ghpo5", 0xffffff00, 0, SROM8_5GH_MCSPO + 5, 0xffff}, 1411 {"mcs5ghpo6", 0xffffff00, 0, SROM8_5GH_MCSPO + 6, 0xffff}, 1412 {"mcs5ghpo7", 0xffffff00, 0, SROM8_5GH_MCSPO + 7, 0xffff}, 1413 {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, 1414 {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, 1415 {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, 1416 {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, 1417 {"cddpo", 0xffffff00, 0, SROM8_CDDPO, 0xffff}, 1418 {"stbcpo", 0xffffff00, 0, SROM8_STBCPO, 0xffff}, 1419 {"bw40po", 0xffffff00, 0, SROM8_BW40PO, 0xffff}, 1420 {"bwduppo", 0xffffff00, 0, SROM8_BWDUPPO, 0xffff}, 1421 {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, 1422 {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, 1423 {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, 1424 {"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff}, 1425 {"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, 1426 {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, 1427 {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, 1428 {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, 1429 {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, 1430 {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, 1431 {"leddc", 0xffffff00, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff}, 1432 {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff}, 1433 {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff}, 1434 {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff}, 1435 {NULL, 0, 0, 0, 0} 1436}; 1437 1438static const sromvar_t perpath_pci_sromvars[] = { 1439 {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff}, 1440 {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, 1441 {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, 1442 {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, 1443 {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, 1444 {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, 1445 {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, 1446 {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff}, 1447 {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff}, 1448 {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, 1449 {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, 1450 {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, 1451 {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, 1452 {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, 1453 {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, 1454 {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, 1455 {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, 1456 {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, 1457 {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, 1458 {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, 1459 {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, 1460 {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, 1461 {"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff}, 1462 {"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00}, 1463 {"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00}, 1464 {"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, 1465 {"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, 1466 {"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, 1467 {"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff}, 1468 {"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff}, 1469 {"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00}, 1470 {"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, 1471 {"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, 1472 {"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, 1473 {"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, 1474 {"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, 1475 {"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, 1476 {"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, 1477 {"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, 1478 {"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, 1479 {NULL, 0, 0, 0, 0} 1480}; 1481 1482/* Parse SROM and create name=value pairs. 'srom' points to 1483 * the SROM word array. 'off' specifies the offset of the 1484 * first word 'srom' points to, which should be either 0 or 1485 * SROM3_SWRG_OFF (full SROM or software region). 1486 */ 1487 1488static uint 1489mask_shift(uint16 mask) 1490{ 1491 uint i; 1492 for (i = 0; i < (sizeof(mask) << 3); i ++) { 1493 if (mask & (1 << i)) 1494 return i; 1495 } 1496 ASSERT(mask); 1497 return 0; 1498} 1499 1500static uint 1501mask_width(uint16 mask) 1502{ 1503 int i; 1504 for (i = (sizeof(mask) << 3) - 1; i >= 0; i --) { 1505 if (mask & (1 << i)) 1506 return (uint)(i - mask_shift(mask) + 1); 1507 } 1508 ASSERT(mask); 1509 return 0; 1510} 1511 1512#ifdef BCMDBG_ASSERT 1513static bool 1514mask_valid(uint16 mask) 1515{ 1516 uint shift = mask_shift(mask); 1517 uint width = mask_width(mask); 1518 return mask == ((~0 << shift) & ~(~0 << (shift + width))); 1519} 1520#endif 1521 1522static void 1523_initvars_srom_pci(uint8 sromrev, uint16 *srom, uint off, varbuf_t *b) 1524{ 1525 uint16 w; 1526 uint32 val; 1527 const sromvar_t *srv; 1528 uint width; 1529 uint flags; 1530 uint32 sr = (1 << sromrev); 1531 1532 varbuf_append(b, "sromrev=%d", sromrev); 1533 1534 for (srv = pci_sromvars; srv->name != NULL; srv ++) { 1535 const char *name; 1536 1537 if ((srv->revmask & sr) == 0) 1538 continue; 1539 1540 if (srv->off < off) 1541 continue; 1542 1543 flags = srv->flags; 1544 name = srv->name; 1545 1546 if (flags & SRFL_ETHADDR) { 1547 char eabuf[ETHER_ADDR_STR_LEN]; 1548 struct ether_addr ea; 1549 1550 ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff; 1551 ea.octet[1] = srom[srv->off - off] & 0xff; 1552 ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff; 1553 ea.octet[3] = srom[srv->off + 1 - off] & 0xff; 1554 ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff; 1555 ea.octet[5] = srom[srv->off + 2 - off] & 0xff; 1556 bcm_ether_ntoa(&ea, eabuf); 1557 1558 varbuf_append(b, "%s=%s", name, eabuf); 1559 } 1560 else { 1561 ASSERT(mask_valid(srv->mask)); 1562 ASSERT(mask_width(srv->mask)); 1563 1564 w = srom[srv->off - off]; 1565 val = (w & srv->mask) >> mask_shift(srv->mask); 1566 width = mask_width(srv->mask); 1567 1568 while (srv->flags & SRFL_MORE) { 1569 srv ++; 1570 ASSERT(srv->name); 1571 1572 if (srv->off == 0 || srv->off < off) 1573 continue; 1574 1575 ASSERT(mask_valid(srv->mask)); 1576 ASSERT(mask_width(srv->mask)); 1577 1578 w = srom[srv->off - off]; 1579 val += ((w & srv->mask) >> mask_shift(srv->mask)) << width; 1580 width += mask_width(srv->mask); 1581 } 1582 1583 if ((flags & SRFL_NOFFS) && ((int)val == (1 << width) - 1)) 1584 continue; 1585 1586 if (flags & SRFL_CCODE) { 1587 if (val == 0) 1588 varbuf_append(b, "ccode="); 1589 else 1590 varbuf_append(b, "ccode=%c%c", (val >> 8), (val & 0xff)); 1591 } 1592 /* LED Powersave duty cycle has to be scaled: 1593 *(oncount >> 24) (offcount >> 8) 1594 */ 1595 else if (flags & SRFL_LEDDC) { 1596 uint32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */ 1597 (((val & 0xff)) << 8); /* offcount */ 1598 varbuf_append(b, "leddc=%d", w32); 1599 } 1600 else if (flags & SRFL_PRHEX) 1601 varbuf_append(b, "%s=0x%x", name, val); 1602 else if ((flags & SRFL_PRSIGN) && (val & (1 << (width - 1)))) 1603 varbuf_append(b, "%s=%d", name, (int)(val | (~0 << width))); 1604 else 1605 varbuf_append(b, "%s=%u", name, val); 1606 } 1607 } 1608 1609 if (sromrev >= 4) { 1610 /* Do per-path variables */ 1611 uint p, pb, psz; 1612 1613 if (sromrev >= 8) { 1614 pb = SROM8_PATH0; 1615 psz = SROM8_PATH1 - SROM8_PATH0; 1616 } else { 1617 pb = SROM4_PATH0; 1618 psz = SROM4_PATH1 - SROM4_PATH0; 1619 } 1620 1621 for (p = 0; p < MAX_PATH; p++) { 1622 for (srv = perpath_pci_sromvars; srv->name != NULL; srv ++) { 1623 if ((srv->revmask & sr) == 0) 1624 continue; 1625 1626 if (pb + srv->off < off) 1627 continue; 1628 1629 w = srom[pb + srv->off - off]; 1630 ASSERT(mask_valid(srv->mask)); 1631 val = (w & srv->mask) >> mask_shift(srv->mask); 1632 width = mask_width(srv->mask); 1633 1634 /* Cheating: no per-path var is more than 1 word */ 1635 1636 if ((srv->flags & SRFL_NOFFS) && ((int)val == (1 << width) - 1)) 1637 continue; 1638 1639 if (srv->flags & SRFL_PRHEX) 1640 varbuf_append(b, "%s%d=0x%x", srv->name, p, val); 1641 else 1642 varbuf_append(b, "%s%d=%d", srv->name, p, val); 1643 } 1644 pb += psz; 1645 } 1646 } 1647} 1648 1649static int 1650initvars_srom_pci(sb_t *sbh, void *curmap, char **vars, uint *count) 1651{ 1652 uint16 *srom; 1653 uint8 sromrev = 0; 1654 uint32 sr; 1655 varbuf_t b; 1656 char *vp, *base = NULL; 1657 osl_t *osh = sb_osh(sbh); 1658 bool flash = FALSE; 1659 char *value; 1660 int err; 1661 1662 /* 1663 * Apply CRC over SROM content regardless SROM is present or not, 1664 * and use variable <devpath>sromrev's existance in flash to decide 1665 * if we should return an error when CRC fails or read SROM variables 1666 * from flash. 1667 */ 1668 srom = MALLOC(osh, SROM_MAX); 1669 ASSERT(srom); 1670 if (!srom) 1671 return -2; 1672 1673 err = sprom_read_pci(osh, (void *)((int8 *)curmap + PCI_BAR0_SPROM_OFFSET), 0, srom, 1674 SROM_WORDS, TRUE); 1675 1676 if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) || 1677 ((sbh->buscoretype == SB_PCIE) && (sbh->buscorerev >= 6))) { 1678 /* sromrev >= 4, read more */ 1679 err = sprom_read_pci(osh, (void *)((int8 *)curmap + PCI_BAR0_SPROM_OFFSET), 0, 1680 srom, SROM4_WORDS, TRUE); 1681 sromrev = srom[SROM4_CRCREV] & 0xff; 1682 } else if (err == 0) { 1683 /* srom is good and is rev < 4 */ 1684 /* top word of sprom contains version and crc8 */ 1685 sromrev = srom[SROM_CRCREV] & 0xff; 1686 /* bcm4401 sroms misprogrammed */ 1687 if (sromrev == 0x10) 1688 sromrev = 1; 1689 } 1690 1691 if (err) { 1692#ifdef WLTEST 1693 uint32 val; 1694 1695 BS_ERROR(("SROM Crc Error, so see if we could use a default\n")); 1696 val = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); 1697 if (val & SPROM_OTPIN_USE) { 1698 BS_ERROR(("srom crc failed with OTP, use default vars....\n")); 1699 vp = base = mfgsromvars; 1700 if (sb_chip(sbh) == BCM4311_CHIP_ID) { 1701 const char *devid = "devid=0x4311"; 1702 const size_t devid_strlen = strlen(devid); 1703 BS_ERROR(("setting the devid to be 4311\n")); 1704 bcopy(devid, vp, devid_strlen + 1); 1705 vp += devid_strlen + 1; 1706 } 1707 bcopy(defaultsromvars, vp, MFGSROM_DEFVARSLEN); 1708 vp += MFGSROM_DEFVARSLEN; 1709 goto varsdone; 1710 } else { 1711#endif /* WLTEST */ 1712 BS_ERROR(("srom crc failed with SPROM....\n")); 1713 if (!(value = sb_getdevpathvar(sbh, "sromrev"))) { 1714 err = -1; 1715 goto errout; 1716 } 1717 sromrev = (uint8)bcm_strtoul(value, NULL, 0); 1718 flash = TRUE; 1719#ifdef WLTEST 1720 } 1721#endif /* WLTEST */ 1722 } 1723 1724 /* Bitmask for the sromrev */ 1725 sr = 1 << sromrev; 1726 1727 /* srom version check 1728 * Current valid versions: 1, 2, 3, 4, 5, 8 1729 */ 1730 if ((sr & 0x13e) == 0) { 1731 err = -2; 1732 goto errout; 1733 } 1734 1735 ASSERT(vars); 1736 ASSERT(count); 1737 1738 base = vp = MALLOC(osh, MAXSZ_NVRAM_VARS); 1739 ASSERT(vp); 1740 if (!vp) { 1741 err = -2; 1742 goto errout; 1743 } 1744 1745 /* read variables from flash */ 1746 if (flash) { 1747 if ((err = initvars_flash(sbh, osh, &vp, MAXSZ_NVRAM_VARS))) 1748 goto errout; 1749 goto varsdone; 1750 } 1751 1752 varbuf_init(&b, base, MAXSZ_NVRAM_VARS); 1753 1754 /* parse SROM into name=value pairs. */ 1755 _initvars_srom_pci(sromrev, srom, 0, &b); 1756 1757 /* final nullbyte terminator */ 1758 ASSERT(b.size >= 1); 1759 vp = b.buf; 1760 *vp++ = '\0'; 1761 1762 ASSERT((vp - base) <= MAXSZ_NVRAM_VARS); 1763 1764varsdone: 1765 err = initvars_table(osh, base, vp, vars, count); 1766 1767errout: 1768#ifdef WLTEST 1769 if (base && (base != mfgsromvars)) 1770#else 1771 if (base) 1772#endif 1773 MFREE(osh, base, MAXSZ_NVRAM_VARS); 1774 1775 MFREE(osh, srom, SROM_MAX); 1776 return err; 1777} 1778 1779/* 1780 * Read the cis and call parsecis to initialize the vars. 1781 * Return 0 on success, nonzero on error. 1782 */ 1783static int 1784initvars_cis_pcmcia(sb_t *sbh, osl_t *osh, char **vars, uint *count) 1785{ 1786 uint8 *cis = NULL; 1787 int rc; 1788 uint data_sz; 1789 1790 data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE; 1791 1792 if ((cis = MALLOC(osh, data_sz)) == NULL) 1793 return (-2); 1794 1795 if (sb_pcmciarev(sbh) == 1) { 1796 if (srom_read(sbh, PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) { 1797 MFREE(osh, cis, data_sz); 1798 return (-1); 1799 } 1800 /* fix up endianess for 16-bit data vs 8-bit parsing */ 1801 htol16_buf((uint16 *)cis, data_sz); 1802 } else 1803 OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz); 1804 1805 rc = srom_parsecis(osh, &cis, 1, vars, count); 1806 1807 MFREE(osh, cis, data_sz); 1808 1809 return (rc); 1810} 1811 1812 1813static int 1814BCMINITFN(initvars_srom_sb)(sb_t *sbh, osl_t *osh, void *curmap, char **vars, uint *varsz) 1815{ 1816#if defined(BCMUSBDEV) 1817 static bool srvars = FALSE; /* Use OTP/SPROM as global variables */ 1818 1819 int sel = 0; /* where to read the srom. 0 - nowhere, 1 - otp, 2 - sprom */ 1820 uint sz = 0; /* srom size in bytes */ 1821 void *oh = NULL; 1822 int rc = BCME_OK; 1823 1824 /* Bail out if we've dealt with OTP/SPROM before! */ 1825 if (srvars) 1826 return 0; 1827 1828#if defined(BCM4328) 1829 if (sbh->chip == BCM4328_CHIP_ID) { 1830 /* Access the SPROM if it is present */ 1831 if ((sz = srom_size(sbh, osh)) != 0) { 1832 sz <<= 1; 1833 sel = 2; 1834 } 1835 } 1836#endif 1837#if defined(BCM4325) 1838 if (sbh->chip == BCM4325_CHIP_ID) { 1839 uint32 cst = sbh->chipst & CST4325_SPROM_OTP_SEL_MASK; 1840 1841 /* Access OTP if it is present, powered on, and programmed */ 1842 if ((oh = otp_init(sbh)) != NULL && (otp_status(oh) & OTPS_GUP_SW)) { 1843 sz = otp_size(oh); 1844 sel = 1; 1845 } 1846 /* Access the SPROM if it is present and allow to be accessed */ 1847 else if ((cst == CST4325_OTP_PWRDN || cst == CST4325_SPROM_SEL) && 1848 (sz = srom_size(sbh, osh)) != 0) { 1849 sz <<= 1; 1850 sel = 2; 1851 } 1852 } 1853#endif /* BCM4325 */ 1854 1855 /* Read CIS in OTP/SPROM */ 1856 if (sel != 0) { 1857 uint16 *srom; 1858 uint8 *body = NULL; 1859 1860 ASSERT(sz); 1861 1862 /* Allocate memory */ 1863 if ((srom = (uint16 *)MALLOC(osh, sz)) == NULL) 1864 return BCME_NOMEM; 1865 1866 /* Read CIS */ 1867 switch (sel) { 1868 case 1: 1869 rc = otp_read_region(oh, OTP_SW_RGN, srom, sz); 1870 body = (uint8 *)srom; 1871 break; 1872 case 2: 1873 rc = srom_read(sbh, SB_BUS, curmap, osh, 0, sz, srom); 1874 /* sprom has 8 byte h/w header */ 1875 body = (uint8 *)srom + SBSDIO_SPROM_CIS_OFFSET; 1876 break; 1877 default: 1878 /* impossible to come here */ 1879 ASSERT(0); 1880 break; 1881 } 1882 1883 /* Parse CIS */ 1884 if (rc == BCME_OK) { 1885 uint i, tpls = 0xffffffff; 1886 /* # sdiod fns + common + extra */ 1887 uint8 *cis[SBSDIO_NUM_FUNCTION + 2]; 1888 uint ciss = 0; 1889 1890 /* each word is in host endian */ 1891 htol16_buf((uint8 *)srom, sz); 1892 1893 ASSERT(body); 1894 1895 /* count cis tuple chains */ 1896 for (i = 0; i < sz && ciss < ARRAYSIZE(cis) && tpls != 0; i ++) { 1897 cis[ciss++] = &body[i]; 1898 for (tpls = 0; i < sz - 1; tpls ++) { 1899 if (body[i++] == CISTPL_END) 1900 break; 1901 i += body[i] + 1; 1902 } 1903 } 1904 1905 /* call parser routine only when there are tuple chains */ 1906 if (ciss > 1) 1907 rc = srom_parsecis(osh, cis, ciss, vars, varsz); 1908 } 1909 1910 /* Clean up */ 1911 MFREE(osh, srom, sz); 1912 1913 /* Make SROM variables global */ 1914 if (rc == BCME_OK) { 1915 rc = nvram_append((void *)sbh, *vars, *varsz); 1916 srvars = TRUE; 1917 1918 /* Tell the caller there is no individual SROM variables */ 1919 *vars = NULL; 1920 *varsz = 0; 1921 } 1922 } 1923 1924 return rc; 1925#else /* !BCMUSBDEV && !BCMSDIODEV */ 1926 /* Search flash nvram section for srom variables */ 1927 return initvars_flash_sb(sbh, vars, varsz); 1928#endif 1929} 1930 1931#ifdef BCMUSBDEV 1932/* Return sprom size in 16-bit words */ 1933static uint 1934srom_size(sb_t *sbh, osl_t *osh) 1935{ 1936 uint size = 0; 1937 if (SPROMBUS == PCMCIA_BUS) { 1938 uint32 origidx; 1939 sdpcmd_regs_t *pcmregs; 1940 bool wasup; 1941 1942 origidx = sb_coreidx(sbh); 1943 pcmregs = sb_setcore(sbh, SB_PCMCIA, 0); 1944 ASSERT(pcmregs); 1945 1946 if (!(wasup = sb_iscoreup(sbh))) 1947 sb_core_reset(sbh, 0, 0); 1948 1949 /* not worry about earlier core revs */ 1950 if (sb_corerev(sbh) < 8) 1951 goto done; 1952 1953 /* SPROM is accessible only in PCMCIA mode unless there is SDIO clock */ 1954 if (!(R_REG(osh, &pcmregs->corestatus) & CS_PCMCIAMODE)) 1955 goto done; 1956 1957 switch (SB_PCMCIA_READ(osh, pcmregs, SROM_INFO) & SRI_SZ_MASK) { 1958 case 1: 1959 size = 256; /* SROM_INFO == 1 means 4kbit */ 1960 break; 1961 case 2: 1962 size = 1024; /* SROM_INFO == 2 means 16kbit */ 1963 break; 1964 default: 1965 break; 1966 } 1967 1968 done: 1969 if (!wasup) 1970 sb_core_disable(sbh, 0); 1971 1972 sb_setcoreidx(sbh, origidx); 1973 } 1974 return size; 1975} 1976#endif /* def BCMUSBDEV */ 1977