blob: edf551561fd8eab55956ec6438a707e51a074fde [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
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 <linux/io.h>
18#include <linux/errno.h>
19#include <linux/string.h>
20
21#include <brcm_hw_ids.h>
22#include <chipcommon.h>
23#include "aiutils.h"
24#include "otp.h"
25
26#define OTPS_GUP_MASK 0x00000f00
27#define OTPS_GUP_SHIFT 8
28/* h/w subregion is programmed */
29#define OTPS_GUP_HW 0x00000100
30/* s/w subregion is programmed */
31#define OTPS_GUP_SW 0x00000200
32/* chipid/pkgopt subregion is programmed */
33#define OTPS_GUP_CI 0x00000400
34/* fuse subregion is programmed */
35#define OTPS_GUP_FUSE 0x00000800
36
37/* Fields in otpprog in rev >= 21 */
38#define OTPP_COL_MASK 0x000000ff
39#define OTPP_COL_SHIFT 0
40#define OTPP_ROW_MASK 0x0000ff00
41#define OTPP_ROW_SHIFT 8
42#define OTPP_OC_MASK 0x0f000000
43#define OTPP_OC_SHIFT 24
44#define OTPP_READERR 0x10000000
45#define OTPP_VALUE_MASK 0x20000000
46#define OTPP_VALUE_SHIFT 29
47#define OTPP_START_BUSY 0x80000000
48#define OTPP_READ 0x40000000
49
50/* Opcodes for OTPP_OC field */
51#define OTPPOC_READ 0
52#define OTPPOC_BIT_PROG 1
53#define OTPPOC_VERIFY 3
54#define OTPPOC_INIT 4
55#define OTPPOC_SET 5
56#define OTPPOC_RESET 6
57#define OTPPOC_OCST 7
58#define OTPPOC_ROW_LOCK 8
59#define OTPPOC_PRESCN_TEST 9
60
61#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
62
63#define OTPP_TRIES 10000000 /* # of tries for OTPP */
64
65#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
66
67/* Fixed size subregions sizes in words */
68#define OTPGU_CI_SZ 2
69
70struct otpinfo;
71
72/* OTP function struct */
73struct otp_fn_s {
74 int (*init)(struct si_pub *sih, struct otpinfo *oi);
75 int (*read_region)(struct otpinfo *oi, int region, u16 *data,
76 uint *wlen);
77};
78
79struct otpinfo {
80 uint ccrev; /* chipc revision */
81 const struct otp_fn_s *fn; /* OTP functions */
82 struct si_pub *sih; /* Saved sb handle */
83
84 /* IPX OTP section */
85 u16 wsize; /* Size of otp in words */
86 u16 rows; /* Geometry */
87 u16 cols; /* Geometry */
88 u32 status; /* Flag bits (lock/prog/rv).
89 * (Reflected only when OTP is power cycled)
90 */
91 u16 hwbase; /* hardware subregion offset */
92 u16 hwlim; /* hardware subregion boundary */
93 u16 swbase; /* software subregion offset */
94 u16 swlim; /* software subregion boundary */
95 u16 fbase; /* fuse subregion offset */
96 u16 flim; /* fuse subregion boundary */
97 int otpgu_base; /* offset to General Use Region */
98};
99
100/* OTP layout */
101/* CC revs 21, 24 and 27 OTP General Use Region word offset */
102#define REVA4_OTPGU_BASE 12
103
104/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
105#define REVB8_OTPGU_BASE 20
106
107/* CC rev 36 OTP General Use Region word offset */
108#define REV36_OTPGU_BASE 12
109
110/* Subregion word offsets in General Use region */
111#define OTPGU_HSB_OFF 0
112#define OTPGU_SFB_OFF 1
113#define OTPGU_CI_OFF 2
114#define OTPGU_P_OFF 3
115#define OTPGU_SROM_OFF 4
116
117/* Flag bit offsets in General Use region */
118#define OTPGU_HWP_OFF 60
119#define OTPGU_SWP_OFF 61
120#define OTPGU_CIP_OFF 62
121#define OTPGU_FUSEP_OFF 63
122#define OTPGU_CIP_MSK 0x4000
123#define OTPGU_P_MSK 0xf000
124#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
125
126/* OTP Size */
127#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
128#define OTP_SZ_FU_288 (288/8) /* 288 bits */
129#define OTP_SZ_FU_216 (216/8) /* 216 bits */
130#define OTP_SZ_FU_72 (72/8) /* 72 bits */
131#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
132#define OTP4315_SWREG_SZ 178 /* 178 bytes */
133#define OTP_SZ_FU_144 (144/8) /* 144 bits */
134
135static u16
136ipxotp_otpr(struct otpinfo *oi, struct chipcregs __iomem *cc, uint wn)
137{
138 return R_REG(&cc->sromotp[wn]);
139}
140
141/*
142 * Calculate max HW/SW region byte size by subtracting fuse region
143 * and checksum size, osizew is oi->wsize (OTP size - GU size) in words
144 */
145static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
146{
147 int ret = 0;
148
149 switch (sih->chip) {
150 case BCM43224_CHIP_ID:
151 case BCM43225_CHIP_ID:
152 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
153 break;
154 case BCM4313_CHIP_ID:
155 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
156 break;
157 default:
158 break; /* Don't know about this chip */
159 }
160
161 return ret;
162}
163
164static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc)
165{
166 uint k;
167 u32 otpp, st;
168
169 /*
170 * record word offset of General Use Region
171 * for various chipcommon revs
172 */
173 if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24
174 || oi->sih->ccrev == 27) {
175 oi->otpgu_base = REVA4_OTPGU_BASE;
176 } else if (oi->sih->ccrev == 36) {
177 /*
178 * OTP size greater than equal to 2KB (128 words),
179 * otpgu_base is similar to rev23
180 */
181 if (oi->wsize >= 128)
182 oi->otpgu_base = REVB8_OTPGU_BASE;
183 else
184 oi->otpgu_base = REV36_OTPGU_BASE;
185 } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) {
186 oi->otpgu_base = REVB8_OTPGU_BASE;
187 }
188
189 /* First issue an init command so the status is up to date */
190 otpp =
191 OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
192
193 W_REG(&cc->otpprog, otpp);
194 for (k = 0;
195 ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
196 && (k < OTPP_TRIES); k++)
197 ;
198 if (k >= OTPP_TRIES)
199 return;
200
201 /* Read OTP lock bits and subregion programmed indication bits */
202 oi->status = R_REG(&cc->otpstatus);
203
204 if ((oi->sih->chip == BCM43224_CHIP_ID)
205 || (oi->sih->chip == BCM43225_CHIP_ID)) {
206 u32 p_bits;
207 p_bits =
208 (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
209 OTPGU_P_MSK)
210 >> OTPGU_P_SHIFT;
211 oi->status |= (p_bits << OTPS_GUP_SHIFT);
212 }
213
214 /*
215 * h/w region base and fuse region limit are fixed to
216 * the top and the bottom of the general use region.
217 * Everything else can be flexible.
218 */
219 oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
220 oi->hwlim = oi->wsize;
221 if (oi->status & OTPS_GUP_HW) {
222 oi->hwlim =
223 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
224 oi->swbase = oi->hwlim;
225 } else
226 oi->swbase = oi->hwbase;
227
228 /* subtract fuse and checksum from beginning */
229 oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
230
231 if (oi->status & OTPS_GUP_SW) {
232 oi->swlim =
233 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
234 oi->fbase = oi->swlim;
235 } else
236 oi->fbase = oi->swbase;
237
238 oi->flim = oi->wsize;
239}
240
241static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
242{
243 uint idx;
244 struct chipcregs __iomem *cc;
245
246 /* Make sure we're running IPX OTP */
247 if (!OTPTYPE_IPX(sih->ccrev))
248 return -EBADE;
249
250 /* Make sure OTP is not disabled */
251 if (ai_is_otp_disabled(sih))
252 return -EBADE;
253
254 /* Check for otp size */
255 switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
256 case 0:
257 /* Nothing there */
258 return -EBADE;
259 case 1: /* 32x64 */
260 oi->rows = 32;
261 oi->cols = 64;
262 oi->wsize = 128;
263 break;
264 case 2: /* 64x64 */
265 oi->rows = 64;
266 oi->cols = 64;
267 oi->wsize = 256;
268 break;
269 case 5: /* 96x64 */
270 oi->rows = 96;
271 oi->cols = 64;
272 oi->wsize = 384;
273 break;
274 case 7: /* 16x64 *//* 1024 bits */
275 oi->rows = 16;
276 oi->cols = 64;
277 oi->wsize = 64;
278 break;
279 default:
280 /* Don't know the geometry */
281 return -EBADE;
282 }
283
284 /* Retrieve OTP region info */
285 idx = ai_coreidx(sih);
286 cc = ai_setcoreidx(sih, SI_CC_IDX);
287
288 _ipxotp_init(oi, cc);
289
290 ai_setcoreidx(sih, idx);
291
292 return 0;
293}
294
295static int
296ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
297{
298 uint idx;
299 struct chipcregs __iomem *cc;
300 uint base, i, sz;
301
302 /* Validate region selection */
303 switch (region) {
304 case OTP_HW_RGN:
305 sz = (uint) oi->hwlim - oi->hwbase;
306 if (!(oi->status & OTPS_GUP_HW)) {
307 *wlen = sz;
308 return -ENODATA;
309 }
310 if (*wlen < sz) {
311 *wlen = sz;
312 return -EOVERFLOW;
313 }
314 base = oi->hwbase;
315 break;
316 case OTP_SW_RGN:
317 sz = ((uint) oi->swlim - oi->swbase);
318 if (!(oi->status & OTPS_GUP_SW)) {
319 *wlen = sz;
320 return -ENODATA;
321 }
322 if (*wlen < sz) {
323 *wlen = sz;
324 return -EOVERFLOW;
325 }
326 base = oi->swbase;
327 break;
328 case OTP_CI_RGN:
329 sz = OTPGU_CI_SZ;
330 if (!(oi->status & OTPS_GUP_CI)) {
331 *wlen = sz;
332 return -ENODATA;
333 }
334 if (*wlen < sz) {
335 *wlen = sz;
336 return -EOVERFLOW;
337 }
338 base = oi->otpgu_base + OTPGU_CI_OFF;
339 break;
340 case OTP_FUSE_RGN:
341 sz = (uint) oi->flim - oi->fbase;
342 if (!(oi->status & OTPS_GUP_FUSE)) {
343 *wlen = sz;
344 return -ENODATA;
345 }
346 if (*wlen < sz) {
347 *wlen = sz;
348 return -EOVERFLOW;
349 }
350 base = oi->fbase;
351 break;
352 case OTP_ALL_RGN:
353 sz = ((uint) oi->flim - oi->hwbase);
354 if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
355 *wlen = sz;
356 return -ENODATA;
357 }
358 if (*wlen < sz) {
359 *wlen = sz;
360 return -EOVERFLOW;
361 }
362 base = oi->hwbase;
363 break;
364 default:
365 return -EINVAL;
366 }
367
368 idx = ai_coreidx(oi->sih);
369 cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
370
371 /* Read the data */
372 for (i = 0; i < sz; i++)
373 data[i] = ipxotp_otpr(oi, cc, base + i);
374
375 ai_setcoreidx(oi->sih, idx);
376 *wlen = sz;
377 return 0;
378}
379
380static const struct otp_fn_s ipxotp_fn = {
381 (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
382 (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
383};
384
385static int otp_init(struct si_pub *sih, struct otpinfo *oi)
386{
387
388 int ret;
389
390 memset(oi, 0, sizeof(struct otpinfo));
391
392 oi->ccrev = sih->ccrev;
393
394 if (OTPTYPE_IPX(oi->ccrev))
395 oi->fn = &ipxotp_fn;
396
397 if (oi->fn == NULL)
398 return -EBADE;
399
400 oi->sih = sih;
401
402 ret = (oi->fn->init) (sih, oi);
403
404 return ret;
405}
406
407int
408otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
409 struct otpinfo otpinfo;
410 struct otpinfo *oi = &otpinfo;
411 int err = 0;
412
413 if (ai_is_otp_disabled(sih)) {
414 err = -EPERM;
415 goto out;
416 }
417
418 err = otp_init(sih, oi);
419 if (err)
420 goto out;
421
422 err = ((oi)->fn->read_region)(oi, region, data, wlen);
423
424 out:
425 return err;
426}