1/* 2 * Write-once support for IPX OTP wrapper. 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 * 12 * $Id: bcmotp.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $ 13 */ 14 15#include <typedefs.h> 16#include <bcmdefs.h> 17#include <osl.h> 18#include <bcmdevs.h> 19#include <bcmutils.h> 20#include <sbutils.h> 21#include <bcmendian.h> 22#include <sbconfig.h> 23#include <sbchipc.h> 24#include <bcmotp.h> 25 26/* debug/trace */ 27#define OTP_MSG(x) 28 29 30#if !defined(BCMHNDOTP) /* Newer IPX OTP wrapper */ 31 32/* OTP layout */ 33/* Subregion word offsets in General Use region */ 34#define OTPGU_HSB_OFF 12 35#define OTPGU_SFB_OFF 13 36#define OTPGU_CI_OFF 14 37#define OTPGU_SROM_OFF 16 38 39/* Fixed size subregions sizes in words */ 40#define OTPGU_CI_SZ 2 41 42/* Flag bit offsets in General Use region */ 43#define OTPGU_HWP_OFF 252 44#define OTPGU_SWP_OFF 253 45#define OTPGU_CIP_OFF 254 46#define OTPGU_FUSEP_OFF 255 47 48typedef struct { 49 sb_t *sbh; /* Saved sb handle */ 50 osl_t *osh; 51 uint16 size; /* Size of otp in words */ 52 uint16 rows; 53 uint16 cols; 54 uint16 hwprot; /* Hardware protection bits */ 55 uint16 prog; /* Subregion programmed bits */ 56 uint16 hwbase; /* hardware subregion offset */ 57 uint16 hwlim; /* hardware subregion boundary */ 58 uint16 swbase; /* software subregion offset */ 59 uint16 swlim; /* software subregion boundary */ 60 uint16 fbase; /* fuse subregion offset */ 61 uint16 flim; /* fuse subregion boundary */ 62} otpinfo_t; 63 64static otpinfo_t otpinfo; 65 66#define OTPP_TRIES 10000000 /* # of tries for OTPP */ 67 68static void 69otp_rgn(otpinfo_t *oi, chipcregs_t *cc) 70{ 71 /* Read OTP lock bits and subregion programmed indication bits */ 72 oi->hwprot = (uint16)(R_REG(oi->osh, &cc->otpstatus) & OTPS_OL_MASK); 73 oi->prog = (uint16)(R_REG(oi->osh, &cc->otpstatus) & OTPS_GUP_MASK); 74 OTP_MSG(("otp_rgn: hwprot %x prog %x\n", oi->hwprot, oi->prog)); 75 76 /* 77 * h/w region base and fuse region limit are fixed to the top and 78 * the bottom of the general use region. Everything else can be flexible. 79 */ 80 oi->hwbase = OTPGU_SROM_OFF; 81 oi->hwlim = oi->size; 82 if (oi->prog & OTPS_GUP_HW) { 83 oi->hwlim = otpr(oi, cc, OTPGU_HSB_OFF) / 16; 84 oi->swbase = oi->hwlim; 85 } 86 else 87 oi->swbase = oi->hwbase; 88 OTP_MSG(("otp_rgn: hwbase %x hwlim %x\n", oi->hwbase, oi->hwlim)); 89 oi->swlim = oi->size; 90 if (oi->prog & OTPS_GUP_SW) { 91 oi->swlim = otpr(oi, cc, OTPGU_SFB_OFF) / 16; 92 oi->fbase = oi->swlim; 93 } 94 else 95 oi->fbase = oi->swbase; 96 OTP_MSG(("otp_rgn: swbase %x swlim %x\n", oi->swbase, oi->swlim)); 97 oi->flim = oi->size; 98 OTP_MSG(("otp_rgn: fbase %x flim %x\n", oi->fbase, oi->flim)); 99} 100 101void * 102otp_init(sb_t *sbh) 103{ 104 uint idx; 105 chipcregs_t *cc; 106 otpinfo_t *oi; 107 108 /* chipc corerev must be >= 21 */ 109 if (sbh->ccrev < 21) 110 return NULL; 111 112 oi = &otpinfo; 113 bzero(oi, sizeof(otpinfo_t)); 114 115 oi->sbh = sbh; 116 oi->osh = sb_osh(sbh); 117 118 /* Check for otp size */ 119 switch ((sbh->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) { 120 case 0: 121 /* Nothing there */ 122 OTP_MSG(("%s: no OTP\n", __FUNCTION__)); 123 return NULL; 124 case 1: /* 32x64 */ 125 oi->rows = 32; 126 oi->cols = 64; 127 oi->size = 128; 128 OTP_MSG(("otp_init: rows %u cols %u\n", oi->rows, oi->cols)); 129 break; 130 default: 131 /* Don't know the geometry */ 132 OTP_MSG(("%s: unknown OTP geometry\n", __FUNCTION__)); 133 return NULL; 134 } 135 136 /* Retrieve OTP region info */ 137 idx = sb_coreidx(sbh); 138 cc = sb_setcore(sbh, SB_CC, 0); 139 ASSERT(cc); 140 141 switch (sbh->chip) { 142#if defined(BCM4325) 143 case BCM4325_CHIP_ID: 144 if ((sbh->chipst & CST4325_SPROM_OTP_SEL_MASK) == CST4325_OTP_PWRDN) { 145 OTP_MSG(("%s: OTP is strapped down\n", __FUNCTION__)); 146 oi = NULL; 147 goto exit; 148 } 149 if (!(R_REG(oi->osh, &cc->min_res_mask) & PMURES_BIT(RES4325_LNLDO2_PU))) { 150 OTP_MSG(("%s: OTP is powered down\n", __FUNCTION__)); 151 oi = NULL; 152 goto exit; 153 } 154 break; 155#endif /* BCM4325 */ 156 default: 157 break; 158 } 159 160 otp_rgn(oi, cc); 161 162 goto exit; 163exit: 164 sb_setcoreidx(sbh, idx); 165 166 return (void *)oi; 167} 168 169uint16 170otpr(void *oh, chipcregs_t *cc, uint wn) 171{ 172 otpinfo_t *oi; 173 174 oi = (otpinfo_t *)oh; 175 176 ASSERT(wn < oi->size); 177 ASSERT(cc); 178 179 return R_REG(oi->osh, &cc->otp[wn]); 180} 181 182int 183otp_read_region(void *oh, int region, uint16 *data, uint wlen) 184{ 185 otpinfo_t *oi = (otpinfo_t *)oh; 186 uint idx; 187 chipcregs_t *cc; 188 uint base, i, sz; 189 190 /* Validate region selection */ 191 switch (region) { 192 case OTP_HW_RGN: 193 if (!(oi->prog & OTPS_GUP_HW)) { 194 OTP_MSG(("%s: h/w region not programmed\n", __FUNCTION__)); 195 return -1; 196 } 197 if (wlen < (sz = (uint)oi->hwlim - oi->hwbase)) { 198 OTP_MSG(("%s: buffer too small, should be at least %u\n", 199 __FUNCTION__, oi->hwlim - oi->hwbase)); 200 return -1; 201 } 202 base = oi->hwbase; 203 break; 204 case OTP_SW_RGN: 205 if (!(oi->prog & OTPS_GUP_SW)) { 206 OTP_MSG(("%s: s/w region not programmed\n", __FUNCTION__)); 207 return -1; 208 } 209 if (wlen < (sz = (uint)oi->swlim - oi->swbase)) { 210 OTP_MSG(("%s: buffer too small should be at least %u\n", 211 __FUNCTION__, oi->swlim - oi->swbase)); 212 return -1; 213 } 214 base = oi->swbase; 215 break; 216 case OTP_CI_RGN: 217 if (!(oi->prog & OTPS_GUP_CI)) { 218 OTP_MSG(("%s: chipid region not programmed\n", __FUNCTION__)); 219 return -1; 220 } 221 if (wlen < (sz = OTPGU_CI_SZ)) { 222 OTP_MSG(("%s: buffer too small, should be at least %u\n", 223 __FUNCTION__, OTPGU_CI_SZ)); 224 return -1; 225 } 226 base = OTPGU_CI_OFF; 227 break; 228 case OTP_FUSE_RGN: 229 if (!(oi->prog & OTPS_GUP_FUSE)) { 230 OTP_MSG(("%s: fuse region not programmed\n", __FUNCTION__)); 231 return -1; 232 } 233 if (wlen < (sz = (uint)oi->flim - oi->fbase)) { 234 OTP_MSG(("%s: buffer too small, should be at least %u\n", 235 __FUNCTION__, oi->flim - oi->fbase)); 236 return -1; 237 } 238 base = oi->fbase; 239 break; 240 default: 241 OTP_MSG(("%s: reading region %d is not supported\n", __FUNCTION__, region)); 242 return -1; 243 } 244 245 idx = sb_coreidx(oi->sbh); 246 cc = sb_setcore(oi->sbh, SB_CC, 0); 247 248 /* Read the data */ 249 for (i = 0; i < sz; i ++) 250 data[i] = otpr(oh, cc, base + i); 251 252 sb_setcoreidx(oi->sbh, idx); 253 return 0; 254} 255 256int 257otp_status(void *oh) 258{ 259 otpinfo_t *oi = (otpinfo_t *)oh; 260 return (int)(oi->hwprot | oi->prog); 261} 262 263int 264otp_size(void *oh) 265{ 266 otpinfo_t *oi = (otpinfo_t *)oh; 267 return (int)oi->size * 2; 268} 269 270int 271otp_nvread(void *oh, char *data, uint *len) 272{ 273 return -1; 274} 275 276#ifdef BCMNVRAMW 277static int 278otp_write_bit(otpinfo_t *oi, chipcregs_t *cc, uint idx) 279{ 280 uint k, row, col; 281 uint32 otpp, st; 282 283 row = idx / oi->cols; 284 col = idx % oi->cols; 285 286 otpp = OTPP_START_BUSY | 287 ((1 << OTPP_VALUE_SHIFT) & OTPP_VALUE_MASK) | 288 ((OTPPOC_BIT_PROG << OTPP_OC_SHIFT) & OTPP_OC_MASK) | 289 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) | 290 ((col << OTPP_COL_SHIFT) & OTPP_COL_MASK); 291 OTP_MSG(("%s: idx = %d, row = %d, col = %d, otpp = 0x%x\n", 292 __FUNCTION__, idx, row, col, otpp)); 293 W_REG(oi->osh, &cc->otpprog, otpp); 294 295 for (k = 0; 296 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY) && (k < OTPP_TRIES); 297 k ++) 298 ; 299 if (k >= OTPP_TRIES) { 300 OTP_MSG(("\n%s: BUSY stuck: st=0x%x, count=%d\n", __FUNCTION__, st, k)); 301 return -1; 302 } 303 304 return 0; 305} 306 307static int 308otpwb16(otpinfo_t *oi, chipcregs_t *cc, int wn, uint16 data) 309{ 310 uint base, i; 311 int rc; 312 313 base = wn * 16; 314 for (i = 0; i < 16; i++) { 315 if (data & (1 << i)) { 316 if ((rc = otp_write_bit(oi, cc, base + i))) 317 return rc; 318 } 319 } 320 321 return 0; 322} 323 324/* expects the caller to disable interrupts before calling this routine */ 325int 326otp_write_region(void *oh, int region, uint16 *data, uint wlen) 327{ 328 otpinfo_t *oi = (otpinfo_t *)oh; 329 uint idx; 330 chipcregs_t *cc; 331 uint base, i; 332 333 /* Validate region selection */ 334 switch (region) { 335 case OTP_HW_RGN: 336 if (oi->prog & OTPS_GUP_HW) { 337 OTP_MSG(("%s: h/w region has been programmed\n", __FUNCTION__)); 338 return -1; 339 } 340 if (wlen > (uint)(oi->hwlim - oi->hwbase)) { 341 OTP_MSG(("%s: wlen %u exceeds OTP h/w region limit %u\n", 342 __FUNCTION__, wlen, oi->hwlim - oi->hwbase)); 343 return -1; 344 } 345 base = oi->hwbase; 346 break; 347 case OTP_SW_RGN: 348 if (oi->prog & OTPS_GUP_SW) { 349 OTP_MSG(("%s: s/w region has been programmed\n", __FUNCTION__)); 350 return -1; 351 } 352 if (wlen > (uint)(oi->swlim - oi->swbase)) { 353 OTP_MSG(("%s: wlen %u exceeds OTP s/w region limit %u\n", 354 __FUNCTION__, wlen, oi->swlim - oi->swbase)); 355 return -1; 356 } 357 base = oi->swbase; 358 break; 359 case OTP_CI_RGN: 360 if (oi->prog & OTPS_GUP_CI) { 361 OTP_MSG(("%s: chipid region has been programmed\n", __FUNCTION__)); 362 return -1; 363 } 364 if (wlen > OTPGU_CI_SZ) { 365 OTP_MSG(("%s: wlen %u exceeds OTP ci region limit %u\n", 366 __FUNCTION__, wlen, OTPGU_CI_SZ)); 367 return -1; 368 } 369 base = OTPGU_CI_OFF; 370 break; 371 case OTP_FUSE_RGN: 372 if (oi->prog & OTPS_GUP_FUSE) { 373 OTP_MSG(("%s: fuse region has been programmed\n", __FUNCTION__)); 374 return -1; 375 } 376 if (wlen > (uint)(oi->flim - oi->fbase)) { 377 OTP_MSG(("%s: wlen %u exceeds OTP ci region limit %u\n", 378 __FUNCTION__, wlen, oi->flim - oi->fbase)); 379 return -1; 380 } 381 base = oi->flim - wlen; 382 break; 383 default: 384 OTP_MSG(("%s: writing region %d is not supported\n", __FUNCTION__, region)); 385 return -1; 386 } 387 388 idx = sb_coreidx(oi->sbh); 389 cc = sb_setcore(oi->sbh, SB_CC, 0); 390 391 /* Enable Write */ 392 OR_REG(oi->osh, &cc->otpcontrol, OTPC_PROGEN); 393 394 /* Write the data */ 395 for (i = 0; i < wlen; i ++) 396 otpwb16(oh, cc, base + i, data[i]); 397 398 /* Update boundary/flag in memory and in OTP */ 399 switch (region) { 400 case OTP_HW_RGN: 401 otpwb16(oh, cc, OTPGU_HSB_OFF, (base + i) * 16); 402 otp_write_bit(oh, cc, OTPGU_HWP_OFF); 403 break; 404 case OTP_SW_RGN: 405 otpwb16(oh, cc, OTPGU_HSB_OFF, base * 16); 406 otpwb16(oh, cc, OTPGU_SFB_OFF, (base + i) * 16); 407 otp_write_bit(oh, cc, OTPGU_SWP_OFF); 408 break; 409 case OTP_CI_RGN: 410 otp_write_bit(oh, cc, OTPGU_CIP_OFF); 411 break; 412 case OTP_FUSE_RGN: 413 otpwb16(oh, cc, OTPGU_SFB_OFF, base * 16); 414 otp_write_bit(oh, cc, OTPGU_FUSEP_OFF); 415 break; 416 } 417 418 /* Disable Write */ 419 AND_REG(oi->osh, &cc->otpcontrol, ~OTPC_PROGEN); 420 421 /* Sync region info by retrieving them again */ 422 otp_rgn(oi, cc); 423 424 sb_setcoreidx(oi->sbh, idx); 425 return 0; 426} 427 428/* expects the caller to disable interrupts before calling this routine */ 429int 430otp_nvwrite(void *oh, uint16 *data, uint wlen) 431{ 432 return -1; 433} 434#endif /* BCMNVRAMW */ 435 436#if defined(WLTEST) 437static int 438otp_read_bit(otpinfo_t *oi, chipcregs_t *cc, uint idx) 439{ 440 uint k, row, col; 441 uint32 otpp, st; 442 443 row = idx / oi->cols; 444 col = idx % oi->cols; 445 446 otpp = OTPP_START_BUSY | 447 ((OTPPOC_READ << OTPP_OC_SHIFT) & OTPP_OC_MASK) | 448 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) | 449 ((col << OTPP_COL_SHIFT) & OTPP_COL_MASK); 450 OTP_MSG(("%s: idx = %d, row = %d, col = %d, otpp = 0x%x", 451 __FUNCTION__, idx, row, col, otpp)); 452 W_REG(oi->osh, &cc->otpprog, otpp); 453 454 for (k = 0; 455 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY) && (k < OTPP_TRIES); 456 k ++) 457 ; 458 if (k >= OTPP_TRIES) { 459 OTP_MSG(("\n%s: BUSY stuck: st=0x%x, count=%d\n", __FUNCTION__, st, k)); 460 return -1; 461 } 462 if (st & OTPP_READERR) { 463 OTP_MSG(("\n%s: Could not read OTP bit %d\n", __FUNCTION__, idx)); 464 return -1; 465 } 466 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT; 467 468 OTP_MSG((" => %d\n", st)); 469 return (int)st; 470} 471 472static uint16 473otprb16(otpinfo_t *oi, chipcregs_t *cc, uint wn) 474{ 475 uint base, i; 476 uint16 val; 477 int bit; 478 479 base = wn * 16; 480 481 val = 0; 482 for (i = 0; i < 16; i++) { 483 if ((bit = otp_read_bit(oi, cc, base + i)) == -1) 484 break; 485 val = val | (bit << i); 486 } 487 if (i < 16) 488 val = 0xffff; 489 490 return val; 491} 492 493int 494otp_dump(void *oh, int arg, char *buf, uint size) 495{ 496 otpinfo_t *oi = (otpinfo_t *)oh; 497 chipcregs_t *cc; 498 uint idx, i, count; 499 uint16 val; 500 struct bcmstrbuf b; 501 502 idx = sb_coreidx(oi->sbh); 503 cc = sb_setcore(oi->sbh, SB_CC, 0); 504 505 count = otp_size(oh); 506 507 bcm_binit(&b, buf, size); 508 for (i = 0; i < count / 2; i++) { 509 if (!(i % 4)) 510 bcm_bprintf(&b, "\n0x%04x:", 2 * i); 511 if (arg == 0) 512 val = otpr(oh, cc, i); 513 else 514 val = otprb16(oh, cc, i); 515 bcm_bprintf(&b, " 0x%04x", val); 516 } 517 bcm_bprintf(&b, "\n"); 518 519 sb_setcoreidx(oi->sbh, idx); 520 521 return ((int)(b.buf - b.origbuf)); 522} 523#endif 524 525#else /* BCMHNDOTP - Older HND OTP controller */ 526 527/* Fields in otpstatus */ 528#define OTPS_PROGFAIL 0x80000000 529#define OTPS_PROTECT 0x00000007 530#define OTPS_HW_PROTECT 0x00000001 531#define OTPS_SW_PROTECT 0x00000002 532#define OTPS_CID_PROTECT 0x00000004 533 534/* Fields in the otpcontrol register */ 535#define OTPC_RECWAIT 0xff000000 536#define OTPC_PROGWAIT 0x00ffff00 537#define OTPC_PRW_SHIFT 8 538#define OTPC_MAXFAIL 0x00000038 539#define OTPC_VSEL 0x00000006 540#define OTPC_SELVL 0x00000001 541 542/* Fields in otpprog */ 543#define OTPP_COL_MASK 0x000000ff 544#define OTPP_ROW_MASK 0x0000ff00 545#define OTPP_ROW_SHIFT 8 546#define OTPP_READERR 0x10000000 547#define OTPP_VALUE 0x20000000 548#define OTPP_VALUE_SHIFT 29 549#define OTPP_READ 0x40000000 550#define OTPP_START 0x80000000 551#define OTPP_BUSY 0x80000000 552 553/* OTP regions (Byte offsets from otp size) */ 554#define OTP_SWLIM_OFF (-8) 555#define OTP_CIDBASE_OFF 0 556#define OTP_CIDLIM_OFF 8 557 558/* Predefined OTP words (Word offset from otp size) */ 559#define OTP_BOUNDARY_OFF (-4) 560#define OTP_HWSIGN_OFF (-3) 561#define OTP_SWSIGN_OFF (-2) 562#define OTP_CIDSIGN_OFF (-1) 563#define OTP_CID_OFF 0 564#define OTP_PKG_OFF 1 565#define OTP_FID_OFF 2 566#define OTP_RSV_OFF 3 567#define OTP_LIM_OFF 4 568 569#define OTP_HW_REGION OTPS_HW_PROTECT 570#define OTP_SW_REGION OTPS_SW_PROTECT 571#define OTP_CID_REGION OTPS_CID_PROTECT 572 573#if OTP_HW_REGION != OTP_HW_RGN 574#error "incompatible OTP_HW_RGN" 575#endif 576#if OTP_SW_REGION != OTP_SW_RGN 577#error "incompatible OTP_SW_RGN" 578#endif 579#if OTP_CID_REGION != OTP_CI_RGN 580#error "incompatible OTP_CI_RGN" 581#endif 582 583#define OTP_SIGNATURE 0x578a 584#define OTP_MAGIC 0x4e56 585 586#define OTPP_TRIES 10000000 /* # of tries for OTPP */ 587 588typedef struct _otpinfo { 589 sb_t *sbh; /* Saved sb handle */ 590 uint ccrev; /* chipc revision */ 591 uint size; /* Size of otp in bytes */ 592 uint hwprot; /* Hardware protection bits */ 593 uint signvalid; /* Signature valid bits */ 594 int boundary; /* hw/sw boundary */ 595} otpinfo_t; 596 597static otpinfo_t otpinfo; 598 599static uint16 otproff(void *oh, chipcregs_t *cc, int woff); 600#ifdef BCMNVRAMW 601static int otp_write_word(void *oh, chipcregs_t *cc, int wn, uint16 data); 602#endif /* BCMNVRAMW */ 603 604uint16 605otpr(void *oh, chipcregs_t *cc, uint wn) 606{ 607 otpinfo_t *oi = (otpinfo_t *)oh; 608 osl_t *osh; 609 uint16 *ptr; 610 611 ASSERT(wn < ((((otpinfo_t *)oh)->size / 2) + OTP_LIM_OFF)); 612 ASSERT(cc); 613 614 osh = sb_osh(oi->sbh); 615 616 ptr = (uint16 *)((uchar *)cc + CC_OTP); 617 return (R_REG(osh, &ptr[wn])); 618} 619 620static uint16 621otproff(void *oh, chipcregs_t *cc, int woff) 622{ 623 otpinfo_t *oi = (otpinfo_t *)oh; 624 osl_t *osh; 625 uint16 *ptr; 626 627 ASSERT(woff >= (-((int)oi->size / 2))); 628 ASSERT(woff < OTP_LIM_OFF); 629 ASSERT(cc); 630 631 osh = sb_osh(oi->sbh); 632 633 ptr = (uint16 *)((uchar *)cc + CC_OTP); 634 635 return (R_REG(osh, &ptr[(oi->size / 2) + woff])); 636} 637 638void * 639otp_init(sb_t *sbh) 640{ 641 uint idx; 642 chipcregs_t *cc; 643 otpinfo_t *oi; 644 uint32 cap = 0; 645 void *ret = NULL; 646 osl_t *osh; 647 648 oi = &otpinfo; 649 bzero(oi, sizeof(otpinfo_t)); 650 651 idx = sb_coreidx(sbh); 652 653 oi->sbh = sbh; 654 osh = sb_osh(oi->sbh); 655 656 /* Check for otp */ 657 if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) { 658 cap = R_REG(osh, &cc->capabilities); 659 if ((cap & CC_CAP_OTPSIZE) == 0) { 660 /* Nothing there */ 661 goto out; 662 } 663 664 oi->sbh = sbh; 665 oi->ccrev = sb_chipcrev(sbh); 666 667 /* As of right now, support only 4320a2 and 4311a1 */ 668 if ((oi->ccrev != 12) && (oi->ccrev != 17)) { 669 goto out; 670 } 671 672 oi->size = 1 << (((cap & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) 673 + CC_CAP_OTPSIZE_BASE); 674 675 oi->hwprot = (int)(R_REG(osh, &cc->otpstatus) & OTPS_PROTECT); 676 oi->boundary = -1; 677 678 if (oi->ccrev != 17) { 679 if (otproff(oi, cc, OTP_HWSIGN_OFF) == OTP_SIGNATURE) { 680 oi->signvalid |= OTP_HW_REGION; 681 oi->boundary = otproff(oi, cc, OTP_BOUNDARY_OFF); 682 } 683 684 if (otproff(oi, cc, OTP_SWSIGN_OFF) == OTP_SIGNATURE) 685 oi->signvalid |= OTP_SW_REGION; 686 687 if (otproff(oi, cc, OTP_CIDSIGN_OFF) == OTP_SIGNATURE) 688 oi->signvalid |= OTP_CID_REGION; 689 } 690 691 ret = (void *)oi; 692 } 693 694out: /* All done */ 695 sb_setcoreidx(sbh, idx); 696 697 return ret; 698} 699 700int 701otp_read_region(void *oh, int region, uint16 *data, uint wlen) 702{ 703 return -1; 704} 705 706int 707otp_status(void *oh) 708{ 709 otpinfo_t *oi = (otpinfo_t *)oh; 710 return ((int)(oi->hwprot | oi->signvalid)); 711} 712 713int 714otp_size(void *oh) 715{ 716 otpinfo_t *oi = (otpinfo_t *)oh; 717 return ((int)(oi->size)); 718} 719 720int 721otp_nvread(void *oh, char *data, uint *len) 722{ 723 int rc = 0; 724 otpinfo_t *oi = (otpinfo_t *)oh; 725 uint32 base, bound, lim = 0, st; 726 int i, chunk, gchunks, tsz = 0; 727 uint32 idx; 728 chipcregs_t *cc; 729 uint offset; 730 uint16 *rawotp = NULL; 731 732 /* save the orig core */ 733 idx = sb_coreidx(oi->sbh); 734 cc = sb_setcore(oi->sbh, SB_CC, 0); 735 736 st = otp_status(oh); 737 if (!(st & (OTP_HW_REGION | OTP_SW_REGION))) { 738 OTP_MSG(("OTP not programmed\n")); 739 rc = -1; 740 goto out; 741 } 742 743 /* Read the whole otp so we can easily manipulate it */ 744 lim = otp_size(oh); 745 if ((rawotp = MALLOC(sb_osh(oi->sbh), lim)) == NULL) { 746 OTP_MSG(("Out of memory for rawotp\n")); 747 rc = -2; 748 goto out; 749 } 750 for (i = 0; i < (lim / 2); i++) 751 rawotp[i] = otpr(oh, cc, i); 752 753 if ((st & OTP_HW_REGION) == 0) { 754 OTP_MSG(("otp: hw region not written (0x%x)\n", st)); 755 756 /* This could be a programming failure in the first 757 * chunk followed by one or more good chunks 758 */ 759 for (i = 0; i < (lim / 2); i++) 760 if (rawotp[i] == OTP_MAGIC) 761 break; 762 763 if (i < (lim / 2)) { 764 base = i; 765 bound = (i * 2) + rawotp[i + 1]; 766 OTP_MSG(("otp: trying chunk at 0x%x-0x%x\n", i * 2, bound)); 767 } else { 768 OTP_MSG(("otp: unprogrammed\n")); 769 rc = -3; 770 goto out; 771 } 772 } else { 773 bound = rawotp[(lim / 2) + OTP_BOUNDARY_OFF]; 774 775 /* There are two cases: 1) The whole otp is used as nvram 776 * and 2) There is a hardware header followed by nvram. 777 */ 778 if (rawotp[0] == OTP_MAGIC) { 779 base = 0; 780 if (bound != rawotp[1]) 781 OTP_MSG(("otp: Bound 0x%x != chunk0 len 0x%x\n", bound, 782 rawotp[1])); 783 } else 784 base = bound; 785 } 786 787 /* Find and copy the data */ 788 789 chunk = 0; 790 gchunks = 0; 791 i = base / 2; 792 offset = 0; 793 while ((i < (lim / 2)) && (rawotp[i] == OTP_MAGIC)) { 794 int dsz, rsz = rawotp[i + 1]; 795 796 if (((i * 2) + rsz) >= lim) { 797 OTP_MSG((" bad chunk size, chunk %d, base 0x%x, size 0x%x\n", 798 chunk, i * 2, rsz)); 799 /* Bad length, try to find another chunk anyway */ 800 rsz = 6; 801 } 802 if (hndcrc16((uint8 *)&rawotp[i], rsz, 803 CRC16_INIT_VALUE) == CRC16_GOOD_VALUE) { 804 /* Good crc, copy the vars */ 805 OTP_MSG((" good chunk %d, base 0x%x, size 0x%x\n", 806 chunk, i * 2, rsz)); 807 gchunks++; 808 dsz = rsz - 6; 809 tsz += dsz; 810 if (offset + dsz >= *len) { 811 OTP_MSG(("Out of memory for otp\n")); 812 goto out; 813 } 814 bcopy((char *)&rawotp[i + 2], &data[offset], dsz); 815 offset += dsz; 816 /* Remove extra null characters at the end */ 817 while (offset > 1 && 818 data[offset - 1] == 0 && data[offset - 2] == 0) 819 offset --; 820 i += rsz / 2; 821 } else { 822 /* bad length or crc didn't check, try to find the next set */ 823 OTP_MSG((" chunk %d @ 0x%x size 0x%x: bad crc, ", 824 chunk, i * 2, rsz)); 825 if (rawotp[i + (rsz / 2)] == OTP_MAGIC) { 826 /* Assume length is good */ 827 i += rsz / 2; 828 } else { 829 while (++i < (lim / 2)) 830 if (rawotp[i] == OTP_MAGIC) 831 break; 832 } 833 if (i < (lim / 2)) 834 OTP_MSG(("trying next base 0x%x\n", i * 2)); 835 else 836 OTP_MSG(("no more chunks\n")); 837 } 838 chunk++; 839 } 840 841 OTP_MSG((" otp size = %d, boundary = 0x%x, nv base = 0x%x\n", 842 lim, bound, base)); 843 if (tsz != 0) 844 OTP_MSG((" Found %d bytes in %d good chunks out of %d\n", 845 tsz, gchunks, chunk)); 846 else 847 OTP_MSG((" No good chunks found out of %d\n", chunk)); 848 849 *len = offset; 850 851out: 852 if (rawotp) 853 MFREE(sb_osh(oi->sbh), rawotp, lim); 854 sb_setcoreidx(oi->sbh, idx); 855 856 return rc; 857} 858 859#ifdef BCMNVRAMW 860 861static int 862otp_write_word(void *oh, chipcregs_t *cc, int wn, uint16 data) 863{ 864 otpinfo_t *oi = (otpinfo_t *)oh; 865 uint base, row, col, bit, i, j, k; 866 uint32 pwait, init_pwait, otpc, otpp, pst, st; 867 868#ifdef OTP_FORCEFAIL 869 OTP_MSG(("%s: [0x%x] = 0x%x\n", __FUNCTION__, wn * 2, data)); 870#endif /* OTP_FORCEFAIL */ 871 872 /* This is bit-at-a-time writing, future cores may do word-at-a-time */ 873 base = (wn * 16) + (wn / 4); 874 if (oi->ccrev == 12) { 875 otpc = 0x20000001; 876 init_pwait = 0x00000200; 877 } else { 878 otpc = 0x20000000; 879 init_pwait = 0x00004000; 880 } 881 for (i = 0; i < 16; i++) { 882 pwait = init_pwait; 883 bit = data & 1; 884 row = (base + i) / 65; 885 col = (base + i) % 65; 886 otpp = OTPP_START | 887 ((bit << OTPP_VALUE_SHIFT) & OTPP_VALUE) | 888 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) | 889 (col & OTPP_COL_MASK); 890 OTP_MSG(("row %d, col %d, val %d, otpc 0x%x, otpp 0x%x\n", row, col, bit, 891 otpc, otpp)); 892 j = 0; 893 while (1) { 894 j++; 895 OTP_MSG((" %d: pwait %d\n", j, (pwait >> 8))); 896 W_REG(osh, &cc->otpcontrol, otpc | pwait); 897 W_REG(osh, &cc->otpprog, otpp); 898 pst = R_REG(osh, &cc->otpprog); 899 for (k = 0; ((pst & OTPP_BUSY) == OTPP_BUSY) && (k < OTPP_TRIES); k++) 900 pst = R_REG(osh, &cc->otpprog); 901 if (k >= OTPP_TRIES) { 902 OTP_MSG(("BUSY stuck: pst=0x%x, count=%d\n", pst, k)); 903 st = OTPS_PROGFAIL; 904 break; 905 } 906 st = R_REG(osh, &cc->otpstatus); 907 if (((st & OTPS_PROGFAIL) == 0) || (pwait == OTPC_PROGWAIT)) { 908 break; 909 } else { 910 if ((oi->ccrev == 12) && (pwait >= 0x1000)) 911 pwait = (pwait << 3) & OTPC_PROGWAIT; 912 else 913 pwait = (pwait << 1) & OTPC_PROGWAIT; 914 if (pwait == 0) 915 pwait = OTPC_PROGWAIT; 916 } 917 } 918 if (st & OTPS_PROGFAIL) { 919 OTP_MSG(("After %d tries: otpc = 0x%x, otpp = 0x%x/0x%x, otps = 0x%x\n", 920 j, otpc | pwait, otpp, pst, st)); 921 OTP_MSG(("otp prog failed. wn=%d, bit=%d, ppret=%d, ret=%d\n", 922 wn, i, k, j)); 923 return 1; 924 } 925 data >>= 1; 926 } 927 return 0; 928} 929 930/* expects the caller to disable interrupts before calling this routine */ 931int 932otp_write_region(void *oh, int region, uint16 *data, uint wlen) 933{ 934 otpinfo_t *oi = (otpinfo_t *)oh; 935 uint32 st; 936 uint wn, base = 0, lim; 937 int ret; 938 uint idx; 939 chipcregs_t *cc; 940 941 idx = sb_coreidx(oi->sbh); 942 cc = sb_setcore(oi->sbh, SB_CC, 0); 943 944 /* Run bist on chipc to get any unprogrammed bits into a known state */ 945 if (sb_corebist(oi->sbh) == 0) 946 OTP_MSG(("%s: bist passed, otp is blank\n", __FUNCTION__)); 947 948 if (oi->ccrev != 17) { 949 /* Check valid region */ 950 if ((region != OTP_HW_REGION) && 951 (region != OTP_SW_REGION) && 952 (region != OTP_CID_REGION)) { 953 ret = -2; 954 goto out; 955 } 956 957 /* Region already written? */ 958 st = oi->hwprot | oi-> signvalid; 959 if ((st & region) != 0) { 960 ret = -3; 961 goto out; 962 } 963 964 /* HW and CID have to be written before SW */ 965 if ((st & OTP_SW_REGION) != 0) { 966 ret = -4; 967 goto out; 968 } 969 970 /* Bounds for the region */ 971 lim = (oi->size / 2) + OTP_SWLIM_OFF; 972 if (region == OTP_HW_REGION) { 973 base = 0; 974 } else if (region == OTP_SW_REGION) { 975 base = oi->boundary / 2; 976 } else if (region == OTP_CID_REGION) { 977 base = (oi->size / 2) + OTP_CID_OFF; 978 lim = (oi->size / 2) + OTP_LIM_OFF; 979 } 980 } else { 981 base = 0; 982 lim = oi->size / 4; 983 } 984 if (wlen > (lim - base)) { 985 ret = -5; 986 goto out; 987 } 988 lim = base + wlen; 989 990 991 /* Write the data */ 992 ret = -7; 993 for (wn = base; wn < lim; wn++) 994 if (oi->ccrev == 17) { 995 uint werrs, rwn; 996 997 rwn = 4 * wn; 998 werrs = (otp_write_word(oh, cc, rwn++, *data) != 0) ? 1 : 0; 999 werrs += (otp_write_word(oh, cc, rwn++, *data) != 0) ? 1 : 0; 1000 werrs += (otp_write_word(oh, cc, rwn, *data++) != 0) ? 1 : 0; 1001 if (werrs > 2) 1002 goto out; 1003 } else 1004 if (otp_write_word(oh, cc, wn, *data++) != 0) 1005 goto out; 1006 1007 if (oi->ccrev != 17) { 1008 /* Done with the data, write the signature & boundary if needed */ 1009 if (region == OTP_HW_REGION) { 1010 ret = -8; 1011 if (otp_write_word(oh, cc, (oi->size / 2) + OTP_BOUNDARY_OFF, 1012 lim * 2) != 0) 1013 goto out; 1014 ret = -9; 1015 if (otp_write_word(oh, cc, (oi->size / 2) + OTP_HWSIGN_OFF, 1016 OTP_SIGNATURE) != 0) 1017 goto out; 1018 oi->boundary = lim * 2; 1019 oi->signvalid |= OTP_HW_REGION; 1020 } else if (region == OTP_SW_REGION) { 1021 ret = -10; 1022 if (otp_write_word(oh, cc, (oi->size / 2) + OTP_SWSIGN_OFF, 1023 OTP_SIGNATURE) != 0) 1024 goto out; 1025 oi->signvalid |= OTP_SW_REGION; 1026 } else if (region == OTP_CID_REGION) { 1027 ret = -11; 1028 if (otp_write_word(oh, cc, (oi->size / 2) + OTP_CIDSIGN_OFF, 1029 OTP_SIGNATURE) != 0) 1030 goto out; 1031 oi->signvalid |= OTP_CID_REGION; 1032 } 1033 } 1034 ret = 0; 1035out: 1036 OTP_MSG(("bits written: %d, average (%d/%d): %d, max retry: %d, pp max: %d\n", 1037 st_n, st_s, st_n, st_n?(st_s / st_n):0, st_hwm, pp_hwm)); 1038 1039 sb_setcoreidx(oi->sbh, idx); 1040 1041 return ret; 1042} 1043 1044/* expects the caller to disable interrupts before calling this routine */ 1045int 1046otp_nvwrite(void *oh, uint16 *data, uint wlen) 1047{ 1048 otpinfo_t *oi = (otpinfo_t *)oh; 1049 uint32 st; 1050 uint16 crc, clen, *p, hdr[2]; 1051 uint wn, base = 0, lim; 1052 int err, gerr = 0; 1053 uint idx; 1054 chipcregs_t *cc; 1055 1056 1057 /* Run bist on chipc to get any unprogrammed bits into a known state */ 1058 if (sb_corebist(oi->sbh) == 0) 1059 OTP_MSG(("%s: bist passed, otp is blank\n", __FUNCTION__)); 1060 1061 /* otp already written? */ 1062 st = oi->hwprot | oi-> signvalid; 1063 if ((st & (OTP_HW_REGION | OTP_SW_REGION)) == (OTP_HW_REGION | OTP_SW_REGION)) 1064 return BCME_EPERM; 1065 1066 /* save the orig core */ 1067 idx = sb_coreidx(oi->sbh); 1068 cc = sb_setcore(oi->sbh, SB_CC, 0); 1069 1070 /* Bounds for the region */ 1071 lim = (oi->size / 2) + OTP_SWLIM_OFF; 1072 base = 0; 1073 1074 /* Look for possible chunks from the end down */ 1075 wn = lim; 1076 while (wn > 0) { 1077 wn--; 1078 if (otpr(oh, cc, wn) == OTP_MAGIC) { 1079 base = wn + (otpr(oh, cc, wn + 1) / 2); 1080 break; 1081 } 1082 } 1083 if (base == 0) { 1084 OTP_MSG(("Unprogrammed otp\n")); 1085 } else { 1086 OTP_MSG(("Found some chunks, skipping to 0x%x\n", base * 2)); 1087 } 1088 if ((wlen + 3) > (lim - base)) { 1089 err = BCME_NORESOURCE; 1090 goto out; 1091 } 1092 1093 1094 /* Prepare the header and crc */ 1095 hdr[0] = OTP_MAGIC; 1096 hdr[1] = (wlen + 3) * 2; 1097 crc = hndcrc16((uint8 *)hdr, sizeof(hdr), CRC16_INIT_VALUE); 1098 crc = hndcrc16((uint8 *)data, wlen * 2, crc); 1099 crc = ~crc; 1100 1101 do { 1102 p = data; 1103 wn = base + 2; 1104 lim = base + wlen + 2; 1105 1106 OTP_MSG(("writing chunk, 0x%x bytes @ 0x%x-0x%x\n", wlen * 2, 1107 base * 2, (lim + 1) * 2)); 1108 1109 /* Write the header */ 1110 err = otp_write_word(oh, cc, base, hdr[0]); 1111 1112 /* Write the data */ 1113 while (wn < lim) { 1114 err += otp_write_word(oh, cc, wn++, *p++); 1115 1116 /* If there has been an error, close this chunk */ 1117 if (err != 0) { 1118 OTP_MSG(("closing early @ 0x%x\n", wn * 2)); 1119 break; 1120 } 1121 } 1122 1123 /* If we wrote the whole chunk, write the crc */ 1124 if (wn == lim) { 1125 OTP_MSG((" whole chunk written, crc = 0x%x\n", crc)); 1126 err += otp_write_word(oh, cc, wn++, crc); 1127 clen = hdr[1]; 1128 } else { 1129 /* If there was an error adjust the count to point to 1130 * the word after the error so we can start the next 1131 * chunk there. 1132 */ 1133 clen = (wn - base) * 2; 1134 OTP_MSG((" partial chunk written, chunk len = 0x%x\n", clen)); 1135 } 1136 /* And now write the chunk length */ 1137 err += otp_write_word(oh, cc, base + 1, clen); 1138 1139 if (base == 0) { 1140 /* Write the signature and boundary if this is the HW region, 1141 * but don't report failure if either of these 2 writes fail. 1142 */ 1143 if (otp_write_word(oh, cc, (oi->size / 2) + OTP_BOUNDARY_OFF, wn * 2) == 0) 1144 gerr += otp_write_word(oh, cc, (oi->size / 2) + OTP_HWSIGN_OFF, 1145 OTP_SIGNATURE); 1146 else 1147 gerr++; 1148 oi->boundary = wn * 2; 1149 oi->signvalid |= OTP_HW_REGION; 1150 } 1151 1152 if (err != 0) { 1153 gerr += err; 1154 /* Errors, do it all over again if there is space left */ 1155 if ((wlen + 3) <= ((oi->size / 2) + OTP_SWLIM_OFF - wn)) { 1156 base = wn; 1157 lim = base + wlen + 2; 1158 OTP_MSG(("Programming errors, retry @ 0x%x\n", wn * 2)); 1159 } else { 1160 OTP_MSG(("Programming errors, no space left ( 0x%x)\n", wn * 2)); 1161 break; 1162 } 1163 } 1164 } while (err != 0); 1165 1166 OTP_MSG(("bits written: %d, average (%d/%d): %d, max retry: %d, pp max: %d\n", 1167 st_n, st_s, st_n, st_s / st_n, st_hwm, pp_hwm)); 1168 1169 if (gerr != 0) 1170 OTP_MSG(("programming %s after %d errors\n", (err == 0) ? "succedded" : "failed", 1171 gerr)); 1172out: 1173 /* done */ 1174 sb_setcoreidx(oi->sbh, idx); 1175 1176 if (err) 1177 return BCME_ERROR; 1178 else 1179 return 0; 1180} 1181#endif /* BCMNVRAMW */ 1182 1183#if defined(WLTEST) 1184static uint16 1185otp_read_bit(void *oh, chipcregs_t *cc, uint idx) 1186{ 1187 uint k, row, col; 1188 uint32 otpp, st; 1189 osl_t *osh; 1190 otpinfo_t *oi = (otpinfo_t *)oh; 1191 1192 osh = sb_osh(oi->sbh); 1193 row = idx / 65; 1194 col = idx % 65; 1195 1196 otpp = OTPP_START | OTPP_READ | 1197 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) | 1198 (col & OTPP_COL_MASK); 1199 1200 OTP_MSG(("%s: idx = %d, row = %d, col = %d, otpp = 0x%x", __FUNCTION__, 1201 idx, row, col, otpp)); 1202 1203 W_REG(osh, &cc->otpprog, otpp); 1204 st = R_REG(osh, &cc->otpprog); 1205 for (k = 0; ((st & OTPP_BUSY) == OTPP_BUSY) && (k < OTPP_TRIES); k++) 1206 st = R_REG(osh, &cc->otpprog); 1207 1208 if (k >= OTPP_TRIES) { 1209 OTP_MSG(("\n%s: BUSY stuck: st=0x%x, count=%d\n", __FUNCTION__, st, k)); 1210 return 0xffff; 1211 } 1212 if (st & OTPP_READERR) { 1213 OTP_MSG(("\n%s: Could not read OTP bit %d\n", __FUNCTION__, idx)); 1214 return 0xffff; 1215 } 1216 st = (st & OTPP_VALUE) >> OTPP_VALUE_SHIFT; 1217 OTP_MSG((" => %d\n", st)); 1218 return (uint16)st; 1219} 1220 1221static uint16 1222otprb16(void *oh, chipcregs_t *cc, uint wn) 1223{ 1224 uint base, i; 1225 uint16 val, bit; 1226 1227 base = (wn * 16) + (wn / 4); 1228 val = 0; 1229 for (i = 0; i < 16; i++) { 1230 if ((bit = otp_read_bit(oh, cc, base + i)) == 0xffff) 1231 break; 1232 val = val | (bit << i); 1233 } 1234 if (i < 16) 1235 val = 0xaaaa; 1236 return val; 1237} 1238 1239int 1240otp_dump(void *oh, int arg, char *buf, uint size) 1241{ 1242 otpinfo_t *oi = (otpinfo_t *)oh; 1243 chipcregs_t *cc; 1244 uint idx, i, count, lil; 1245 uint16 val; 1246 struct bcmstrbuf b; 1247 1248 idx = sb_coreidx(oi->sbh); 1249 cc = sb_setcore(oi->sbh, SB_CC, 0); 1250 1251 if (arg >= 16) { 1252 arg -= 16; 1253 } else { 1254 /* Run bist on chipc to get any unprogrammed bits into a known state */ 1255 if (sb_corebist(oi->sbh) == 0) 1256 OTP_MSG(("%s: bist passed, otp is blank\n", __FUNCTION__)); 1257 } 1258 1259 if (arg == 2) { 1260 count = 66 * 4; 1261 lil = 3; 1262 } else { 1263 count = (oi->size / 2) + OTP_LIM_OFF; 1264 lil = 7; 1265 } 1266 1267 OTP_MSG(("%s: arg %d, size %d, words %d\n", __FUNCTION__, arg, size, count)); 1268 bcm_binit(&b, buf, size); 1269 for (i = 0; i < count; i++) { 1270 if ((i & lil) == 0) 1271 bcm_bprintf(&b, "0x%04x:", 2 * i); 1272 1273 if (arg == 0) 1274 val = otpr(oh, cc, i); 1275 else 1276 val = otprb16(oh, cc, i); 1277 bcm_bprintf(&b, " 0x%04x", val); 1278 if ((i & lil) == lil) { 1279 if (arg == 2) { 1280 bcm_bprintf(&b, " %d\n", 1281 otp_read_bit(oh, cc, ((i / 4) * 65) + 64) & 1); 1282 } else { 1283 bcm_bprintf(&b, "\n"); 1284 } 1285 } 1286 } 1287 if ((i & lil) != lil) 1288 bcm_bprintf(&b, "\n"); 1289 1290 OTP_MSG(("%s: returning %d, left %d, wn %d\n", 1291 __FUNCTION__, (int)(b.buf - b.origbuf), b.size, i)); 1292 1293 sb_setcoreidx(oi->sbh, idx); 1294 1295 return ((int)(b.buf - b.origbuf)); 1296} 1297#endif 1298 1299#endif /* BCMHNDOTP */ 1300