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