dnscrypto-proxy: Support files updated.
[tomato.git] / release / src / shared / bcmotp.c
bloba17a8b10cbdd9a1eb4b2b2a65d82045de4972db5
1 /*
2 * Write-once support for IPX OTP wrapper.
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.
12 * $Id$
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>
26 /* debug/trace */
27 #define OTP_MSG(x)
30 #if !defined(CONFIG_BCMHNDOTP) /* Newer IPX OTP wrapper */
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
39 /* Fixed size subregions sizes in words */
40 #define OTPGU_CI_SZ 2
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
48 typedef 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;
64 static otpinfo_t otpinfo;
66 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
68 static void
69 otp_rgn(otpinfo_t *oi, chipcregs_t *cc)
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));
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.
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;
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;
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));
101 void *
102 otp_init(sb_t *sbh)
104 uint idx;
105 chipcregs_t *cc;
106 otpinfo_t *oi;
108 /* chipc corerev must be >= 21 */
109 if (sbh->ccrev < 21)
110 return NULL;
112 oi = &otpinfo;
113 bzero(oi, sizeof(otpinfo_t));
115 oi->sbh = sbh;
116 oi->osh = sb_osh(sbh);
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;
136 /* Retrieve OTP region info */
137 idx = sb_coreidx(sbh);
138 cc = sb_setcore(sbh, SB_CC, 0);
139 ASSERT(cc);
141 switch (sbh->chip) {
142 #if defined(CONFIG_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;
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;
154 break;
155 #endif /* BCM4325 */
156 default:
157 break;
160 otp_rgn(oi, cc);
162 goto exit;
163 exit:
164 sb_setcoreidx(sbh, idx);
166 return (void *)oi;
169 uint16
170 otpr(void *oh, chipcregs_t *cc, uint wn)
172 otpinfo_t *oi;
174 oi = (otpinfo_t *)oh;
176 ASSERT(wn < oi->size);
177 ASSERT(cc);
179 return R_REG(oi->osh, &cc->otp[wn]);
183 otp_read_region(void *oh, int region, uint16 *data, uint wlen)
185 otpinfo_t *oi = (otpinfo_t *)oh;
186 uint idx;
187 chipcregs_t *cc;
188 uint base, i, sz;
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;
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;
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;
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;
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;
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;
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;
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;
238 base = oi->fbase;
239 break;
240 default:
241 OTP_MSG(("%s: reading region %d is not supported\n", __FUNCTION__, region));
242 return -1;
245 idx = sb_coreidx(oi->sbh);
246 cc = sb_setcore(oi->sbh, SB_CC, 0);
248 /* Read the data */
249 for (i = 0; i < sz; i ++)
250 data[i] = otpr(oh, cc, base + i);
252 sb_setcoreidx(oi->sbh, idx);
253 return 0;
257 otp_status(void *oh)
259 otpinfo_t *oi = (otpinfo_t *)oh;
260 return (int)(oi->hwprot | oi->prog);
264 otp_size(void *oh)
266 otpinfo_t *oi = (otpinfo_t *)oh;
267 return (int)oi->size * 2;
271 otp_nvread(void *oh, char *data, uint *len)
273 return -1;
276 #ifdef BCMNVRAMW
277 static int
278 otp_write_bit(otpinfo_t *oi, chipcregs_t *cc, uint idx)
280 uint k, row, col;
281 uint32 otpp, st;
283 row = idx / oi->cols;
284 col = idx % oi->cols;
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);
295 for (k = 0;
296 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY) && (k < OTPP_TRIES);
297 k ++)
299 if (k >= OTPP_TRIES) {
300 OTP_MSG(("\n%s: BUSY stuck: st=0x%x, count=%d\n", __FUNCTION__, st, k));
301 return -1;
304 return 0;
307 static int
308 otpwb16(otpinfo_t *oi, chipcregs_t *cc, int wn, uint16 data)
310 uint base, i;
311 int rc;
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;
321 return 0;
324 /* expects the caller to disable interrupts before calling this routine */
326 otp_write_region(void *oh, int region, uint16 *data, uint wlen)
328 otpinfo_t *oi = (otpinfo_t *)oh;
329 uint idx;
330 chipcregs_t *cc;
331 uint base, i;
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;
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;
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;
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;
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;
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;
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;
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;
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;
388 idx = sb_coreidx(oi->sbh);
389 cc = sb_setcore(oi->sbh, SB_CC, 0);
391 /* Enable Write */
392 OR_REG(oi->osh, &cc->otpcontrol, OTPC_PROGEN);
394 /* Write the data */
395 for (i = 0; i < wlen; i ++)
396 otpwb16(oh, cc, base + i, data[i]);
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;
418 /* Disable Write */
419 AND_REG(oi->osh, &cc->otpcontrol, ~OTPC_PROGEN);
421 /* Sync region info by retrieving them again */
422 otp_rgn(oi, cc);
424 sb_setcoreidx(oi->sbh, idx);
425 return 0;
428 /* expects the caller to disable interrupts before calling this routine */
430 otp_nvwrite(void *oh, uint16 *data, uint wlen)
432 return -1;
434 #endif /* BCMNVRAMW */
436 #if defined(WLTEST)
437 static int
438 otp_read_bit(otpinfo_t *oi, chipcregs_t *cc, uint idx)
440 uint k, row, col;
441 uint32 otpp, st;
443 row = idx / oi->cols;
444 col = idx % oi->cols;
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);
454 for (k = 0;
455 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY) && (k < OTPP_TRIES);
456 k ++)
458 if (k >= OTPP_TRIES) {
459 OTP_MSG(("\n%s: BUSY stuck: st=0x%x, count=%d\n", __FUNCTION__, st, k));
460 return -1;
462 if (st & OTPP_READERR) {
463 OTP_MSG(("\n%s: Could not read OTP bit %d\n", __FUNCTION__, idx));
464 return -1;
466 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
468 OTP_MSG((" => %d\n", st));
469 return (int)st;
472 static uint16
473 otprb16(otpinfo_t *oi, chipcregs_t *cc, uint wn)
475 uint base, i;
476 uint16 val;
477 int bit;
479 base = wn * 16;
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);
487 if (i < 16)
488 val = 0xffff;
490 return val;
494 otp_dump(void *oh, int arg, char *buf, uint size)
496 otpinfo_t *oi = (otpinfo_t *)oh;
497 chipcregs_t *cc;
498 uint idx, i, count;
499 uint16 val;
500 struct bcmstrbuf b;
502 idx = sb_coreidx(oi->sbh);
503 cc = sb_setcore(oi->sbh, SB_CC, 0);
505 count = otp_size(oh);
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);
517 bcm_bprintf(&b, "\n");
519 sb_setcoreidx(oi->sbh, idx);
521 return ((int)(b.buf - b.origbuf));
523 #endif
525 #else /* BCMHNDOTP - Older HND OTP controller */
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
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
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
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
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
569 #define OTP_HW_REGION OTPS_HW_PROTECT
570 #define OTP_SW_REGION OTPS_SW_PROTECT
571 #define OTP_CID_REGION OTPS_CID_PROTECT
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
583 #define OTP_SIGNATURE 0x578a
584 #define OTP_MAGIC 0x4e56
586 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
588 typedef 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;
597 static otpinfo_t otpinfo;
599 static uint16 otproff(void *oh, chipcregs_t *cc, int woff);
600 #ifdef BCMNVRAMW
601 static int otp_write_word(void *oh, chipcregs_t *cc, int wn, uint16 data);
602 #endif /* BCMNVRAMW */
604 uint16
605 otpr(void *oh, chipcregs_t *cc, uint wn)
607 otpinfo_t *oi = (otpinfo_t *)oh;
608 osl_t *osh;
609 uint16 *ptr;
611 ASSERT(wn < ((((otpinfo_t *)oh)->size / 2) + OTP_LIM_OFF));
612 ASSERT(cc);
614 osh = sb_osh(oi->sbh);
616 ptr = (uint16 *)((uchar *)cc + CC_OTP);
617 return (R_REG(osh, &ptr[wn]));
620 static uint16
621 otproff(void *oh, chipcregs_t *cc, int woff)
623 otpinfo_t *oi = (otpinfo_t *)oh;
624 osl_t *osh;
625 uint16 *ptr;
627 ASSERT(woff >= (-((int)oi->size / 2)));
628 ASSERT(woff < OTP_LIM_OFF);
629 ASSERT(cc);
631 osh = sb_osh(oi->sbh);
633 ptr = (uint16 *)((uchar *)cc + CC_OTP);
635 return (R_REG(osh, &ptr[(oi->size / 2) + woff]));
638 void *
639 otp_init(sb_t *sbh)
641 uint idx;
642 chipcregs_t *cc;
643 otpinfo_t *oi;
644 uint32 cap = 0;
645 void *ret = NULL;
646 osl_t *osh;
648 oi = &otpinfo;
649 bzero(oi, sizeof(otpinfo_t));
651 idx = sb_coreidx(sbh);
653 oi->sbh = sbh;
654 osh = sb_osh(oi->sbh);
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;
664 oi->sbh = sbh;
665 oi->ccrev = sb_chipcrev(sbh);
667 /* As of right now, support only 4320a2 and 4311a1 */
668 if ((oi->ccrev != 12) && (oi->ccrev != 17)) {
669 goto out;
672 oi->size = 1 << (((cap & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT)
673 + CC_CAP_OTPSIZE_BASE);
675 oi->hwprot = (int)(R_REG(osh, &cc->otpstatus) & OTPS_PROTECT);
676 oi->boundary = -1;
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);
684 if (otproff(oi, cc, OTP_SWSIGN_OFF) == OTP_SIGNATURE)
685 oi->signvalid |= OTP_SW_REGION;
687 if (otproff(oi, cc, OTP_CIDSIGN_OFF) == OTP_SIGNATURE)
688 oi->signvalid |= OTP_CID_REGION;
691 ret = (void *)oi;
694 out: /* All done */
695 sb_setcoreidx(sbh, idx);
697 return ret;
701 otp_read_region(void *oh, int region, uint16 *data, uint wlen)
703 return -1;
707 otp_status(void *oh)
709 otpinfo_t *oi = (otpinfo_t *)oh;
710 return ((int)(oi->hwprot | oi->signvalid));
714 otp_size(void *oh)
716 otpinfo_t *oi = (otpinfo_t *)oh;
717 return ((int)(oi->size));
721 otp_nvread(void *oh, char *data, uint *len)
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;
732 /* save the orig core */
733 idx = sb_coreidx(oi->sbh);
734 cc = sb_setcore(oi->sbh, SB_CC, 0);
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;
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;
750 for (i = 0; i < (lim / 2); i++)
751 rawotp[i] = otpr(oh, cc, i);
753 if ((st & OTP_HW_REGION) == 0) {
754 OTP_MSG(("otp: hw region not written (0x%x)\n", st));
756 /* This could be a programming failure in the first
757 * chunk followed by one or more good chunks
759 for (i = 0; i < (lim / 2); i++)
760 if (rawotp[i] == OTP_MAGIC)
761 break;
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;
772 } else {
773 bound = rawotp[(lim / 2) + OTP_BOUNDARY_OFF];
775 /* There are two cases: 1) The whole otp is used as nvram
776 * and 2) There is a hardware header followed by nvram.
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;
787 /* Find and copy the data */
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];
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;
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;
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;
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"));
838 chunk++;
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));
849 *len = offset;
851 out:
852 if (rawotp)
853 MFREE(sb_osh(oi->sbh), rawotp, lim);
854 sb_setcoreidx(oi->sbh, idx);
856 return rc;
859 #ifdef BCMNVRAMW
861 static int
862 otp_write_word(void *oh, chipcregs_t *cc, int wn, uint16 data)
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;
868 #ifdef OTP_FORCEFAIL
869 OTP_MSG(("%s: [0x%x] = 0x%x\n", __FUNCTION__, wn * 2, data));
870 #endif /* OTP_FORCEFAIL */
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;
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;
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;
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;
925 data >>= 1;
927 return 0;
930 /* expects the caller to disable interrupts before calling this routine */
932 otp_write_region(void *oh, int region, uint16 *data, uint wlen)
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;
941 idx = sb_coreidx(oi->sbh);
942 cc = sb_setcore(oi->sbh, SB_CC, 0);
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__));
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;
957 /* Region already written? */
958 st = oi->hwprot | oi-> signvalid;
959 if ((st & region) != 0) {
960 ret = -3;
961 goto out;
964 /* HW and CID have to be written before SW */
965 if ((st & OTP_SW_REGION) != 0) {
966 ret = -4;
967 goto out;
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;
980 } else {
981 base = 0;
982 lim = oi->size / 4;
984 if (wlen > (lim - base)) {
985 ret = -5;
986 goto out;
988 lim = base + wlen;
991 /* Write the data */
992 ret = -7;
993 for (wn = base; wn < lim; wn++)
994 if (oi->ccrev == 17) {
995 uint werrs, rwn;
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;
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;
1034 ret = 0;
1035 out:
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));
1039 sb_setcoreidx(oi->sbh, idx);
1041 return ret;
1044 /* expects the caller to disable interrupts before calling this routine */
1046 otp_nvwrite(void *oh, uint16 *data, uint wlen)
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;
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__));
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;
1066 /* save the orig core */
1067 idx = sb_coreidx(oi->sbh);
1068 cc = sb_setcore(oi->sbh, SB_CC, 0);
1070 /* Bounds for the region */
1071 lim = (oi->size / 2) + OTP_SWLIM_OFF;
1072 base = 0;
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;
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));
1088 if ((wlen + 3) > (lim - base)) {
1089 err = BCME_NORESOURCE;
1090 goto out;
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;
1101 do {
1102 p = data;
1103 wn = base + 2;
1104 lim = base + wlen + 2;
1106 OTP_MSG(("writing chunk, 0x%x bytes @ 0x%x-0x%x\n", wlen * 2,
1107 base * 2, (lim + 1) * 2));
1109 /* Write the header */
1110 err = otp_write_word(oh, cc, base, hdr[0]);
1112 /* Write the data */
1113 while (wn < lim) {
1114 err += otp_write_word(oh, cc, wn++, *p++);
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;
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.
1133 clen = (wn - base) * 2;
1134 OTP_MSG((" partial chunk written, chunk len = 0x%x\n", clen));
1136 /* And now write the chunk length */
1137 err += otp_write_word(oh, cc, base + 1, clen);
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.
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;
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;
1164 } while (err != 0);
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));
1169 if (gerr != 0)
1170 OTP_MSG(("programming %s after %d errors\n", (err == 0) ? "succedded" : "failed",
1171 gerr));
1172 out:
1173 /* done */
1174 sb_setcoreidx(oi->sbh, idx);
1176 if (err)
1177 return BCME_ERROR;
1178 else
1179 return 0;
1181 #endif /* BCMNVRAMW */
1183 #if defined(WLTEST)
1184 static uint16
1185 otp_read_bit(void *oh, chipcregs_t *cc, uint idx)
1187 uint k, row, col;
1188 uint32 otpp, st;
1189 osl_t *osh;
1190 otpinfo_t *oi = (otpinfo_t *)oh;
1192 osh = sb_osh(oi->sbh);
1193 row = idx / 65;
1194 col = idx % 65;
1196 otpp = OTPP_START | OTPP_READ |
1197 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) |
1198 (col & OTPP_COL_MASK);
1200 OTP_MSG(("%s: idx = %d, row = %d, col = %d, otpp = 0x%x", __FUNCTION__,
1201 idx, row, col, otpp));
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);
1208 if (k >= OTPP_TRIES) {
1209 OTP_MSG(("\n%s: BUSY stuck: st=0x%x, count=%d\n", __FUNCTION__, st, k));
1210 return 0xffff;
1212 if (st & OTPP_READERR) {
1213 OTP_MSG(("\n%s: Could not read OTP bit %d\n", __FUNCTION__, idx));
1214 return 0xffff;
1216 st = (st & OTPP_VALUE) >> OTPP_VALUE_SHIFT;
1217 OTP_MSG((" => %d\n", st));
1218 return (uint16)st;
1221 static uint16
1222 otprb16(void *oh, chipcregs_t *cc, uint wn)
1224 uint base, i;
1225 uint16 val, bit;
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);
1234 if (i < 16)
1235 val = 0xaaaa;
1236 return val;
1240 otp_dump(void *oh, int arg, char *buf, uint size)
1242 otpinfo_t *oi = (otpinfo_t *)oh;
1243 chipcregs_t *cc;
1244 uint idx, i, count, lil;
1245 uint16 val;
1246 struct bcmstrbuf b;
1248 idx = sb_coreidx(oi->sbh);
1249 cc = sb_setcore(oi->sbh, SB_CC, 0);
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__));
1259 if (arg == 2) {
1260 count = 66 * 4;
1261 lil = 3;
1262 } else {
1263 count = (oi->size / 2) + OTP_LIM_OFF;
1264 lil = 7;
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);
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");
1287 if ((i & lil) != lil)
1288 bcm_bprintf(&b, "\n");
1290 OTP_MSG(("%s: returning %d, left %d, wn %d\n",
1291 __FUNCTION__, (int)(b.buf - b.origbuf), b.size, i));
1293 sb_setcoreidx(oi->sbh, idx);
1295 return ((int)(b.buf - b.origbuf));
1297 #endif
1299 #endif /* BCMHNDOTP */