staging: brcm80211: fix 'ERROR: "foo * bar" should be "foo *bar"'
[linux-2.6/libata-dev.git] / drivers / staging / brcm80211 / util / bcmotp.c
blob88e872065e44d20190a7c2a4995c78009331f7f8
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <typedefs.h>
18 #include <bcmdefs.h>
19 #include <osl.h>
20 #include <bcmdevs.h>
21 #include <bcmutils.h>
22 #include <siutils.h>
23 #include <bcmendian.h>
24 #include <hndsoc.h>
25 #include <sbchipc.h>
26 #include <bcmotp.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)
42 #define BCMHNDOTP 1
43 #define BCMIPXOTP 1
44 #endif
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 */
51 #ifdef BCMIPXOTP
52 #define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
53 #endif
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,
61 uint *wlen);
62 typedef int (*otp_nvread_t) (void *oh, char *data, uint *len);
64 /* OTP function struct */
65 typedef struct otp_fn_s {
66 otp_size_t size;
67 otp_read_bit_t read_bit;
68 otp_init_t init;
69 otp_read_region_t read_region;
70 otp_nvread_t nvread;
71 otp_status_t status;
72 } otp_fn_t;
74 typedef struct {
75 uint ccrev; /* chipc revision */
76 otp_fn_t *fn; /* OTP functions */
77 si_t *sih; /* Saved sb handle */
78 osl_t *osh;
80 #ifdef BCMIPXOTP
81 /* IPX OTP section */
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 */
97 #ifdef BCMHNDOTP
98 /* HND OTP section */
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 */
104 } otpinfo_t;
106 static otpinfo_t otpinfo;
109 * IPX OTP Code
111 * Exported functions:
112 * ipxotp_status()
113 * ipxotp_size()
114 * ipxotp_init()
115 * ipxotp_read_bit()
116 * ipxotp_read_region()
117 * ipxotp_nvread()
121 #ifdef BCMIPXOTP
123 #define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
125 /* OTP layout */
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)
151 /* OTP Size */
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)
175 otpinfo_t *oi;
177 oi = (otpinfo_t *) oh;
179 ASSERT(wn < oi->wsize);
180 ASSERT(cc != NULL);
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;
188 uint k, row, col;
189 uint32 otpp, st;
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);
200 for (k = 0;
201 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY)
202 && (k < OTPP_TRIES); k++) ;
203 if (k >= OTPP_TRIES) {
204 return 0xffff;
206 if (st & OTPP_READERR) {
207 return 0xffff;
209 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
211 return (int)st;
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)
219 int ret = 0;
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;
225 break;
226 case BCM4313_CHIP_ID:
227 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
228 break;
229 default:
230 ASSERT(0); /* Don't konw about this chip */
233 return ret;
236 static void BCMNMIATTACHFN(_ipxotp_init) (otpinfo_t *oi, chipcregs_t *cc) {
237 uint k;
238 uint32 otpp, st;
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;
248 else
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 */
255 otpp =
256 OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
258 W_REG(oi->osh, &cc->otpprog, otpp);
259 for (k = 0;
260 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY)
261 && (k < OTPP_TRIES); k++) ;
262 if (k >= OTPP_TRIES) {
263 return;
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)) {
271 uint32 p_bits;
272 p_bits =
273 (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
274 OTPGU_P_MSK)
275 >> OTPGU_P_SHIFT;
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) {
286 oi->hwlim =
287 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
288 oi->swbase = oi->hwlim;
289 } else
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) {
296 oi->swlim =
297 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
298 oi->fbase = oi->swlim;
299 } else
300 oi->fbase = oi->swbase;
302 oi->flim = oi->wsize;
305 static void *BCMNMIATTACHFN(ipxotp_init) (si_t *sih) {
306 uint idx;
307 chipcregs_t *cc;
308 otpinfo_t *oi;
310 /* Make sure we're running IPX OTP */
311 ASSERT(OTPTYPE_IPX(sih->ccrev));
312 if (!OTPTYPE_IPX(sih->ccrev))
313 return NULL;
315 /* Make sure OTP is not disabled */
316 if (si_is_otp_disabled(sih)) {
317 return NULL;
320 /* Make sure OTP is powered up */
321 if (!si_is_otp_powered(sih)) {
322 return NULL;
325 oi = &otpinfo;
327 /* Check for otp size */
328 switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
329 case 0:
330 /* Nothing there */
331 return NULL;
332 case 1: /* 32x64 */
333 oi->rows = 32;
334 oi->cols = 64;
335 oi->wsize = 128;
336 break;
337 case 2: /* 64x64 */
338 oi->rows = 64;
339 oi->cols = 64;
340 oi->wsize = 256;
341 break;
342 case 5: /* 96x64 */
343 oi->rows = 96;
344 oi->cols = 64;
345 oi->wsize = 384;
346 break;
347 case 7: /* 16x64 *//* 1024 bits */
348 oi->rows = 16;
349 oi->cols = 64;
350 oi->wsize = 64;
351 break;
352 default:
353 /* Don't know the geometry */
354 return NULL;
357 /* Retrieve OTP region info */
358 idx = si_coreidx(sih);
359 cc = si_setcoreidx(sih, SI_CC_IDX);
360 ASSERT(cc != NULL);
362 _ipxotp_init(oi, cc);
364 si_setcoreidx(sih, idx);
366 return (void *)oi;
369 static int ipxotp_read_region(void *oh, int region, uint16 *data, uint *wlen)
371 otpinfo_t *oi = (otpinfo_t *) oh;
372 uint idx;
373 chipcregs_t *cc;
374 uint base, i, sz;
376 /* Validate region selection */
377 switch (region) {
378 case OTP_HW_RGN:
379 sz = (uint) oi->hwlim - oi->hwbase;
380 if (!(oi->status & OTPS_GUP_HW)) {
381 *wlen = sz;
382 return BCME_NOTFOUND;
384 if (*wlen < sz) {
385 *wlen = sz;
386 return BCME_BUFTOOSHORT;
388 base = oi->hwbase;
389 break;
390 case OTP_SW_RGN:
391 sz = ((uint) oi->swlim - oi->swbase);
392 if (!(oi->status & OTPS_GUP_SW)) {
393 *wlen = sz;
394 return BCME_NOTFOUND;
396 if (*wlen < sz) {
397 *wlen = sz;
398 return BCME_BUFTOOSHORT;
400 base = oi->swbase;
401 break;
402 case OTP_CI_RGN:
403 sz = OTPGU_CI_SZ;
404 if (!(oi->status & OTPS_GUP_CI)) {
405 *wlen = sz;
406 return BCME_NOTFOUND;
408 if (*wlen < sz) {
409 *wlen = sz;
410 return BCME_BUFTOOSHORT;
412 base = oi->otpgu_base + OTPGU_CI_OFF;
413 break;
414 case OTP_FUSE_RGN:
415 sz = (uint) oi->flim - oi->fbase;
416 if (!(oi->status & OTPS_GUP_FUSE)) {
417 *wlen = sz;
418 return BCME_NOTFOUND;
420 if (*wlen < sz) {
421 *wlen = sz;
422 return BCME_BUFTOOSHORT;
424 base = oi->fbase;
425 break;
426 case OTP_ALL_RGN:
427 sz = ((uint) oi->flim - oi->hwbase);
428 if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
429 *wlen = sz;
430 return BCME_NOTFOUND;
432 if (*wlen < sz) {
433 *wlen = sz;
434 return BCME_BUFTOOSHORT;
436 base = oi->hwbase;
437 break;
438 default:
439 return BCME_BADARG;
442 idx = si_coreidx(oi->sih);
443 cc = si_setcoreidx(oi->sih, SI_CC_IDX);
444 ASSERT(cc != NULL);
446 /* Read the data */
447 for (i = 0; i < sz; i++)
448 data[i] = ipxotp_otpr(oh, cc, base + i);
450 si_setcoreidx(oi->sih, idx);
451 *wlen = sz;
452 return 0;
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 */
474 * HND OTP Code
476 * Exported functions:
477 * hndotp_status()
478 * hndotp_size()
479 * hndotp_init()
480 * hndotp_read_bit()
481 * hndotp_read_region()
482 * hndotp_nvread()
486 #ifdef BCMHNDOTP
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"
531 #endif
532 #if OTP_SW_REGION != OTP_SW_RGN
533 #error "incompatible OTP_SW_RGN"
534 #endif
535 #if OTP_CID_REGION != OTP_CI_RGN
536 #error "incompatible OTP_CI_RGN"
537 #endif
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
547 #define OTP_WPR 4
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;
566 osl_t *osh;
567 volatile uint16 *ptr;
569 ASSERT(wn < ((oi->size / 2) + OTP_RC_LIM_OFF));
570 ASSERT(cc != NULL);
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;
581 osl_t *osh;
582 volatile uint16 *ptr;
584 ASSERT(woff >= (-((int)oi->size / 2)));
585 ASSERT(woff < OTP_LIM_OFF);
586 ASSERT(cc != NULL);
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;
598 uint k, row, col;
599 uint32 otpp, st;
600 osl_t *osh;
602 osh = si_osh(oi->sih);
603 row = idx / 65;
604 col = idx % 65;
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);
611 for (k = 0;
612 ((st & OTPP_START_BUSY) == OTPP_START_BUSY) && (k < OTPP_TRIES);
613 k++)
614 st = R_REG(osh, &cc->otpprog);
616 if (k >= OTPP_TRIES) {
617 return 0xffff;
619 if (st & OTPP_READERR) {
620 return 0xffff;
622 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
623 return (uint16) st;
626 static void *BCMNMIATTACHFN(hndotp_init) (si_t *sih) {
627 uint idx;
628 chipcregs_t *cc;
629 otpinfo_t *oi;
630 uint32 cap = 0, clkdiv, otpdiv = 0;
631 void *ret = NULL;
632 osl_t *osh;
634 oi = &otpinfo;
636 idx = si_coreidx(sih);
637 osh = si_osh(oi->sih);
639 /* Check for otp */
640 if ((cc = si_setcoreidx(sih, SI_CC_IDX)) != NULL) {
641 cap = R_REG(osh, &cc->capabilities);
642 if ((cap & CC_CAP_OTPSIZE) == 0) {
643 /* Nothing there */
644 goto out;
647 /* As of right now, support only 4320a2, 4311a1 and 4312 */
648 ASSERT((oi->ccrev == 12) || (oi->ccrev == 17)
649 || (oi->ccrev == 22));
650 if (!
651 ((oi->ccrev == 12) || (oi->ccrev == 17)
652 || (oi->ccrev == 22)))
653 return NULL;
655 /* Read the OTP byte size. chipcommon rev >= 18 has RCE so the size is
656 * 8 row (64 bytes) smaller
658 oi->size =
659 1 << (((cap & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT)
660 + CC_CAP_OTPSIZE_BASE);
661 if (oi->ccrev >= 18)
662 oi->size -= ((OTP_RC0_OFF - OTP_BOUNDARY_OFF) * 2);
664 oi->hwprot = (int)(R_REG(osh, &cc->otpstatus) & OTPS_PROTECT);
665 oi->boundary = -1;
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 */
680 if (oi->ccrev == 22)
681 otpdiv = 12;
683 if (otpdiv) {
684 clkdiv = R_REG(osh, &cc->clkdiv);
685 clkdiv =
686 (clkdiv & ~CLKD_OTP) | (otpdiv << CLKD_OTP_SHIFT);
687 W_REG(osh, &cc->clkdiv, clkdiv);
689 OSL_DELAY(10);
691 ret = (void *)oi;
694 out: /* All done */
695 si_setcoreidx(sih, idx);
697 return ret;
700 static int hndotp_read_region(void *oh, int region, uint16 *data, uint *wlen)
702 otpinfo_t *oi = (otpinfo_t *) oh;
703 uint32 idx, st;
704 chipcregs_t *cc;
705 int i;
707 /* Only support HW region (no active chips use HND OTP SW region) */
708 ASSERT(region == OTP_HW_REGION);
710 /* Region empty? */
711 st = oi->hwprot | oi->signvalid;
712 if ((st & region) == 0)
713 return BCME_NOTFOUND;
715 *wlen =
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);
720 ASSERT(cc != NULL);
722 for (i = 0; i < (int)*wlen; i++)
723 data[i] = hndotp_otpr(oh, cc, i);
725 si_setcoreidx(oi->sih, idx);
727 return 0;
730 static int hndotp_nvread(void *oh, char *data, uint *len)
732 int rc = 0;
733 otpinfo_t *oi = (otpinfo_t *) oh;
734 uint32 base, bound, lim = 0, st;
735 int i, chunk, gchunks, tsz = 0;
736 uint32 idx;
737 chipcregs_t *cc;
738 uint offset;
739 uint16 *rawotp = NULL;
741 /* save the orig core */
742 idx = si_coreidx(oi->sih);
743 cc = si_setcoreidx(oi->sih, SI_CC_IDX);
744 ASSERT(cc != NULL);
746 st = hndotp_status(oh);
747 if (!(st & (OTP_HW_REGION | OTP_SW_REGION))) {
748 rc = -1;
749 goto out;
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) {
755 rc = -2;
756 goto out;
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)
767 break;
769 if (i < (int)(lim / 2)) {
770 base = i;
771 bound = (i * 2) + rawotp[i + 1];
772 } else {
773 rc = -3;
774 goto out;
776 } else {
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) {
783 base = 0;
784 } else
785 base = bound;
788 /* Find and copy the data */
790 chunk = 0;
791 gchunks = 0;
792 i = base / 2;
793 offset = 0;
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 */
799 rsz = 6;
801 if (hndcrc16((uint8 *) & rawotp[i], rsz,
802 CRC16_INIT_VALUE) == CRC16_GOOD_VALUE) {
803 /* Good crc, copy the vars */
804 gchunks++;
805 dsz = rsz - 6;
806 tsz += dsz;
807 if (offset + dsz >= *len) {
808 goto out;
810 bcopy((char *)&rawotp[i + 2], &data[offset], dsz);
811 offset += dsz;
812 /* Remove extra null characters at the end */
813 while (offset > 1 &&
814 data[offset - 1] == 0 && data[offset - 2] == 0)
815 offset--;
816 i += rsz / 2;
817 } else {
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 */
821 i += rsz / 2;
822 } else {
823 while (++i < (int)(lim / 2))
824 if (rawotp[i] == OTP_MAGIC)
825 break;
828 chunk++;
831 *len = offset;
833 out:
834 if (rawotp)
835 MFREE(si_osh(oi->sih), rawotp, lim);
836 si_setcoreidx(oi->sih, idx);
838 return rc;
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
856 * otp_status()
857 * otp_size()
858 * otp_read_bit()
859 * otp_init()
860 * otp_read_region()
861 * otp_nvread()
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);
885 return readBit;
888 void *BCMNMIATTACHFN(otp_init) (si_t *sih) {
889 otpinfo_t *oi;
890 void *ret = NULL;
892 oi = &otpinfo;
893 bzero(oi, sizeof(otpinfo_t));
895 oi->ccrev = sih->ccrev;
897 #ifdef BCMIPXOTP
898 if (OTPTYPE_IPX(oi->ccrev))
899 oi->fn = &ipxotp_fn;
900 #endif
902 #ifdef BCMHNDOTP
903 if (OTPTYPE_HND(oi->ccrev))
904 oi->fn = &hndotp_fn;
905 #endif
907 if (oi->fn == NULL) {
908 return NULL;
911 oi->sih = sih;
912 oi->osh = si_osh(oi->sih);
914 ret = (oi->fn->init) (sih);
916 return ret;
920 BCMNMIATTACHFN(otp_read_region) (si_t *sih, int region, uint16 *data,
921 uint *wlen) {
922 bool wasup = FALSE;
923 void *oh;
924 int err = 0;
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)) {
930 err = BCME_NOTREADY;
931 goto out;
934 oh = otp_init(sih);
935 if (oh == NULL) {
936 err = BCME_ERROR;
937 goto out;
940 err = (((otpinfo_t *) oh)->fn->read_region) (oh, region, data, wlen);
942 out:
943 if (!wasup)
944 si_otp_power(sih, FALSE);
946 return err;
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);