baed204ea4cd879865c16f66bf3326e3c810d9a3
[deliverable/linux.git] / drivers / staging / brcm80211 / brcmsmac / bcmotp.c
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 <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>
23
24 #include <bcmdefs.h>
25 #include <bcmdevs.h>
26 #include "wlc_types.h"
27 #include <brcmu_utils.h>
28 #include <aiutils.h>
29 #include <bcmsoc.h>
30 #include <chipcommon.h>
31 #include <bcmotp.h>
32
33 #define OTPS_GUP_MASK 0x00000f00
34 #define OTPS_GUP_SHIFT 8
35 #define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */
36 #define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */
37 #define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */
38 #define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */
39
40 /* Fields in otpprog in rev >= 21 */
41 #define OTPP_COL_MASK 0x000000ff
42 #define OTPP_COL_SHIFT 0
43 #define OTPP_ROW_MASK 0x0000ff00
44 #define OTPP_ROW_SHIFT 8
45 #define OTPP_OC_MASK 0x0f000000
46 #define OTPP_OC_SHIFT 24
47 #define OTPP_READERR 0x10000000
48 #define OTPP_VALUE_MASK 0x20000000
49 #define OTPP_VALUE_SHIFT 29
50 #define OTPP_START_BUSY 0x80000000
51 #define OTPP_READ 0x40000000
52
53 /* Opcodes for OTPP_OC field */
54 #define OTPPOC_READ 0
55 #define OTPPOC_BIT_PROG 1
56 #define OTPPOC_VERIFY 3
57 #define OTPPOC_INIT 4
58 #define OTPPOC_SET 5
59 #define OTPPOC_RESET 6
60 #define OTPPOC_OCST 7
61 #define OTPPOC_ROW_LOCK 8
62 #define OTPPOC_PRESCN_TEST 9
63
64 #define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
65
66 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
67
68 #define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
69
70 /* OTP common function type */
71 typedef int (*otp_status_t) (void *oh);
72 typedef int (*otp_size_t) (void *oh);
73 typedef void *(*otp_init_t) (struct si_pub *sih);
74 typedef u16(*otp_read_bit_t) (void *oh, chipcregs_t *cc, uint off);
75 typedef int (*otp_read_region_t) (struct si_pub *sih, int region, u16 *data,
76 uint *wlen);
77 typedef int (*otp_nvread_t) (void *oh, char *data, uint *len);
78
79 /* OTP function struct */
80 typedef struct otp_fn_s {
81 otp_size_t size;
82 otp_read_bit_t read_bit;
83 otp_init_t init;
84 otp_read_region_t read_region;
85 otp_nvread_t nvread;
86 otp_status_t status;
87 } otp_fn_t;
88
89 typedef struct {
90 uint ccrev; /* chipc revision */
91 otp_fn_t *fn; /* OTP functions */
92 struct si_pub *sih; /* Saved sb handle */
93
94 /* IPX OTP section */
95 u16 wsize; /* Size of otp in words */
96 u16 rows; /* Geometry */
97 u16 cols; /* Geometry */
98 u32 status; /* Flag bits (lock/prog/rv).
99 * (Reflected only when OTP is power cycled)
100 */
101 u16 hwbase; /* hardware subregion offset */
102 u16 hwlim; /* hardware subregion boundary */
103 u16 swbase; /* software subregion offset */
104 u16 swlim; /* software subregion boundary */
105 u16 fbase; /* fuse subregion offset */
106 u16 flim; /* fuse subregion boundary */
107 int otpgu_base; /* offset to General Use Region */
108 } otpinfo_t;
109
110 static otpinfo_t otpinfo;
111
112 /*
113 * IPX OTP Code
114 *
115 * Exported functions:
116 * ipxotp_status()
117 * ipxotp_size()
118 * ipxotp_init()
119 * ipxotp_read_bit()
120 * ipxotp_read_region()
121 * ipxotp_nvread()
122 *
123 */
124
125 #define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
126
127 /* OTP layout */
128 /* CC revs 21, 24 and 27 OTP General Use Region word offset */
129 #define REVA4_OTPGU_BASE 12
130
131 /* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
132 #define REVB8_OTPGU_BASE 20
133
134 /* CC rev 36 OTP General Use Region word offset */
135 #define REV36_OTPGU_BASE 12
136
137 /* Subregion word offsets in General Use region */
138 #define OTPGU_HSB_OFF 0
139 #define OTPGU_SFB_OFF 1
140 #define OTPGU_CI_OFF 2
141 #define OTPGU_P_OFF 3
142 #define OTPGU_SROM_OFF 4
143
144 /* Flag bit offsets in General Use region */
145 #define OTPGU_HWP_OFF 60
146 #define OTPGU_SWP_OFF 61
147 #define OTPGU_CIP_OFF 62
148 #define OTPGU_FUSEP_OFF 63
149 #define OTPGU_CIP_MSK 0x4000
150 #define OTPGU_P_MSK 0xf000
151 #define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
152
153 /* OTP Size */
154 #define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
155 #define OTP_SZ_FU_288 (288/8) /* 288 bits */
156 #define OTP_SZ_FU_216 (216/8) /* 216 bits */
157 #define OTP_SZ_FU_72 (72/8) /* 72 bits */
158 #define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
159 #define OTP4315_SWREG_SZ 178 /* 178 bytes */
160 #define OTP_SZ_FU_144 (144/8) /* 144 bits */
161
162 static int ipxotp_status(void *oh)
163 {
164 otpinfo_t *oi = (otpinfo_t *) oh;
165 return (int)(oi->status);
166 }
167
168 /* Return size in bytes */
169 static int ipxotp_size(void *oh)
170 {
171 otpinfo_t *oi = (otpinfo_t *) oh;
172 return (int)oi->wsize * 2;
173 }
174
175 static u16 ipxotp_otpr(void *oh, chipcregs_t *cc, uint wn)
176 {
177 otpinfo_t *oi;
178
179 oi = (otpinfo_t *) oh;
180
181 return R_REG(&cc->sromotp[wn]);
182 }
183
184 static u16 ipxotp_read_bit(void *oh, chipcregs_t *cc, uint off)
185 {
186 otpinfo_t *oi = (otpinfo_t *) oh;
187 uint k, row, col;
188 u32 otpp, st;
189
190 row = off / oi->cols;
191 col = off % oi->cols;
192
193 otpp = OTPP_START_BUSY |
194 ((OTPPOC_READ << OTPP_OC_SHIFT) & OTPP_OC_MASK) |
195 ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) |
196 ((col << OTPP_COL_SHIFT) & OTPP_COL_MASK);
197 W_REG(&cc->otpprog, otpp);
198
199 for (k = 0;
200 ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
201 && (k < OTPP_TRIES); k++)
202 ;
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 subtracting fuse region and checksum size,
215 * osizew is oi->wsize (OTP size - GU size) in words
216 */
217 static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
218 {
219 int ret = 0;
220
221 switch (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 break; /* Don't know about this chip */
231 }
232
233 return ret;
234 }
235
236 static void _ipxotp_init(otpinfo_t *oi, chipcregs_t *cc)
237 {
238 uint k;
239 u32 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(&cc->otpprog, otpp);
260 for (k = 0;
261 ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
262 && (k < OTPP_TRIES); k++)
263 ;
264 if (k >= OTPP_TRIES) {
265 return;
266 }
267
268 /* Read OTP lock bits and subregion programmed indication bits */
269 oi->status = R_REG(&cc->otpstatus);
270
271 if ((oi->sih->chip == BCM43224_CHIP_ID)
272 || (oi->sih->chip == BCM43225_CHIP_ID)) {
273 u32 p_bits;
274 p_bits =
275 (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
276 OTPGU_P_MSK)
277 >> OTPGU_P_SHIFT;
278 oi->status |= (p_bits << OTPS_GUP_SHIFT);
279 }
280
281 /*
282 * h/w region base and fuse region limit are fixed to the top and
283 * the bottom of the general use region. Everything else can be flexible.
284 */
285 oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
286 oi->hwlim = oi->wsize;
287 if (oi->status & OTPS_GUP_HW) {
288 oi->hwlim =
289 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
290 oi->swbase = oi->hwlim;
291 } else
292 oi->swbase = oi->hwbase;
293
294 /* subtract fuse and checksum from beginning */
295 oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
296
297 if (oi->status & OTPS_GUP_SW) {
298 oi->swlim =
299 ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
300 oi->fbase = oi->swlim;
301 } else
302 oi->fbase = oi->swbase;
303
304 oi->flim = oi->wsize;
305 }
306
307 static void *ipxotp_init(struct si_pub *sih)
308 {
309 uint idx;
310 chipcregs_t *cc;
311 otpinfo_t *oi;
312
313 /* Make sure we're running IPX OTP */
314 if (!OTPTYPE_IPX(sih->ccrev))
315 return NULL;
316
317 /* Make sure OTP is not disabled */
318 if (ai_is_otp_disabled(sih))
319 return NULL;
320
321 /* Make sure OTP is powered up */
322 if (!ai_is_otp_powered(sih))
323 return NULL;
324
325 oi = &otpinfo;
326
327 /* Check for otp size */
328 switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
329 case 0:
330 /* Nothing there */
331 return NULL;
332 case 1: /* 32x64 */
333 oi->rows = 32;
334 oi->cols = 64;
335 oi->wsize = 128;
336 break;
337 case 2: /* 64x64 */
338 oi->rows = 64;
339 oi->cols = 64;
340 oi->wsize = 256;
341 break;
342 case 5: /* 96x64 */
343 oi->rows = 96;
344 oi->cols = 64;
345 oi->wsize = 384;
346 break;
347 case 7: /* 16x64 *//* 1024 bits */
348 oi->rows = 16;
349 oi->cols = 64;
350 oi->wsize = 64;
351 break;
352 default:
353 /* Don't know the geometry */
354 return NULL;
355 }
356
357 /* Retrieve OTP region info */
358 idx = ai_coreidx(sih);
359 cc = ai_setcoreidx(sih, SI_CC_IDX);
360
361 _ipxotp_init(oi, cc);
362
363 ai_setcoreidx(sih, idx);
364
365 return (void *)oi;
366 }
367
368 static int ipxotp_read_region(void *oh, int region, u16 *data, uint *wlen)
369 {
370 otpinfo_t *oi = (otpinfo_t *) oh;
371 uint idx;
372 chipcregs_t *cc;
373 uint base, i, sz;
374
375 /* Validate region selection */
376 switch (region) {
377 case OTP_HW_RGN:
378 sz = (uint) oi->hwlim - oi->hwbase;
379 if (!(oi->status & OTPS_GUP_HW)) {
380 *wlen = sz;
381 return -ENODATA;
382 }
383 if (*wlen < sz) {
384 *wlen = sz;
385 return -EOVERFLOW;
386 }
387 base = oi->hwbase;
388 break;
389 case OTP_SW_RGN:
390 sz = ((uint) oi->swlim - oi->swbase);
391 if (!(oi->status & OTPS_GUP_SW)) {
392 *wlen = sz;
393 return -ENODATA;
394 }
395 if (*wlen < sz) {
396 *wlen = sz;
397 return -EOVERFLOW;
398 }
399 base = oi->swbase;
400 break;
401 case OTP_CI_RGN:
402 sz = OTPGU_CI_SZ;
403 if (!(oi->status & OTPS_GUP_CI)) {
404 *wlen = sz;
405 return -ENODATA;
406 }
407 if (*wlen < sz) {
408 *wlen = sz;
409 return -EOVERFLOW;
410 }
411 base = oi->otpgu_base + OTPGU_CI_OFF;
412 break;
413 case OTP_FUSE_RGN:
414 sz = (uint) oi->flim - oi->fbase;
415 if (!(oi->status & OTPS_GUP_FUSE)) {
416 *wlen = sz;
417 return -ENODATA;
418 }
419 if (*wlen < sz) {
420 *wlen = sz;
421 return -EOVERFLOW;
422 }
423 base = oi->fbase;
424 break;
425 case OTP_ALL_RGN:
426 sz = ((uint) oi->flim - oi->hwbase);
427 if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
428 *wlen = sz;
429 return -ENODATA;
430 }
431 if (*wlen < sz) {
432 *wlen = sz;
433 return -EOVERFLOW;
434 }
435 base = oi->hwbase;
436 break;
437 default:
438 return -EINVAL;
439 }
440
441 idx = ai_coreidx(oi->sih);
442 cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
443
444 /* Read the data */
445 for (i = 0; i < sz; i++)
446 data[i] = ipxotp_otpr(oh, cc, base + i);
447
448 ai_setcoreidx(oi->sih, idx);
449 *wlen = sz;
450 return 0;
451 }
452
453 static int ipxotp_nvread(void *oh, char *data, uint *len)
454 {
455 return -ENOTSUPP;
456 }
457
458 static otp_fn_t ipxotp_fn = {
459 (otp_size_t) ipxotp_size,
460 (otp_read_bit_t) ipxotp_read_bit,
461
462 (otp_init_t) ipxotp_init,
463 (otp_read_region_t) ipxotp_read_region,
464 (otp_nvread_t) ipxotp_nvread,
465
466 (otp_status_t) ipxotp_status
467 };
468
469 /*
470 * otp_status()
471 * otp_size()
472 * otp_read_bit()
473 * otp_init()
474 * otp_read_region()
475 * otp_nvread()
476 */
477
478 int otp_status(void *oh)
479 {
480 otpinfo_t *oi = (otpinfo_t *) oh;
481
482 return oi->fn->status(oh);
483 }
484
485 int otp_size(void *oh)
486 {
487 otpinfo_t *oi = (otpinfo_t *) oh;
488
489 return oi->fn->size(oh);
490 }
491
492 u16 otp_read_bit(void *oh, uint offset)
493 {
494 otpinfo_t *oi = (otpinfo_t *) oh;
495 uint idx = ai_coreidx(oi->sih);
496 chipcregs_t *cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
497 u16 readBit = (u16) oi->fn->read_bit(oh, cc, offset);
498 ai_setcoreidx(oi->sih, idx);
499 return readBit;
500 }
501
502 void *otp_init(struct si_pub *sih)
503 {
504 otpinfo_t *oi;
505 void *ret = NULL;
506
507 oi = &otpinfo;
508 memset(oi, 0, sizeof(otpinfo_t));
509
510 oi->ccrev = sih->ccrev;
511
512 if (OTPTYPE_IPX(oi->ccrev))
513 oi->fn = &ipxotp_fn;
514
515 if (oi->fn == NULL) {
516 return NULL;
517 }
518
519 oi->sih = sih;
520
521 ret = (oi->fn->init) (sih);
522
523 return ret;
524 }
525
526 int
527 otp_read_region(struct si_pub *sih, int region, u16 *data,
528 uint *wlen) {
529 bool wasup = false;
530 void *oh;
531 int err = 0;
532
533 wasup = ai_is_otp_powered(sih);
534 if (!wasup)
535 ai_otp_power(sih, true);
536
537 if (!ai_is_otp_powered(sih) || ai_is_otp_disabled(sih)) {
538 err = -EPERM;
539 goto out;
540 }
541
542 oh = otp_init(sih);
543 if (oh == NULL) {
544 err = -EBADE;
545 goto out;
546 }
547
548 err = (((otpinfo_t *) oh)->fn->read_region) (oh, region, data, wlen);
549
550 out:
551 if (!wasup)
552 ai_otp_power(sih, false);
553
554 return err;
555 }
556
557 int otp_nvread(void *oh, char *data, uint *len)
558 {
559 otpinfo_t *oi = (otpinfo_t *) oh;
560
561 return oi->fn->nvread(oh, data, len);
562 }
This page took 0.06021 seconds and 4 git commands to generate.