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.
18 #include <linux/errno.h>
19 #include <linux/string.h>
21 #include <brcm_hw_ids.h>
22 #include <chipcommon.h>
26 #define OTPS_GUP_MASK 0x00000f00
27 #define OTPS_GUP_SHIFT 8
28 #define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */
29 #define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */
30 #define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */
31 #define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */
33 /* Fields in otpprog in rev >= 21 */
34 #define OTPP_COL_MASK 0x000000ff
35 #define OTPP_COL_SHIFT 0
36 #define OTPP_ROW_MASK 0x0000ff00
37 #define OTPP_ROW_SHIFT 8
38 #define OTPP_OC_MASK 0x0f000000
39 #define OTPP_OC_SHIFT 24
40 #define OTPP_READERR 0x10000000
41 #define OTPP_VALUE_MASK 0x20000000
42 #define OTPP_VALUE_SHIFT 29
43 #define OTPP_START_BUSY 0x80000000
44 #define OTPP_READ 0x40000000
46 /* Opcodes for OTPP_OC field */
48 #define OTPPOC_BIT_PROG 1
49 #define OTPPOC_VERIFY 3
52 #define OTPPOC_RESET 6
54 #define OTPPOC_ROW_LOCK 8
55 #define OTPPOC_PRESCN_TEST 9
57 #define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
59 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
61 #define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
63 /* OTP common function type */
64 typedef int (*otp_status_t
) (void *oh
);
65 typedef int (*otp_size_t
) (void *oh
);
66 typedef void *(*otp_init_t
) (struct si_pub
*sih
);
67 typedef u16(*otp_read_bit_t
) (void *oh
, chipcregs_t
*cc
, uint off
);
68 typedef int (*otp_read_region_t
) (struct si_pub
*sih
, int region
, u16
*data
,
70 typedef int (*otp_nvread_t
) (void *oh
, char *data
, uint
*len
);
72 /* OTP function struct */
75 otp_read_bit_t read_bit
;
77 otp_read_region_t read_region
;
83 uint ccrev
; /* chipc revision */
84 struct otp_fn_s
*fn
; /* OTP functions */
85 struct si_pub
*sih
; /* Saved sb handle */
88 u16 wsize
; /* Size of otp in words */
89 u16 rows
; /* Geometry */
90 u16 cols
; /* Geometry */
91 u32 status
; /* Flag bits (lock/prog/rv).
92 * (Reflected only when OTP is power cycled)
94 u16 hwbase
; /* hardware subregion offset */
95 u16 hwlim
; /* hardware subregion boundary */
96 u16 swbase
; /* software subregion offset */
97 u16 swlim
; /* software subregion boundary */
98 u16 fbase
; /* fuse subregion offset */
99 u16 flim
; /* fuse subregion boundary */
100 int otpgu_base
; /* offset to General Use Region */
103 static struct otpinfo otpinfo
;
108 * Exported functions:
113 * ipxotp_read_region()
118 #define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
121 /* CC revs 21, 24 and 27 OTP General Use Region word offset */
122 #define REVA4_OTPGU_BASE 12
124 /* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
125 #define REVB8_OTPGU_BASE 20
127 /* CC rev 36 OTP General Use Region word offset */
128 #define REV36_OTPGU_BASE 12
130 /* Subregion word offsets in General Use region */
131 #define OTPGU_HSB_OFF 0
132 #define OTPGU_SFB_OFF 1
133 #define OTPGU_CI_OFF 2
134 #define OTPGU_P_OFF 3
135 #define OTPGU_SROM_OFF 4
137 /* Flag bit offsets in General Use region */
138 #define OTPGU_HWP_OFF 60
139 #define OTPGU_SWP_OFF 61
140 #define OTPGU_CIP_OFF 62
141 #define OTPGU_FUSEP_OFF 63
142 #define OTPGU_CIP_MSK 0x4000
143 #define OTPGU_P_MSK 0xf000
144 #define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
147 #define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
148 #define OTP_SZ_FU_288 (288/8) /* 288 bits */
149 #define OTP_SZ_FU_216 (216/8) /* 216 bits */
150 #define OTP_SZ_FU_72 (72/8) /* 72 bits */
151 #define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
152 #define OTP4315_SWREG_SZ 178 /* 178 bytes */
153 #define OTP_SZ_FU_144 (144/8) /* 144 bits */
155 static int ipxotp_status(void *oh
)
157 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
158 return (int)(oi
->status
);
161 /* Return size in bytes */
162 static int ipxotp_size(void *oh
)
164 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
165 return (int)oi
->wsize
* 2;
168 static u16
ipxotp_otpr(void *oh
, chipcregs_t
*cc
, uint wn
)
172 oi
= (struct otpinfo
*) oh
;
174 return R_REG(&cc
->sromotp
[wn
]);
177 static u16
ipxotp_read_bit(void *oh
, chipcregs_t
*cc
, uint off
)
179 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
183 row
= off
/ oi
->cols
;
184 col
= off
% oi
->cols
;
186 otpp
= OTPP_START_BUSY
|
187 ((OTPPOC_READ
<< OTPP_OC_SHIFT
) & OTPP_OC_MASK
) |
188 ((row
<< OTPP_ROW_SHIFT
) & OTPP_ROW_MASK
) |
189 ((col
<< OTPP_COL_SHIFT
) & OTPP_COL_MASK
);
190 W_REG(&cc
->otpprog
, otpp
);
193 ((st
= R_REG(&cc
->otpprog
)) & OTPP_START_BUSY
)
194 && (k
< OTPP_TRIES
); k
++)
196 if (k
>= OTPP_TRIES
) {
199 if (st
& OTPP_READERR
) {
202 st
= (st
& OTPP_VALUE_MASK
) >> OTPP_VALUE_SHIFT
;
207 /* Calculate max HW/SW region byte size by subtracting fuse region and checksum size,
208 * osizew is oi->wsize (OTP size - GU size) in words
210 static int ipxotp_max_rgnsz(struct si_pub
*sih
, int osizew
)
215 case BCM43224_CHIP_ID
:
216 case BCM43225_CHIP_ID
:
217 ret
= osizew
* 2 - OTP_SZ_FU_72
- OTP_SZ_CHECKSUM
;
219 case BCM4313_CHIP_ID
:
220 ret
= osizew
* 2 - OTP_SZ_FU_72
- OTP_SZ_CHECKSUM
;
223 break; /* Don't know about this chip */
229 static void _ipxotp_init(struct otpinfo
*oi
, chipcregs_t
*cc
)
234 /* record word offset of General Use Region for various chipcommon revs */
235 if (oi
->sih
->ccrev
== 21 || oi
->sih
->ccrev
== 24
236 || oi
->sih
->ccrev
== 27) {
237 oi
->otpgu_base
= REVA4_OTPGU_BASE
;
238 } else if (oi
->sih
->ccrev
== 36) {
239 /* OTP size greater than equal to 2KB (128 words), otpgu_base is similar to rev23 */
240 if (oi
->wsize
>= 128)
241 oi
->otpgu_base
= REVB8_OTPGU_BASE
;
243 oi
->otpgu_base
= REV36_OTPGU_BASE
;
244 } else if (oi
->sih
->ccrev
== 23 || oi
->sih
->ccrev
>= 25) {
245 oi
->otpgu_base
= REVB8_OTPGU_BASE
;
248 /* First issue an init command so the status is up to date */
250 OTPP_START_BUSY
| ((OTPPOC_INIT
<< OTPP_OC_SHIFT
) & OTPP_OC_MASK
);
252 W_REG(&cc
->otpprog
, otpp
);
254 ((st
= R_REG(&cc
->otpprog
)) & OTPP_START_BUSY
)
255 && (k
< OTPP_TRIES
); k
++)
257 if (k
>= OTPP_TRIES
) {
261 /* Read OTP lock bits and subregion programmed indication bits */
262 oi
->status
= R_REG(&cc
->otpstatus
);
264 if ((oi
->sih
->chip
== BCM43224_CHIP_ID
)
265 || (oi
->sih
->chip
== BCM43225_CHIP_ID
)) {
268 (ipxotp_otpr(oi
, cc
, oi
->otpgu_base
+ OTPGU_P_OFF
) &
271 oi
->status
|= (p_bits
<< OTPS_GUP_SHIFT
);
275 * h/w region base and fuse region limit are fixed to the top and
276 * the bottom of the general use region. Everything else can be flexible.
278 oi
->hwbase
= oi
->otpgu_base
+ OTPGU_SROM_OFF
;
279 oi
->hwlim
= oi
->wsize
;
280 if (oi
->status
& OTPS_GUP_HW
) {
282 ipxotp_otpr(oi
, cc
, oi
->otpgu_base
+ OTPGU_HSB_OFF
) / 16;
283 oi
->swbase
= oi
->hwlim
;
285 oi
->swbase
= oi
->hwbase
;
287 /* subtract fuse and checksum from beginning */
288 oi
->swlim
= ipxotp_max_rgnsz(oi
->sih
, oi
->wsize
) / 2;
290 if (oi
->status
& OTPS_GUP_SW
) {
292 ipxotp_otpr(oi
, cc
, oi
->otpgu_base
+ OTPGU_SFB_OFF
) / 16;
293 oi
->fbase
= oi
->swlim
;
295 oi
->fbase
= oi
->swbase
;
297 oi
->flim
= oi
->wsize
;
300 static void *ipxotp_init(struct si_pub
*sih
)
306 /* Make sure we're running IPX OTP */
307 if (!OTPTYPE_IPX(sih
->ccrev
))
310 /* Make sure OTP is not disabled */
311 if (ai_is_otp_disabled(sih
))
314 /* OTP is always powered */
317 /* Check for otp size */
318 switch ((sih
->cccaps
& CC_CAP_OTPSIZE
) >> CC_CAP_OTPSIZE_SHIFT
) {
337 case 7: /* 16x64 *//* 1024 bits */
343 /* Don't know the geometry */
347 /* Retrieve OTP region info */
348 idx
= ai_coreidx(sih
);
349 cc
= ai_setcoreidx(sih
, SI_CC_IDX
);
351 _ipxotp_init(oi
, cc
);
353 ai_setcoreidx(sih
, idx
);
358 static int ipxotp_read_region(void *oh
, int region
, u16
*data
, uint
*wlen
)
360 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
365 /* Validate region selection */
368 sz
= (uint
) oi
->hwlim
- oi
->hwbase
;
369 if (!(oi
->status
& OTPS_GUP_HW
)) {
380 sz
= ((uint
) oi
->swlim
- oi
->swbase
);
381 if (!(oi
->status
& OTPS_GUP_SW
)) {
393 if (!(oi
->status
& OTPS_GUP_CI
)) {
401 base
= oi
->otpgu_base
+ OTPGU_CI_OFF
;
404 sz
= (uint
) oi
->flim
- oi
->fbase
;
405 if (!(oi
->status
& OTPS_GUP_FUSE
)) {
416 sz
= ((uint
) oi
->flim
- oi
->hwbase
);
417 if (!(oi
->status
& (OTPS_GUP_HW
| OTPS_GUP_SW
))) {
431 idx
= ai_coreidx(oi
->sih
);
432 cc
= ai_setcoreidx(oi
->sih
, SI_CC_IDX
);
435 for (i
= 0; i
< sz
; i
++)
436 data
[i
] = ipxotp_otpr(oh
, cc
, base
+ i
);
438 ai_setcoreidx(oi
->sih
, idx
);
443 static int ipxotp_nvread(void *oh
, char *data
, uint
*len
)
448 static struct otp_fn_s ipxotp_fn
= {
449 (otp_size_t
) ipxotp_size
,
450 (otp_read_bit_t
) ipxotp_read_bit
,
452 (otp_init_t
) ipxotp_init
,
453 (otp_read_region_t
) ipxotp_read_region
,
454 (otp_nvread_t
) ipxotp_nvread
,
456 (otp_status_t
) ipxotp_status
468 int otp_status(void *oh
)
470 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
472 return oi
->fn
->status(oh
);
475 int otp_size(void *oh
)
477 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
479 return oi
->fn
->size(oh
);
482 u16
otp_read_bit(void *oh
, uint offset
)
484 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
485 uint idx
= ai_coreidx(oi
->sih
);
486 chipcregs_t
*cc
= ai_setcoreidx(oi
->sih
, SI_CC_IDX
);
487 u16 readBit
= (u16
) oi
->fn
->read_bit(oh
, cc
, offset
);
488 ai_setcoreidx(oi
->sih
, idx
);
492 void *otp_init(struct si_pub
*sih
)
498 memset(oi
, 0, sizeof(struct otpinfo
));
500 oi
->ccrev
= sih
->ccrev
;
502 if (OTPTYPE_IPX(oi
->ccrev
))
505 if (oi
->fn
== NULL
) {
511 ret
= (oi
->fn
->init
) (sih
);
517 otp_read_region(struct si_pub
*sih
, int region
, u16
*data
,
522 if (ai_is_otp_disabled(sih
)) {
533 err
= (((struct otpinfo
*) oh
)->fn
->read_region
)
534 (oh
, region
, data
, wlen
);
540 int otp_nvread(void *oh
, char *data
, uint
*len
)
542 struct otpinfo
*oi
= (struct otpinfo
*) oh
;
544 return oi
->fn
->nvread(oh
, data
, len
);