2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include <bcmendian.h>
27 #include "siutils_priv.h"
30 * There are two different OTP controllers so far:
31 * 1. new IPX OTP controller: chipc 21, >=23
32 * 2. older HND OTP controller: chipc 12, 17, 22
34 * Define BCMHNDOTP to include support for the HND OTP controller.
35 * Define BCMIPXOTP to include support for the IPX OTP controller.
37 * NOTE 1: More than one may be defined
38 * NOTE 2: If none are defined, the default is to include them all.
41 #if !defined(BCMHNDOTP) && !defined(BCMIPXOTP)
46 #define OTPTYPE_HND(ccrev) ((ccrev) < 21 || (ccrev) == 22)
47 #define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
49 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
52 #define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
55 /* OTP common function type */
56 typedef int (*otp_status_t
) (void *oh
);
57 typedef int (*otp_size_t
) (void *oh
);
58 typedef void *(*otp_init_t
) (si_t
*sih
);
59 typedef uint16(*otp_read_bit_t
) (void *oh
, chipcregs_t
*cc
, uint off
);
60 typedef int (*otp_read_region_t
) (si_t
*sih
, int region
, uint16
*data
,
62 typedef int (*otp_nvread_t
) (void *oh
, char *data
, uint
*len
);
64 /* OTP function struct */
65 typedef struct otp_fn_s
{
67 otp_read_bit_t read_bit
;
69 otp_read_region_t read_region
;
75 uint ccrev
; /* chipc revision */
76 otp_fn_t
*fn
; /* OTP functions */
77 si_t
*sih
; /* Saved sb handle */
82 uint16 wsize
; /* Size of otp in words */
83 uint16 rows
; /* Geometry */
84 uint16 cols
; /* Geometry */
85 uint32 status
; /* Flag bits (lock/prog/rv).
86 * (Reflected only when OTP is power cycled)
88 uint16 hwbase
; /* hardware subregion offset */
89 uint16 hwlim
; /* hardware subregion boundary */
90 uint16 swbase
; /* software subregion offset */
91 uint16 swlim
; /* software subregion boundary */
92 uint16 fbase
; /* fuse subregion offset */
93 uint16 flim
; /* fuse subregion boundary */
94 int otpgu_base
; /* offset to General Use Region */
95 #endif /* BCMIPXOTP */
99 uint size
; /* Size of otp in bytes */
100 uint hwprot
; /* Hardware protection bits */
101 uint signvalid
; /* Signature valid bits */
102 int boundary
; /* hw/sw boundary */
103 #endif /* BCMHNDOTP */
106 static otpinfo_t otpinfo
;
111 * Exported functions:
116 * ipxotp_read_region()
123 #define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
126 /* CC revs 21, 24 and 27 OTP General Use Region word offset */
127 #define REVA4_OTPGU_BASE 12
129 /* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
130 #define REVB8_OTPGU_BASE 20
132 /* CC rev 36 OTP General Use Region word offset */
133 #define REV36_OTPGU_BASE 12
135 /* Subregion word offsets in General Use region */
136 #define OTPGU_HSB_OFF 0
137 #define OTPGU_SFB_OFF 1
138 #define OTPGU_CI_OFF 2
139 #define OTPGU_P_OFF 3
140 #define OTPGU_SROM_OFF 4
142 /* Flag bit offsets in General Use region */
143 #define OTPGU_HWP_OFF 60
144 #define OTPGU_SWP_OFF 61
145 #define OTPGU_CIP_OFF 62
146 #define OTPGU_FUSEP_OFF 63
147 #define OTPGU_CIP_MSK 0x4000
148 #define OTPGU_P_MSK 0xf000
149 #define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
152 #define OTP_SZ_FU_324 ((ROUNDUP(324,8))/8) /* 324 bits */
153 #define OTP_SZ_FU_288 (288/8) /* 288 bits */
154 #define OTP_SZ_FU_216 (216/8) /* 216 bits */
155 #define OTP_SZ_FU_72 (72/8) /* 72 bits */
156 #define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
157 #define OTP4315_SWREG_SZ 178 /* 178 bytes */
158 #define OTP_SZ_FU_144 (144/8) /* 144 bits */
160 static int ipxotp_status(void *oh
)
162 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
163 return (int)(oi
->status
);
166 /* Return size in bytes */
167 static int ipxotp_size(void *oh
)
169 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
170 return (int)oi
->wsize
* 2;
173 static uint16
ipxotp_otpr(void *oh
, chipcregs_t
*cc
, uint wn
)
177 oi
= (otpinfo_t
*) oh
;
179 ASSERT(wn
< oi
->wsize
);
182 return R_REG(oi
->osh
, &cc
->sromotp
[wn
]);
185 static uint16
ipxotp_read_bit(void *oh
, chipcregs_t
*cc
, uint off
)
187 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
191 row
= off
/ oi
->cols
;
192 col
= off
% oi
->cols
;
194 otpp
= OTPP_START_BUSY
|
195 ((OTPPOC_READ
<< OTPP_OC_SHIFT
) & OTPP_OC_MASK
) |
196 ((row
<< OTPP_ROW_SHIFT
) & OTPP_ROW_MASK
) |
197 ((col
<< OTPP_COL_SHIFT
) & OTPP_COL_MASK
);
198 W_REG(oi
->osh
, &cc
->otpprog
, otpp
);
201 ((st
= R_REG(oi
->osh
, &cc
->otpprog
)) & OTPP_START_BUSY
)
202 && (k
< OTPP_TRIES
); k
++) ;
203 if (k
>= OTPP_TRIES
) {
206 if (st
& OTPP_READERR
) {
209 st
= (st
& OTPP_VALUE_MASK
) >> OTPP_VALUE_SHIFT
;
214 /* Calculate max HW/SW region byte size by substracting fuse region and checksum size,
215 * osizew is oi->wsize (OTP size - GU size) in words
217 static int ipxotp_max_rgnsz(si_t
*sih
, int osizew
)
221 switch (CHIPID(sih
->chip
)) {
222 case BCM43224_CHIP_ID
:
223 case BCM43225_CHIP_ID
:
224 ret
= osizew
* 2 - OTP_SZ_FU_72
- OTP_SZ_CHECKSUM
;
226 case BCM4313_CHIP_ID
:
227 ret
= osizew
* 2 - OTP_SZ_FU_72
- OTP_SZ_CHECKSUM
;
230 ASSERT(0); /* Don't konw about this chip */
236 static void BCMNMIATTACHFN(_ipxotp_init
) (otpinfo_t
*oi
, chipcregs_t
*cc
) {
240 /* record word offset of General Use Region for various chipcommon revs */
241 if (oi
->sih
->ccrev
== 21 || oi
->sih
->ccrev
== 24
242 || oi
->sih
->ccrev
== 27) {
243 oi
->otpgu_base
= REVA4_OTPGU_BASE
;
244 } else if (oi
->sih
->ccrev
== 36) {
245 /* OTP size greater than equal to 2KB (128 words), otpgu_base is similar to rev23 */
246 if (oi
->wsize
>= 128)
247 oi
->otpgu_base
= REVB8_OTPGU_BASE
;
249 oi
->otpgu_base
= REV36_OTPGU_BASE
;
250 } else if (oi
->sih
->ccrev
== 23 || oi
->sih
->ccrev
>= 25) {
251 oi
->otpgu_base
= REVB8_OTPGU_BASE
;
254 /* First issue an init command so the status is up to date */
256 OTPP_START_BUSY
| ((OTPPOC_INIT
<< OTPP_OC_SHIFT
) & OTPP_OC_MASK
);
258 W_REG(oi
->osh
, &cc
->otpprog
, otpp
);
260 ((st
= R_REG(oi
->osh
, &cc
->otpprog
)) & OTPP_START_BUSY
)
261 && (k
< OTPP_TRIES
); k
++) ;
262 if (k
>= OTPP_TRIES
) {
266 /* Read OTP lock bits and subregion programmed indication bits */
267 oi
->status
= R_REG(oi
->osh
, &cc
->otpstatus
);
269 if ((CHIPID(oi
->sih
->chip
) == BCM43224_CHIP_ID
)
270 || (CHIPID(oi
->sih
->chip
) == BCM43225_CHIP_ID
)) {
273 (ipxotp_otpr(oi
, cc
, oi
->otpgu_base
+ OTPGU_P_OFF
) &
276 oi
->status
|= (p_bits
<< OTPS_GUP_SHIFT
);
280 * h/w region base and fuse region limit are fixed to the top and
281 * the bottom of the general use region. Everything else can be flexible.
283 oi
->hwbase
= oi
->otpgu_base
+ OTPGU_SROM_OFF
;
284 oi
->hwlim
= oi
->wsize
;
285 if (oi
->status
& OTPS_GUP_HW
) {
287 ipxotp_otpr(oi
, cc
, oi
->otpgu_base
+ OTPGU_HSB_OFF
) / 16;
288 oi
->swbase
= oi
->hwlim
;
290 oi
->swbase
= oi
->hwbase
;
292 /* subtract fuse and checksum from beginning */
293 oi
->swlim
= ipxotp_max_rgnsz(oi
->sih
, oi
->wsize
) / 2;
295 if (oi
->status
& OTPS_GUP_SW
) {
297 ipxotp_otpr(oi
, cc
, oi
->otpgu_base
+ OTPGU_SFB_OFF
) / 16;
298 oi
->fbase
= oi
->swlim
;
300 oi
->fbase
= oi
->swbase
;
302 oi
->flim
= oi
->wsize
;
305 static void *BCMNMIATTACHFN(ipxotp_init
) (si_t
*sih
) {
310 /* Make sure we're running IPX OTP */
311 ASSERT(OTPTYPE_IPX(sih
->ccrev
));
312 if (!OTPTYPE_IPX(sih
->ccrev
))
315 /* Make sure OTP is not disabled */
316 if (si_is_otp_disabled(sih
)) {
320 /* Make sure OTP is powered up */
321 if (!si_is_otp_powered(sih
)) {
327 /* Check for otp size */
328 switch ((sih
->cccaps
& CC_CAP_OTPSIZE
) >> CC_CAP_OTPSIZE_SHIFT
) {
347 case 7: /* 16x64 *//* 1024 bits */
353 /* Don't know the geometry */
357 /* Retrieve OTP region info */
358 idx
= si_coreidx(sih
);
359 cc
= si_setcoreidx(sih
, SI_CC_IDX
);
362 _ipxotp_init(oi
, cc
);
364 si_setcoreidx(sih
, idx
);
369 static int ipxotp_read_region(void *oh
, int region
, uint16
*data
, uint
*wlen
)
371 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
376 /* Validate region selection */
379 sz
= (uint
) oi
->hwlim
- oi
->hwbase
;
380 if (!(oi
->status
& OTPS_GUP_HW
)) {
382 return BCME_NOTFOUND
;
386 return BCME_BUFTOOSHORT
;
391 sz
= ((uint
) oi
->swlim
- oi
->swbase
);
392 if (!(oi
->status
& OTPS_GUP_SW
)) {
394 return BCME_NOTFOUND
;
398 return BCME_BUFTOOSHORT
;
404 if (!(oi
->status
& OTPS_GUP_CI
)) {
406 return BCME_NOTFOUND
;
410 return BCME_BUFTOOSHORT
;
412 base
= oi
->otpgu_base
+ OTPGU_CI_OFF
;
415 sz
= (uint
) oi
->flim
- oi
->fbase
;
416 if (!(oi
->status
& OTPS_GUP_FUSE
)) {
418 return BCME_NOTFOUND
;
422 return BCME_BUFTOOSHORT
;
427 sz
= ((uint
) oi
->flim
- oi
->hwbase
);
428 if (!(oi
->status
& (OTPS_GUP_HW
| OTPS_GUP_SW
))) {
430 return BCME_NOTFOUND
;
434 return BCME_BUFTOOSHORT
;
442 idx
= si_coreidx(oi
->sih
);
443 cc
= si_setcoreidx(oi
->sih
, SI_CC_IDX
);
447 for (i
= 0; i
< sz
; i
++)
448 data
[i
] = ipxotp_otpr(oh
, cc
, base
+ i
);
450 si_setcoreidx(oi
->sih
, idx
);
455 static int ipxotp_nvread(void *oh
, char *data
, uint
*len
)
457 return BCME_UNSUPPORTED
;
460 static otp_fn_t ipxotp_fn
= {
461 (otp_size_t
) ipxotp_size
,
462 (otp_read_bit_t
) ipxotp_read_bit
,
464 (otp_init_t
) ipxotp_init
,
465 (otp_read_region_t
) ipxotp_read_region
,
466 (otp_nvread_t
) ipxotp_nvread
,
468 (otp_status_t
) ipxotp_status
471 #endif /* BCMIPXOTP */
476 * Exported functions:
481 * hndotp_read_region()
488 /* Fields in otpstatus */
489 #define OTPS_PROGFAIL 0x80000000
490 #define OTPS_PROTECT 0x00000007
491 #define OTPS_HW_PROTECT 0x00000001
492 #define OTPS_SW_PROTECT 0x00000002
493 #define OTPS_CID_PROTECT 0x00000004
494 #define OTPS_RCEV_MSK 0x00003f00
495 #define OTPS_RCEV_SHIFT 8
497 /* Fields in the otpcontrol register */
498 #define OTPC_RECWAIT 0xff000000
499 #define OTPC_PROGWAIT 0x00ffff00
500 #define OTPC_PRW_SHIFT 8
501 #define OTPC_MAXFAIL 0x00000038
502 #define OTPC_VSEL 0x00000006
503 #define OTPC_SELVL 0x00000001
505 /* OTP regions (Word offsets from otp size) */
506 #define OTP_SWLIM_OFF (-4)
507 #define OTP_CIDBASE_OFF 0
508 #define OTP_CIDLIM_OFF 4
510 /* Predefined OTP words (Word offset from otp size) */
511 #define OTP_BOUNDARY_OFF (-4)
512 #define OTP_HWSIGN_OFF (-3)
513 #define OTP_SWSIGN_OFF (-2)
514 #define OTP_CIDSIGN_OFF (-1)
515 #define OTP_CID_OFF 0
516 #define OTP_PKG_OFF 1
517 #define OTP_FID_OFF 2
518 #define OTP_RSV_OFF 3
519 #define OTP_LIM_OFF 4
520 #define OTP_RD_OFF 4 /* Redundancy row starts here */
521 #define OTP_RC0_OFF 28 /* Redundancy control word 1 */
522 #define OTP_RC1_OFF 32 /* Redundancy control word 2 */
523 #define OTP_RC_LIM_OFF 36 /* Redundancy control word end */
525 #define OTP_HW_REGION OTPS_HW_PROTECT
526 #define OTP_SW_REGION OTPS_SW_PROTECT
527 #define OTP_CID_REGION OTPS_CID_PROTECT
529 #if OTP_HW_REGION != OTP_HW_RGN
530 #error "incompatible OTP_HW_RGN"
532 #if OTP_SW_REGION != OTP_SW_RGN
533 #error "incompatible OTP_SW_RGN"
535 #if OTP_CID_REGION != OTP_CI_RGN
536 #error "incompatible OTP_CI_RGN"
539 /* Redundancy entry definitions */
540 #define OTP_RCE_ROW_SZ 6
541 #define OTP_RCE_SIGN_MASK 0x7fff
542 #define OTP_RCE_ROW_MASK 0x3f
543 #define OTP_RCE_BITS 21
544 #define OTP_RCE_SIGN_SZ 15
545 #define OTP_RCE_BIT0 1
548 #define OTP_SIGNATURE 0x578a
549 #define OTP_MAGIC 0x4e56
551 static int hndotp_status(void *oh
)
553 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
554 return ((int)(oi
->hwprot
| oi
->signvalid
));
557 static int hndotp_size(void *oh
)
559 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
560 return ((int)(oi
->size
));
563 static uint16
hndotp_otpr(void *oh
, chipcregs_t
*cc
, uint wn
)
565 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
567 volatile uint16
*ptr
;
569 ASSERT(wn
< ((oi
->size
/ 2) + OTP_RC_LIM_OFF
));
572 osh
= si_osh(oi
->sih
);
574 ptr
= (volatile uint16
*)((volatile char *)cc
+ CC_SROM_OTP
);
575 return (R_REG(osh
, &ptr
[wn
]));
578 static uint16
hndotp_otproff(void *oh
, chipcregs_t
*cc
, int woff
)
580 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
582 volatile uint16
*ptr
;
584 ASSERT(woff
>= (-((int)oi
->size
/ 2)));
585 ASSERT(woff
< OTP_LIM_OFF
);
588 osh
= si_osh(oi
->sih
);
590 ptr
= (volatile uint16
*)((volatile char *)cc
+ CC_SROM_OTP
);
592 return (R_REG(osh
, &ptr
[(oi
->size
/ 2) + woff
]));
595 static uint16
hndotp_read_bit(void *oh
, chipcregs_t
*cc
, uint idx
)
597 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
602 osh
= si_osh(oi
->sih
);
606 otpp
= OTPP_START_BUSY
| OTPP_READ
|
607 ((row
<< OTPP_ROW_SHIFT
) & OTPP_ROW_MASK
) | (col
& OTPP_COL_MASK
);
609 W_REG(osh
, &cc
->otpprog
, otpp
);
610 st
= R_REG(osh
, &cc
->otpprog
);
612 ((st
& OTPP_START_BUSY
) == OTPP_START_BUSY
) && (k
< OTPP_TRIES
);
614 st
= R_REG(osh
, &cc
->otpprog
);
616 if (k
>= OTPP_TRIES
) {
619 if (st
& OTPP_READERR
) {
622 st
= (st
& OTPP_VALUE_MASK
) >> OTPP_VALUE_SHIFT
;
626 static void *BCMNMIATTACHFN(hndotp_init
) (si_t
*sih
) {
630 uint32 cap
= 0, clkdiv
, otpdiv
= 0;
636 idx
= si_coreidx(sih
);
637 osh
= si_osh(oi
->sih
);
640 if ((cc
= si_setcoreidx(sih
, SI_CC_IDX
)) != NULL
) {
641 cap
= R_REG(osh
, &cc
->capabilities
);
642 if ((cap
& CC_CAP_OTPSIZE
) == 0) {
647 /* As of right now, support only 4320a2, 4311a1 and 4312 */
648 ASSERT((oi
->ccrev
== 12) || (oi
->ccrev
== 17)
649 || (oi
->ccrev
== 22));
651 ((oi
->ccrev
== 12) || (oi
->ccrev
== 17)
652 || (oi
->ccrev
== 22)))
655 /* Read the OTP byte size. chipcommon rev >= 18 has RCE so the size is
656 * 8 row (64 bytes) smaller
659 1 << (((cap
& CC_CAP_OTPSIZE
) >> CC_CAP_OTPSIZE_SHIFT
)
660 + CC_CAP_OTPSIZE_BASE
);
662 oi
->size
-= ((OTP_RC0_OFF
- OTP_BOUNDARY_OFF
) * 2);
664 oi
->hwprot
= (int)(R_REG(osh
, &cc
->otpstatus
) & OTPS_PROTECT
);
667 /* Check the region signature */
668 if (hndotp_otproff(oi
, cc
, OTP_HWSIGN_OFF
) == OTP_SIGNATURE
) {
669 oi
->signvalid
|= OTP_HW_REGION
;
670 oi
->boundary
= hndotp_otproff(oi
, cc
, OTP_BOUNDARY_OFF
);
673 if (hndotp_otproff(oi
, cc
, OTP_SWSIGN_OFF
) == OTP_SIGNATURE
)
674 oi
->signvalid
|= OTP_SW_REGION
;
676 if (hndotp_otproff(oi
, cc
, OTP_CIDSIGN_OFF
) == OTP_SIGNATURE
)
677 oi
->signvalid
|= OTP_CID_REGION
;
679 /* Set OTP clkdiv for stability */
684 clkdiv
= R_REG(osh
, &cc
->clkdiv
);
686 (clkdiv
& ~CLKD_OTP
) | (otpdiv
<< CLKD_OTP_SHIFT
);
687 W_REG(osh
, &cc
->clkdiv
, clkdiv
);
695 si_setcoreidx(sih
, idx
);
700 static int hndotp_read_region(void *oh
, int region
, uint16
*data
, uint
*wlen
)
702 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
707 /* Only support HW region (no active chips use HND OTP SW region) */
708 ASSERT(region
== OTP_HW_REGION
);
711 st
= oi
->hwprot
| oi
->signvalid
;
712 if ((st
& region
) == 0)
713 return BCME_NOTFOUND
;
716 ((int)*wlen
< oi
->boundary
/ 2) ? *wlen
: (uint
) oi
->boundary
/ 2;
718 idx
= si_coreidx(oi
->sih
);
719 cc
= si_setcoreidx(oi
->sih
, SI_CC_IDX
);
722 for (i
= 0; i
< (int)*wlen
; i
++)
723 data
[i
] = hndotp_otpr(oh
, cc
, i
);
725 si_setcoreidx(oi
->sih
, idx
);
730 static int hndotp_nvread(void *oh
, char *data
, uint
*len
)
733 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
734 uint32 base
, bound
, lim
= 0, st
;
735 int i
, chunk
, gchunks
, tsz
= 0;
739 uint16
*rawotp
= NULL
;
741 /* save the orig core */
742 idx
= si_coreidx(oi
->sih
);
743 cc
= si_setcoreidx(oi
->sih
, SI_CC_IDX
);
746 st
= hndotp_status(oh
);
747 if (!(st
& (OTP_HW_REGION
| OTP_SW_REGION
))) {
752 /* Read the whole otp so we can easily manipulate it */
753 lim
= hndotp_size(oh
);
754 if ((rawotp
= MALLOC(si_osh(oi
->sih
), lim
)) == NULL
) {
758 for (i
= 0; i
< (int)(lim
/ 2); i
++)
759 rawotp
[i
] = hndotp_otpr(oh
, cc
, i
);
761 if ((st
& OTP_HW_REGION
) == 0) {
762 /* This could be a programming failure in the first
763 * chunk followed by one or more good chunks
765 for (i
= 0; i
< (int)(lim
/ 2); i
++)
766 if (rawotp
[i
] == OTP_MAGIC
)
769 if (i
< (int)(lim
/ 2)) {
771 bound
= (i
* 2) + rawotp
[i
+ 1];
777 bound
= rawotp
[(lim
/ 2) + OTP_BOUNDARY_OFF
];
779 /* There are two cases: 1) The whole otp is used as nvram
780 * and 2) There is a hardware header followed by nvram.
782 if (rawotp
[0] == OTP_MAGIC
) {
788 /* Find and copy the data */
794 while ((i
< (int)(lim
/ 2)) && (rawotp
[i
] == OTP_MAGIC
)) {
795 int dsz
, rsz
= rawotp
[i
+ 1];
797 if (((i
* 2) + rsz
) >= (int)lim
) {
798 /* Bad length, try to find another chunk anyway */
801 if (hndcrc16((uint8
*) & rawotp
[i
], rsz
,
802 CRC16_INIT_VALUE
) == CRC16_GOOD_VALUE
) {
803 /* Good crc, copy the vars */
807 if (offset
+ dsz
>= *len
) {
810 bcopy((char *)&rawotp
[i
+ 2], &data
[offset
], dsz
);
812 /* Remove extra null characters at the end */
814 data
[offset
- 1] == 0 && data
[offset
- 2] == 0)
818 /* bad length or crc didn't check, try to find the next set */
819 if (rawotp
[i
+ (rsz
/ 2)] == OTP_MAGIC
) {
820 /* Assume length is good */
823 while (++i
< (int)(lim
/ 2))
824 if (rawotp
[i
] == OTP_MAGIC
)
835 MFREE(si_osh(oi
->sih
), rawotp
, lim
);
836 si_setcoreidx(oi
->sih
, idx
);
841 static otp_fn_t hndotp_fn
= {
842 (otp_size_t
) hndotp_size
,
843 (otp_read_bit_t
) hndotp_read_bit
,
845 (otp_init_t
) hndotp_init
,
846 (otp_read_region_t
) hndotp_read_region
,
847 (otp_nvread_t
) hndotp_nvread
,
849 (otp_status_t
) hndotp_status
852 #endif /* BCMHNDOTP */
855 * Common Code: Compiled for IPX / HND / AUTO
864 int otp_status(void *oh
)
866 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
868 return oi
->fn
->status(oh
);
871 int otp_size(void *oh
)
873 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
875 return oi
->fn
->size(oh
);
878 uint16
otp_read_bit(void *oh
, uint offset
)
880 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
881 uint idx
= si_coreidx(oi
->sih
);
882 chipcregs_t
*cc
= si_setcoreidx(oi
->sih
, SI_CC_IDX
);
883 uint16 readBit
= (uint16
) oi
->fn
->read_bit(oh
, cc
, offset
);
884 si_setcoreidx(oi
->sih
, idx
);
888 void *BCMNMIATTACHFN(otp_init
) (si_t
*sih
) {
893 bzero(oi
, sizeof(otpinfo_t
));
895 oi
->ccrev
= sih
->ccrev
;
898 if (OTPTYPE_IPX(oi
->ccrev
))
903 if (OTPTYPE_HND(oi
->ccrev
))
907 if (oi
->fn
== NULL
) {
912 oi
->osh
= si_osh(oi
->sih
);
914 ret
= (oi
->fn
->init
) (sih
);
920 BCMNMIATTACHFN(otp_read_region
) (si_t
*sih
, int region
, uint16
*data
,
926 if (!(wasup
= si_is_otp_powered(sih
)))
927 si_otp_power(sih
, TRUE
);
929 if (!si_is_otp_powered(sih
) || si_is_otp_disabled(sih
)) {
940 err
= (((otpinfo_t
*) oh
)->fn
->read_region
) (oh
, region
, data
, wlen
);
944 si_otp_power(sih
, FALSE
);
949 int otp_nvread(void *oh
, char *data
, uint
*len
)
951 otpinfo_t
*oi
= (otpinfo_t
*) oh
;
953 return oi
->fn
->nvread(oh
, data
, len
);