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 <linux/delay.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <linux/crc-ccitt.h>
26 #include <brcmu_utils.h>
29 #include <chipcommon.h>
32 #define OTPS_GUP_MASK 0x00000f00
33 #define OTPS_GUP_SHIFT 8
34 #define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */
35 #define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */
36 #define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */
37 #define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */
39 /* Fields in otpprog in rev >= 21 */
40 #define OTPP_COL_MASK 0x000000ff
41 #define OTPP_COL_SHIFT 0
42 #define OTPP_ROW_MASK 0x0000ff00
43 #define OTPP_ROW_SHIFT 8
44 #define OTPP_OC_MASK 0x0f000000
45 #define OTPP_OC_SHIFT 24
46 #define OTPP_READERR 0x10000000
47 #define OTPP_VALUE_MASK 0x20000000
48 #define OTPP_VALUE_SHIFT 29
49 #define OTPP_START_BUSY 0x80000000
50 #define OTPP_READ 0x40000000
52 /* Opcodes for OTPP_OC field */
54 #define OTPPOC_BIT_PROG 1
55 #define OTPPOC_VERIFY 3
58 #define OTPPOC_RESET 6
60 #define OTPPOC_ROW_LOCK 8
61 #define OTPPOC_PRESCN_TEST 9
63 #define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
65 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
67 #define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
69 /* OTP common function type */
70 typedef int (*otp_status_t) (void *oh);
71 typedef int (*otp_size_t) (void *oh);
72 typedef void *(*otp_init_t) (struct si_pub *sih);
73 typedef u16(*otp_read_bit_t) (void *oh, chipcregs_t *cc, uint off);
74 typedef int (*otp_read_region_t) (struct si_pub *sih, int region, u16 *data,
76 typedef int (*otp_nvread_t) (void *oh, char *data, uint *len);
78 /* OTP function struct */
79 typedef struct otp_fn_s {
81 otp_read_bit_t read_bit;
83 otp_read_region_t read_region;
89 uint ccrev; /* chipc revision */
90 otp_fn_t *fn; /* OTP functions */
91 struct si_pub *sih; /* Saved sb handle */
94 u16 wsize; /* Size of otp in words */
95 u16 rows; /* Geometry */
96 u16 cols; /* Geometry */
97 u32 status; /* Flag bits (lock/prog/rv).
98 * (Reflected only when OTP is power cycled)
100 u16 hwbase; /* hardware subregion offset */
101 u16 hwlim; /* hardware subregion boundary */
102 u16 swbase; /* software subregion offset */
103 u16 swlim; /* software subregion boundary */
104 u16 fbase; /* fuse subregion offset */
105 u16 flim; /* fuse subregion boundary */
106 int otpgu_base; /* offset to General Use Region */
109 static otpinfo_t otpinfo;
114 * Exported functions:
119 * ipxotp_read_region()
124 #define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
127 /* CC revs 21, 24 and 27 OTP General Use Region word offset */
128 #define REVA4_OTPGU_BASE 12
130 /* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
131 #define REVB8_OTPGU_BASE 20
133 /* CC rev 36 OTP General Use Region word offset */
134 #define REV36_OTPGU_BASE 12
136 /* Subregion word offsets in General Use region */
137 #define OTPGU_HSB_OFF 0
138 #define OTPGU_SFB_OFF 1
139 #define OTPGU_CI_OFF 2
140 #define OTPGU_P_OFF 3
141 #define OTPGU_SROM_OFF 4
143 /* Flag bit offsets in General Use region */
144 #define OTPGU_HWP_OFF 60
145 #define OTPGU_SWP_OFF 61
146 #define OTPGU_CIP_OFF 62
147 #define OTPGU_FUSEP_OFF 63
148 #define OTPGU_CIP_MSK 0x4000
149 #define OTPGU_P_MSK 0xf000
150 #define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
153 #define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
154 #define OTP_SZ_FU_288 (288/8) /* 288 bits */
155 #define OTP_SZ_FU_216 (216/8) /* 216 bits */
156 #define OTP_SZ_FU_72 (72/8) /* 72 bits */
157 #define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
158 #define OTP4315_SWREG_SZ 178 /* 178 bytes */
159 #define OTP_SZ_FU_144 (144/8) /* 144 bits */
161 static int ipxotp_status(void *oh)
163 otpinfo_t *oi = (otpinfo_t *) oh;
164 return (int)(oi->status);
167 /* Return size in bytes */
168 static int ipxotp_size(void *oh)
170 otpinfo_t *oi = (otpinfo_t *) oh;
171 return (int)oi->wsize * 2;
174 static u16 ipxotp_otpr(void *oh, chipcregs_t *cc, uint wn)
178 oi = (otpinfo_t *) oh;
180 return R_REG(&cc->sromotp[wn]);
183 static u16 ipxotp_read_bit(void *oh, chipcregs_t *cc, uint off)
185 otpinfo_t *oi = (otpinfo_t *) oh;
189 row = off / oi->cols;
190 col = off % oi->cols;
192 otpp = OTPP_START_BUSY |
193 ((OTPPOC_READ << OTPP_OC_SHIFT) & OTPP_OC_MASK) |
194 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) |
195 ((col << OTPP_COL_SHIFT) & OTPP_COL_MASK);
196 W_REG(&cc->otpprog, otpp);
199 ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
200 && (k < OTPP_TRIES); k++)
202 if (k >= OTPP_TRIES) {
205 if (st & OTPP_READERR) {
208 st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
213 /* Calculate max HW/SW region byte size by subtracting fuse region and checksum size,
214 * osizew is oi->wsize (OTP size - GU size) in words
216 static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
221 case BCM43224_CHIP_ID:
222 case BCM43225_CHIP_ID:
223 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
225 case BCM4313_CHIP_ID:
226 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
229 break; /* Don't know about this chip */
235 static void _ipxotp_init(otpinfo_t *oi, chipcregs_t *cc)
240 /* record word offset of General Use Region for various chipcommon revs */
241 if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24
242 || oi->sih->ccrev == 27) {
243 oi->otpgu_base = REVA4_OTPGU_BASE;
244 } else if (oi->sih->ccrev == 36) {
245 /* OTP size greater than equal to 2KB (128 words), otpgu_base is similar to rev23 */
246 if (oi->wsize >= 128)
247 oi->otpgu_base = REVB8_OTPGU_BASE;
249 oi->otpgu_base = REV36_OTPGU_BASE;
250 } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) {
251 oi->otpgu_base = REVB8_OTPGU_BASE;
254 /* First issue an init command so the status is up to date */
256 OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
258 W_REG(&cc->otpprog, otpp);
260 ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
261 && (k < OTPP_TRIES); k++)
263 if (k >= OTPP_TRIES) {
267 /* Read OTP lock bits and subregion programmed indication bits */
268 oi->status = R_REG(&cc->otpstatus);
270 if ((oi->sih->chip == BCM43224_CHIP_ID)
271 || (oi->sih->chip == BCM43225_CHIP_ID)) {
274 (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
277 oi->status |= (p_bits << OTPS_GUP_SHIFT);
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.
284 oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
285 oi->hwlim = oi->wsize;
286 if (oi->status & OTPS_GUP_HW) {
288 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
289 oi->swbase = oi->hwlim;
291 oi->swbase = oi->hwbase;
293 /* subtract fuse and checksum from beginning */
294 oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
296 if (oi->status & OTPS_GUP_SW) {
298 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
299 oi->fbase = oi->swlim;
301 oi->fbase = oi->swbase;
303 oi->flim = oi->wsize;
306 static void *ipxotp_init(struct si_pub *sih)
312 /* Make sure we're running IPX OTP */
313 if (!OTPTYPE_IPX(sih->ccrev))
316 /* Make sure OTP is not disabled */
317 if (ai_is_otp_disabled(sih))
320 /* Make sure OTP is powered up */
321 if (!ai_is_otp_powered(sih))
326 /* Check for otp size */
327 switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
346 case 7: /* 16x64 *//* 1024 bits */
352 /* Don't know the geometry */
356 /* Retrieve OTP region info */
357 idx = ai_coreidx(sih);
358 cc = ai_setcoreidx(sih, SI_CC_IDX);
360 _ipxotp_init(oi, cc);
362 ai_setcoreidx(sih, idx);
367 static int ipxotp_read_region(void *oh, int region, u16 *data, uint *wlen)
369 otpinfo_t *oi = (otpinfo_t *) oh;
374 /* Validate region selection */
377 sz = (uint) oi->hwlim - oi->hwbase;
378 if (!(oi->status & OTPS_GUP_HW)) {
389 sz = ((uint) oi->swlim - oi->swbase);
390 if (!(oi->status & OTPS_GUP_SW)) {
402 if (!(oi->status & OTPS_GUP_CI)) {
410 base = oi->otpgu_base + OTPGU_CI_OFF;
413 sz = (uint) oi->flim - oi->fbase;
414 if (!(oi->status & OTPS_GUP_FUSE)) {
425 sz = ((uint) oi->flim - oi->hwbase);
426 if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
440 idx = ai_coreidx(oi->sih);
441 cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
444 for (i = 0; i < sz; i++)
445 data[i] = ipxotp_otpr(oh, cc, base + i);
447 ai_setcoreidx(oi->sih, idx);
452 static int ipxotp_nvread(void *oh, char *data, uint *len)
457 static otp_fn_t ipxotp_fn = {
458 (otp_size_t) ipxotp_size,
459 (otp_read_bit_t) ipxotp_read_bit,
461 (otp_init_t) ipxotp_init,
462 (otp_read_region_t) ipxotp_read_region,
463 (otp_nvread_t) ipxotp_nvread,
465 (otp_status_t) ipxotp_status
477 int otp_status(void *oh)
479 otpinfo_t *oi = (otpinfo_t *) oh;
481 return oi->fn->status(oh);
484 int otp_size(void *oh)
486 otpinfo_t *oi = (otpinfo_t *) oh;
488 return oi->fn->size(oh);
491 u16 otp_read_bit(void *oh, uint offset)
493 otpinfo_t *oi = (otpinfo_t *) oh;
494 uint idx = ai_coreidx(oi->sih);
495 chipcregs_t *cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
496 u16 readBit = (u16) oi->fn->read_bit(oh, cc, offset);
497 ai_setcoreidx(oi->sih, idx);
501 void *otp_init(struct si_pub *sih)
507 memset(oi, 0, sizeof(otpinfo_t));
509 oi->ccrev = sih->ccrev;
511 if (OTPTYPE_IPX(oi->ccrev))
514 if (oi->fn == NULL) {
520 ret = (oi->fn->init) (sih);
526 otp_read_region(struct si_pub *sih, int region, u16 *data,
532 wasup = ai_is_otp_powered(sih);
534 ai_otp_power(sih, true);
536 if (!ai_is_otp_powered(sih) || ai_is_otp_disabled(sih)) {
547 err = (((otpinfo_t *) oh)->fn->read_region) (oh, region, data, wlen);
551 ai_otp_power(sih, false);
556 int otp_nvread(void *oh, char *data, uint *len)
558 otpinfo_t *oi = (otpinfo_t *) oh;
560 return oi->fn->nvread(oh, data, len);