]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/brcm80211/util/bcmotp.c
staging: brcm80211: fix "ERROR: do not use assignment in if condition"
[net-next-2.6.git] / drivers / staging / brcm80211 / util / bcmotp.c
CommitLineData
a9533e7e
HP
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
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.
7 *
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.
15 */
16
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"
28
29/*
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
33 *
34 * Define BCMHNDOTP to include support for the HND OTP controller.
35 * Define BCMIPXOTP to include support for the IPX OTP controller.
36 *
37 * NOTE 1: More than one may be defined
38 * NOTE 2: If none are defined, the default is to include them all.
39 */
40
41#if !defined(BCMHNDOTP) && !defined(BCMIPXOTP)
42#define BCMHNDOTP 1
43#define BCMIPXOTP 1
44#endif
45
46#define OTPTYPE_HND(ccrev) ((ccrev) < 21 || (ccrev) == 22)
47#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
48
49#define OTPP_TRIES 10000000 /* # of tries for OTPP */
50
51#ifdef BCMIPXOTP
52#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
53#endif
54
55/* OTP common function type */
56typedef int (*otp_status_t) (void *oh);
57typedef int (*otp_size_t) (void *oh);
7cc4a4c0
JC
58typedef void *(*otp_init_t) (si_t *sih);
59typedef uint16(*otp_read_bit_t) (void *oh, chipcregs_t *cc, uint off);
60typedef int (*otp_read_region_t) (si_t *sih, int region, uint16 *data,
61 uint *wlen);
62typedef int (*otp_nvread_t) (void *oh, char *data, uint *len);
a9533e7e
HP
63
64/* OTP function struct */
65typedef 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;
73
74typedef struct {
75 uint ccrev; /* chipc revision */
76 otp_fn_t *fn; /* OTP functions */
77 si_t *sih; /* Saved sb handle */
78 osl_t *osh;
79
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)
87 */
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 */
96
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;
105
106static otpinfo_t otpinfo;
107
108/*
109 * IPX OTP Code
110 *
111 * Exported functions:
112 * ipxotp_status()
113 * ipxotp_size()
114 * ipxotp_init()
115 * ipxotp_read_bit()
116 * ipxotp_read_region()
117 * ipxotp_nvread()
118 *
119 */
120
121#ifdef BCMIPXOTP
122
123#define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
124
125/* OTP layout */
126/* CC revs 21, 24 and 27 OTP General Use Region word offset */
127#define REVA4_OTPGU_BASE 12
128
129/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
130#define REVB8_OTPGU_BASE 20
131
132/* CC rev 36 OTP General Use Region word offset */
133#define REV36_OTPGU_BASE 12
134
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
141
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)
150
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 */
159
160static int ipxotp_status(void *oh)
161{
162 otpinfo_t *oi = (otpinfo_t *) oh;
163 return (int)(oi->status);
164}
165
166/* Return size in bytes */
167static int ipxotp_size(void *oh)
168{
169 otpinfo_t *oi = (otpinfo_t *) oh;
170 return (int)oi->wsize * 2;
171}
172
7cc4a4c0 173static uint16 ipxotp_otpr(void *oh, chipcregs_t *cc, uint wn)
a9533e7e
HP
174{
175 otpinfo_t *oi;
176
177 oi = (otpinfo_t *) oh;
178
179 ASSERT(wn < oi->wsize);
180 ASSERT(cc != NULL);
181
182 return R_REG(oi->osh, &cc->sromotp[wn]);
183}
184
7cc4a4c0 185static uint16 ipxotp_read_bit(void *oh, chipcregs_t *cc, uint off)
a9533e7e
HP
186{
187 otpinfo_t *oi = (otpinfo_t *) oh;
188 uint k, row, col;
189 uint32 otpp, st;
190
191 row = off / oi->cols;
192 col = off % oi->cols;
193
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);
199
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;
205 }
206 if (st & OTPP_READERR) {
207 return 0xffff;
208 }
209 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
210
211 return (int)st;
212}
213
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
216 */
7cc4a4c0 217static int ipxotp_max_rgnsz(si_t *sih, int osizew)
a9533e7e
HP
218{
219 int ret = 0;
220
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 */
231 }
232
233 return ret;
234}
235
a2627bc0
JC
236static void BCMNMIATTACHFN(_ipxotp_init) (otpinfo_t *oi, chipcregs_t *cc)
237{
a9533e7e
HP
238 uint k;
239 uint32 otpp, st;
240
241 /* record word offset of General Use Region for various chipcommon revs */
242 if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24
243 || oi->sih->ccrev == 27) {
244 oi->otpgu_base = REVA4_OTPGU_BASE;
245 } else if (oi->sih->ccrev == 36) {
246 /* OTP size greater than equal to 2KB (128 words), otpgu_base is similar to rev23 */
247 if (oi->wsize >= 128)
248 oi->otpgu_base = REVB8_OTPGU_BASE;
249 else
250 oi->otpgu_base = REV36_OTPGU_BASE;
251 } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) {
252 oi->otpgu_base = REVB8_OTPGU_BASE;
253 }
254
255 /* First issue an init command so the status is up to date */
256 otpp =
257 OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
258
259 W_REG(oi->osh, &cc->otpprog, otpp);
260 for (k = 0;
261 ((st = R_REG(oi->osh, &cc->otpprog)) & OTPP_START_BUSY)
262 && (k < OTPP_TRIES); k++) ;
263 if (k >= OTPP_TRIES) {
264 return;
265 }
266
267 /* Read OTP lock bits and subregion programmed indication bits */
268 oi->status = R_REG(oi->osh, &cc->otpstatus);
269
270 if ((CHIPID(oi->sih->chip) == BCM43224_CHIP_ID)
271 || (CHIPID(oi->sih->chip) == BCM43225_CHIP_ID)) {
272 uint32 p_bits;
273 p_bits =
274 (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
275 OTPGU_P_MSK)
276 >> OTPGU_P_SHIFT;
277 oi->status |= (p_bits << OTPS_GUP_SHIFT);
278 }
279
280 /*
281 * h/w region base and fuse region limit are fixed to the top and
282 * the bottom of the general use region. Everything else can be flexible.
283 */
284 oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
285 oi->hwlim = oi->wsize;
286 if (oi->status & OTPS_GUP_HW) {
287 oi->hwlim =
288 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
289 oi->swbase = oi->hwlim;
290 } else
291 oi->swbase = oi->hwbase;
292
293 /* subtract fuse and checksum from beginning */
294 oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
295
296 if (oi->status & OTPS_GUP_SW) {
297 oi->swlim =
298 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
299 oi->fbase = oi->swlim;
300 } else
301 oi->fbase = oi->swbase;
302
303 oi->flim = oi->wsize;
304}
305
a2627bc0
JC
306static void *BCMNMIATTACHFN(ipxotp_init) (si_t *sih)
307{
a9533e7e
HP
308 uint idx;
309 chipcregs_t *cc;
310 otpinfo_t *oi;
311
312 /* Make sure we're running IPX OTP */
313 ASSERT(OTPTYPE_IPX(sih->ccrev));
314 if (!OTPTYPE_IPX(sih->ccrev))
315 return NULL;
316
317 /* Make sure OTP is not disabled */
318 if (si_is_otp_disabled(sih)) {
319 return NULL;
320 }
321
322 /* Make sure OTP is powered up */
323 if (!si_is_otp_powered(sih)) {
324 return NULL;
325 }
326
327 oi = &otpinfo;
328
329 /* Check for otp size */
330 switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
331 case 0:
332 /* Nothing there */
333 return NULL;
334 case 1: /* 32x64 */
335 oi->rows = 32;
336 oi->cols = 64;
337 oi->wsize = 128;
338 break;
339 case 2: /* 64x64 */
340 oi->rows = 64;
341 oi->cols = 64;
342 oi->wsize = 256;
343 break;
344 case 5: /* 96x64 */
345 oi->rows = 96;
346 oi->cols = 64;
347 oi->wsize = 384;
348 break;
349 case 7: /* 16x64 *//* 1024 bits */
350 oi->rows = 16;
351 oi->cols = 64;
352 oi->wsize = 64;
353 break;
354 default:
355 /* Don't know the geometry */
356 return NULL;
357 }
358
359 /* Retrieve OTP region info */
360 idx = si_coreidx(sih);
361 cc = si_setcoreidx(sih, SI_CC_IDX);
362 ASSERT(cc != NULL);
363
364 _ipxotp_init(oi, cc);
365
366 si_setcoreidx(sih, idx);
367
368 return (void *)oi;
369}
370
7cc4a4c0 371static int ipxotp_read_region(void *oh, int region, uint16 *data, uint *wlen)
a9533e7e
HP
372{
373 otpinfo_t *oi = (otpinfo_t *) oh;
374 uint idx;
375 chipcregs_t *cc;
376 uint base, i, sz;
377
378 /* Validate region selection */
379 switch (region) {
380 case OTP_HW_RGN:
381 sz = (uint) oi->hwlim - oi->hwbase;
382 if (!(oi->status & OTPS_GUP_HW)) {
383 *wlen = sz;
384 return BCME_NOTFOUND;
385 }
386 if (*wlen < sz) {
387 *wlen = sz;
388 return BCME_BUFTOOSHORT;
389 }
390 base = oi->hwbase;
391 break;
392 case OTP_SW_RGN:
393 sz = ((uint) oi->swlim - oi->swbase);
394 if (!(oi->status & OTPS_GUP_SW)) {
395 *wlen = sz;
396 return BCME_NOTFOUND;
397 }
398 if (*wlen < sz) {
399 *wlen = sz;
400 return BCME_BUFTOOSHORT;
401 }
402 base = oi->swbase;
403 break;
404 case OTP_CI_RGN:
405 sz = OTPGU_CI_SZ;
406 if (!(oi->status & OTPS_GUP_CI)) {
407 *wlen = sz;
408 return BCME_NOTFOUND;
409 }
410 if (*wlen < sz) {
411 *wlen = sz;
412 return BCME_BUFTOOSHORT;
413 }
414 base = oi->otpgu_base + OTPGU_CI_OFF;
415 break;
416 case OTP_FUSE_RGN:
417 sz = (uint) oi->flim - oi->fbase;
418 if (!(oi->status & OTPS_GUP_FUSE)) {
419 *wlen = sz;
420 return BCME_NOTFOUND;
421 }
422 if (*wlen < sz) {
423 *wlen = sz;
424 return BCME_BUFTOOSHORT;
425 }
426 base = oi->fbase;
427 break;
428 case OTP_ALL_RGN:
429 sz = ((uint) oi->flim - oi->hwbase);
430 if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
431 *wlen = sz;
432 return BCME_NOTFOUND;
433 }
434 if (*wlen < sz) {
435 *wlen = sz;
436 return BCME_BUFTOOSHORT;
437 }
438 base = oi->hwbase;
439 break;
440 default:
441 return BCME_BADARG;
442 }
443
444 idx = si_coreidx(oi->sih);
445 cc = si_setcoreidx(oi->sih, SI_CC_IDX);
446 ASSERT(cc != NULL);
447
448 /* Read the data */
449 for (i = 0; i < sz; i++)
450 data[i] = ipxotp_otpr(oh, cc, base + i);
451
452 si_setcoreidx(oi->sih, idx);
453 *wlen = sz;
454 return 0;
455}
456
7cc4a4c0 457static int ipxotp_nvread(void *oh, char *data, uint *len)
a9533e7e
HP
458{
459 return BCME_UNSUPPORTED;
460}
461
462static otp_fn_t ipxotp_fn = {
463 (otp_size_t) ipxotp_size,
464 (otp_read_bit_t) ipxotp_read_bit,
465
466 (otp_init_t) ipxotp_init,
467 (otp_read_region_t) ipxotp_read_region,
468 (otp_nvread_t) ipxotp_nvread,
469
470 (otp_status_t) ipxotp_status
471};
472
473#endif /* BCMIPXOTP */
474
475/*
476 * HND OTP Code
477 *
478 * Exported functions:
479 * hndotp_status()
480 * hndotp_size()
481 * hndotp_init()
482 * hndotp_read_bit()
483 * hndotp_read_region()
484 * hndotp_nvread()
485 *
486 */
487
488#ifdef BCMHNDOTP
489
490/* Fields in otpstatus */
491#define OTPS_PROGFAIL 0x80000000
492#define OTPS_PROTECT 0x00000007
493#define OTPS_HW_PROTECT 0x00000001
494#define OTPS_SW_PROTECT 0x00000002
495#define OTPS_CID_PROTECT 0x00000004
496#define OTPS_RCEV_MSK 0x00003f00
497#define OTPS_RCEV_SHIFT 8
498
499/* Fields in the otpcontrol register */
500#define OTPC_RECWAIT 0xff000000
501#define OTPC_PROGWAIT 0x00ffff00
502#define OTPC_PRW_SHIFT 8
503#define OTPC_MAXFAIL 0x00000038
504#define OTPC_VSEL 0x00000006
505#define OTPC_SELVL 0x00000001
506
507/* OTP regions (Word offsets from otp size) */
508#define OTP_SWLIM_OFF (-4)
509#define OTP_CIDBASE_OFF 0
510#define OTP_CIDLIM_OFF 4
511
512/* Predefined OTP words (Word offset from otp size) */
513#define OTP_BOUNDARY_OFF (-4)
514#define OTP_HWSIGN_OFF (-3)
515#define OTP_SWSIGN_OFF (-2)
516#define OTP_CIDSIGN_OFF (-1)
517#define OTP_CID_OFF 0
518#define OTP_PKG_OFF 1
519#define OTP_FID_OFF 2
520#define OTP_RSV_OFF 3
521#define OTP_LIM_OFF 4
522#define OTP_RD_OFF 4 /* Redundancy row starts here */
523#define OTP_RC0_OFF 28 /* Redundancy control word 1 */
524#define OTP_RC1_OFF 32 /* Redundancy control word 2 */
525#define OTP_RC_LIM_OFF 36 /* Redundancy control word end */
526
527#define OTP_HW_REGION OTPS_HW_PROTECT
528#define OTP_SW_REGION OTPS_SW_PROTECT
529#define OTP_CID_REGION OTPS_CID_PROTECT
530
531#if OTP_HW_REGION != OTP_HW_RGN
532#error "incompatible OTP_HW_RGN"
533#endif
534#if OTP_SW_REGION != OTP_SW_RGN
535#error "incompatible OTP_SW_RGN"
536#endif
537#if OTP_CID_REGION != OTP_CI_RGN
538#error "incompatible OTP_CI_RGN"
539#endif
540
541/* Redundancy entry definitions */
542#define OTP_RCE_ROW_SZ 6
543#define OTP_RCE_SIGN_MASK 0x7fff
544#define OTP_RCE_ROW_MASK 0x3f
545#define OTP_RCE_BITS 21
546#define OTP_RCE_SIGN_SZ 15
547#define OTP_RCE_BIT0 1
548
549#define OTP_WPR 4
550#define OTP_SIGNATURE 0x578a
551#define OTP_MAGIC 0x4e56
552
553static int hndotp_status(void *oh)
554{
555 otpinfo_t *oi = (otpinfo_t *) oh;
90ea2296 556 return (int)(oi->hwprot | oi->signvalid);
a9533e7e
HP
557}
558
559static int hndotp_size(void *oh)
560{
561 otpinfo_t *oi = (otpinfo_t *) oh;
90ea2296 562 return (int)(oi->size);
a9533e7e
HP
563}
564
7cc4a4c0 565static uint16 hndotp_otpr(void *oh, chipcregs_t *cc, uint wn)
a9533e7e
HP
566{
567 otpinfo_t *oi = (otpinfo_t *) oh;
568 osl_t *osh;
569 volatile uint16 *ptr;
570
571 ASSERT(wn < ((oi->size / 2) + OTP_RC_LIM_OFF));
572 ASSERT(cc != NULL);
573
574 osh = si_osh(oi->sih);
575
576 ptr = (volatile uint16 *)((volatile char *)cc + CC_SROM_OTP);
90ea2296 577 return R_REG(osh, &ptr[wn]);
a9533e7e
HP
578}
579
7cc4a4c0 580static uint16 hndotp_otproff(void *oh, chipcregs_t *cc, int woff)
a9533e7e
HP
581{
582 otpinfo_t *oi = (otpinfo_t *) oh;
583 osl_t *osh;
584 volatile uint16 *ptr;
585
586 ASSERT(woff >= (-((int)oi->size / 2)));
587 ASSERT(woff < OTP_LIM_OFF);
588 ASSERT(cc != NULL);
589
590 osh = si_osh(oi->sih);
591
592 ptr = (volatile uint16 *)((volatile char *)cc + CC_SROM_OTP);
593
90ea2296 594 return R_REG(osh, &ptr[(oi->size / 2) + woff]);
a9533e7e
HP
595}
596
7cc4a4c0 597static uint16 hndotp_read_bit(void *oh, chipcregs_t *cc, uint idx)
a9533e7e
HP
598{
599 otpinfo_t *oi = (otpinfo_t *) oh;
600 uint k, row, col;
601 uint32 otpp, st;
602 osl_t *osh;
603
604 osh = si_osh(oi->sih);
605 row = idx / 65;
606 col = idx % 65;
607
608 otpp = OTPP_START_BUSY | OTPP_READ |
609 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) | (col & OTPP_COL_MASK);
610
611 W_REG(osh, &cc->otpprog, otpp);
612 st = R_REG(osh, &cc->otpprog);
613 for (k = 0;
614 ((st & OTPP_START_BUSY) == OTPP_START_BUSY) && (k < OTPP_TRIES);
615 k++)
616 st = R_REG(osh, &cc->otpprog);
617
618 if (k >= OTPP_TRIES) {
619 return 0xffff;
620 }
621 if (st & OTPP_READERR) {
622 return 0xffff;
623 }
624 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
625 return (uint16) st;
626}
627
a2627bc0
JC
628static void *BCMNMIATTACHFN(hndotp_init) (si_t *sih)
629{
a9533e7e
HP
630 uint idx;
631 chipcregs_t *cc;
632 otpinfo_t *oi;
633 uint32 cap = 0, clkdiv, otpdiv = 0;
634 void *ret = NULL;
635 osl_t *osh;
636
637 oi = &otpinfo;
638
639 idx = si_coreidx(sih);
640 osh = si_osh(oi->sih);
641
642 /* Check for otp */
ca8c1e59
JC
643 cc = si_setcoreidx(sih, SI_CC_IDX);
644 if (cc != NULL) {
a9533e7e
HP
645 cap = R_REG(osh, &cc->capabilities);
646 if ((cap & CC_CAP_OTPSIZE) == 0) {
647 /* Nothing there */
648 goto out;
649 }
650
651 /* As of right now, support only 4320a2, 4311a1 and 4312 */
652 ASSERT((oi->ccrev == 12) || (oi->ccrev == 17)
653 || (oi->ccrev == 22));
654 if (!
655 ((oi->ccrev == 12) || (oi->ccrev == 17)
656 || (oi->ccrev == 22)))
657 return NULL;
658
659 /* Read the OTP byte size. chipcommon rev >= 18 has RCE so the size is
660 * 8 row (64 bytes) smaller
661 */
662 oi->size =
663 1 << (((cap & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT)
664 + CC_CAP_OTPSIZE_BASE);
665 if (oi->ccrev >= 18)
666 oi->size -= ((OTP_RC0_OFF - OTP_BOUNDARY_OFF) * 2);
667
668 oi->hwprot = (int)(R_REG(osh, &cc->otpstatus) & OTPS_PROTECT);
669 oi->boundary = -1;
670
671 /* Check the region signature */
672 if (hndotp_otproff(oi, cc, OTP_HWSIGN_OFF) == OTP_SIGNATURE) {
673 oi->signvalid |= OTP_HW_REGION;
674 oi->boundary = hndotp_otproff(oi, cc, OTP_BOUNDARY_OFF);
675 }
676
677 if (hndotp_otproff(oi, cc, OTP_SWSIGN_OFF) == OTP_SIGNATURE)
678 oi->signvalid |= OTP_SW_REGION;
679
680 if (hndotp_otproff(oi, cc, OTP_CIDSIGN_OFF) == OTP_SIGNATURE)
681 oi->signvalid |= OTP_CID_REGION;
682
683 /* Set OTP clkdiv for stability */
684 if (oi->ccrev == 22)
685 otpdiv = 12;
686
687 if (otpdiv) {
688 clkdiv = R_REG(osh, &cc->clkdiv);
689 clkdiv =
690 (clkdiv & ~CLKD_OTP) | (otpdiv << CLKD_OTP_SHIFT);
691 W_REG(osh, &cc->clkdiv, clkdiv);
692 }
693 OSL_DELAY(10);
694
695 ret = (void *)oi;
696 }
697
698 out: /* All done */
699 si_setcoreidx(sih, idx);
700
701 return ret;
702}
703
7cc4a4c0 704static int hndotp_read_region(void *oh, int region, uint16 *data, uint *wlen)
a9533e7e
HP
705{
706 otpinfo_t *oi = (otpinfo_t *) oh;
707 uint32 idx, st;
708 chipcregs_t *cc;
709 int i;
710
711 /* Only support HW region (no active chips use HND OTP SW region) */
712 ASSERT(region == OTP_HW_REGION);
713
714 /* Region empty? */
715 st = oi->hwprot | oi->signvalid;
716 if ((st & region) == 0)
717 return BCME_NOTFOUND;
718
719 *wlen =
720 ((int)*wlen < oi->boundary / 2) ? *wlen : (uint) oi->boundary / 2;
721
722 idx = si_coreidx(oi->sih);
723 cc = si_setcoreidx(oi->sih, SI_CC_IDX);
724 ASSERT(cc != NULL);
725
726 for (i = 0; i < (int)*wlen; i++)
727 data[i] = hndotp_otpr(oh, cc, i);
728
729 si_setcoreidx(oi->sih, idx);
730
731 return 0;
732}
733
7cc4a4c0 734static int hndotp_nvread(void *oh, char *data, uint *len)
a9533e7e
HP
735{
736 int rc = 0;
737 otpinfo_t *oi = (otpinfo_t *) oh;
738 uint32 base, bound, lim = 0, st;
739 int i, chunk, gchunks, tsz = 0;
740 uint32 idx;
741 chipcregs_t *cc;
742 uint offset;
743 uint16 *rawotp = NULL;
744
745 /* save the orig core */
746 idx = si_coreidx(oi->sih);
747 cc = si_setcoreidx(oi->sih, SI_CC_IDX);
748 ASSERT(cc != NULL);
749
750 st = hndotp_status(oh);
751 if (!(st & (OTP_HW_REGION | OTP_SW_REGION))) {
752 rc = -1;
753 goto out;
754 }
755
756 /* Read the whole otp so we can easily manipulate it */
757 lim = hndotp_size(oh);
ca8c1e59
JC
758 rawotp = MALLOC(si_osh(oi->sih), lim);
759 if (rawotp == NULL) {
a9533e7e
HP
760 rc = -2;
761 goto out;
762 }
763 for (i = 0; i < (int)(lim / 2); i++)
764 rawotp[i] = hndotp_otpr(oh, cc, i);
765
766 if ((st & OTP_HW_REGION) == 0) {
767 /* This could be a programming failure in the first
768 * chunk followed by one or more good chunks
769 */
770 for (i = 0; i < (int)(lim / 2); i++)
771 if (rawotp[i] == OTP_MAGIC)
772 break;
773
774 if (i < (int)(lim / 2)) {
775 base = i;
776 bound = (i * 2) + rawotp[i + 1];
777 } else {
778 rc = -3;
779 goto out;
780 }
781 } else {
782 bound = rawotp[(lim / 2) + OTP_BOUNDARY_OFF];
783
784 /* There are two cases: 1) The whole otp is used as nvram
785 * and 2) There is a hardware header followed by nvram.
786 */
787 if (rawotp[0] == OTP_MAGIC) {
788 base = 0;
789 } else
790 base = bound;
791 }
792
793 /* Find and copy the data */
794
795 chunk = 0;
796 gchunks = 0;
797 i = base / 2;
798 offset = 0;
799 while ((i < (int)(lim / 2)) && (rawotp[i] == OTP_MAGIC)) {
800 int dsz, rsz = rawotp[i + 1];
801
802 if (((i * 2) + rsz) >= (int)lim) {
803 /* Bad length, try to find another chunk anyway */
804 rsz = 6;
805 }
806 if (hndcrc16((uint8 *) & rawotp[i], rsz,
807 CRC16_INIT_VALUE) == CRC16_GOOD_VALUE) {
808 /* Good crc, copy the vars */
809 gchunks++;
810 dsz = rsz - 6;
811 tsz += dsz;
812 if (offset + dsz >= *len) {
813 goto out;
814 }
815 bcopy((char *)&rawotp[i + 2], &data[offset], dsz);
816 offset += dsz;
817 /* Remove extra null characters at the end */
818 while (offset > 1 &&
819 data[offset - 1] == 0 && data[offset - 2] == 0)
820 offset--;
821 i += rsz / 2;
822 } else {
823 /* bad length or crc didn't check, try to find the next set */
824 if (rawotp[i + (rsz / 2)] == OTP_MAGIC) {
825 /* Assume length is good */
826 i += rsz / 2;
827 } else {
828 while (++i < (int)(lim / 2))
829 if (rawotp[i] == OTP_MAGIC)
830 break;
831 }
832 }
833 chunk++;
834 }
835
836 *len = offset;
837
838 out:
839 if (rawotp)
840 MFREE(si_osh(oi->sih), rawotp, lim);
841 si_setcoreidx(oi->sih, idx);
842
843 return rc;
844}
845
846static otp_fn_t hndotp_fn = {
847 (otp_size_t) hndotp_size,
848 (otp_read_bit_t) hndotp_read_bit,
849
850 (otp_init_t) hndotp_init,
851 (otp_read_region_t) hndotp_read_region,
852 (otp_nvread_t) hndotp_nvread,
853
854 (otp_status_t) hndotp_status
855};
856
857#endif /* BCMHNDOTP */
858
859/*
860 * Common Code: Compiled for IPX / HND / AUTO
861 * otp_status()
862 * otp_size()
863 * otp_read_bit()
864 * otp_init()
865 * otp_read_region()
866 * otp_nvread()
867 */
868
869int otp_status(void *oh)
870{
871 otpinfo_t *oi = (otpinfo_t *) oh;
872
873 return oi->fn->status(oh);
874}
875
876int otp_size(void *oh)
877{
878 otpinfo_t *oi = (otpinfo_t *) oh;
879
880 return oi->fn->size(oh);
881}
882
883uint16 otp_read_bit(void *oh, uint offset)
884{
885 otpinfo_t *oi = (otpinfo_t *) oh;
886 uint idx = si_coreidx(oi->sih);
887 chipcregs_t *cc = si_setcoreidx(oi->sih, SI_CC_IDX);
888 uint16 readBit = (uint16) oi->fn->read_bit(oh, cc, offset);
889 si_setcoreidx(oi->sih, idx);
890 return readBit;
891}
892
a2627bc0
JC
893void *BCMNMIATTACHFN(otp_init) (si_t *sih)
894{
a9533e7e
HP
895 otpinfo_t *oi;
896 void *ret = NULL;
897
898 oi = &otpinfo;
899 bzero(oi, sizeof(otpinfo_t));
900
901 oi->ccrev = sih->ccrev;
902
903#ifdef BCMIPXOTP
904 if (OTPTYPE_IPX(oi->ccrev))
905 oi->fn = &ipxotp_fn;
906#endif
907
908#ifdef BCMHNDOTP
909 if (OTPTYPE_HND(oi->ccrev))
910 oi->fn = &hndotp_fn;
911#endif
912
913 if (oi->fn == NULL) {
914 return NULL;
915 }
916
917 oi->sih = sih;
918 oi->osh = si_osh(oi->sih);
919
920 ret = (oi->fn->init) (sih);
921
922 return ret;
923}
924
925int
7cc4a4c0
JC
926BCMNMIATTACHFN(otp_read_region) (si_t *sih, int region, uint16 *data,
927 uint *wlen) {
a9533e7e
HP
928 bool wasup = FALSE;
929 void *oh;
930 int err = 0;
931
ca8c1e59
JC
932 wasup = si_is_otp_powered(sih);
933 if (!wasup)
a9533e7e
HP
934 si_otp_power(sih, TRUE);
935
936 if (!si_is_otp_powered(sih) || si_is_otp_disabled(sih)) {
937 err = BCME_NOTREADY;
938 goto out;
939 }
940
941 oh = otp_init(sih);
942 if (oh == NULL) {
943 err = BCME_ERROR;
944 goto out;
945 }
946
947 err = (((otpinfo_t *) oh)->fn->read_region) (oh, region, data, wlen);
948
949 out:
950 if (!wasup)
951 si_otp_power(sih, FALSE);
952
953 return err;
954}
955
7cc4a4c0 956int otp_nvread(void *oh, char *data, uint *len)
a9533e7e
HP
957{
958 otpinfo_t *oi = (otpinfo_t *) oh;
959
960 return oi->fn->nvread(oh, data, len);
961}