spi-topcliff-pch: add recovery processing in case wait-event timeout
[zen-stable.git] / drivers / net / wireless / brcm80211 / brcmsmac / otp.c
blobf1ca12625860427a74e2011cf7ebb4ad614e1dd1
1 /*
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/io.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
21 #include <brcm_hw_ids.h>
22 #include <chipcommon.h>
23 #include "aiutils.h"
24 #include "otp.h"
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
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
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
61 #define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
63 #define OTPP_TRIES 10000000 /* # of tries for OTPP */
65 #define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
67 /* Fixed size subregions sizes in words */
68 #define OTPGU_CI_SZ 2
70 struct otpinfo;
72 /* OTP function struct */
73 struct 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);
79 struct otpinfo {
80 struct bcma_device *core; /* chipc core */
81 const struct otp_fn_s *fn; /* OTP functions */
82 struct si_pub *sih; /* Saved sb handle */
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)
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 */
100 /* OTP layout */
101 /* CC revs 21, 24 and 27 OTP General Use Region word offset */
102 #define REVA4_OTPGU_BASE 12
104 /* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
105 #define REVB8_OTPGU_BASE 20
107 /* CC rev 36 OTP General Use Region word offset */
108 #define REV36_OTPGU_BASE 12
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
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)
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 */
135 static u16
136 ipxotp_otpr(struct otpinfo *oi, uint wn)
138 return bcma_read16(oi->core,
139 CHIPCREGOFFS(sromotp[wn]));
143 * Calculate max HW/SW region byte size by subtracting fuse region
144 * and checksum size, osizew is oi->wsize (OTP size - GU size) in words
146 static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
148 int ret = 0;
150 switch (ai_get_chip_id(sih)) {
151 case BCM43224_CHIP_ID:
152 case BCM43225_CHIP_ID:
153 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
154 break;
155 case BCM4313_CHIP_ID:
156 ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
157 break;
158 default:
159 break; /* Don't know about this chip */
162 return ret;
165 static void _ipxotp_init(struct otpinfo *oi)
167 uint k;
168 u32 otpp, st;
169 int ccrev = ai_get_ccrev(oi->sih);
173 * record word offset of General Use Region
174 * for various chipcommon revs
176 if (ccrev == 21 || ccrev == 24
177 || ccrev == 27) {
178 oi->otpgu_base = REVA4_OTPGU_BASE;
179 } else if (ccrev == 36) {
181 * OTP size greater than equal to 2KB (128 words),
182 * otpgu_base is similar to rev23
184 if (oi->wsize >= 128)
185 oi->otpgu_base = REVB8_OTPGU_BASE;
186 else
187 oi->otpgu_base = REV36_OTPGU_BASE;
188 } else if (ccrev == 23 || ccrev >= 25) {
189 oi->otpgu_base = REVB8_OTPGU_BASE;
192 /* First issue an init command so the status is up to date */
193 otpp =
194 OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
196 bcma_write32(oi->core, CHIPCREGOFFS(otpprog), otpp);
197 st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
198 for (k = 0; (st & OTPP_START_BUSY) && (k < OTPP_TRIES); k++)
199 st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
200 if (k >= OTPP_TRIES)
201 return;
203 /* Read OTP lock bits and subregion programmed indication bits */
204 oi->status = bcma_read32(oi->core, CHIPCREGOFFS(otpstatus));
206 if ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID)
207 || (ai_get_chip_id(oi->sih) == BCM43225_CHIP_ID)) {
208 u32 p_bits;
209 p_bits = (ipxotp_otpr(oi, oi->otpgu_base + OTPGU_P_OFF) &
210 OTPGU_P_MSK) >> OTPGU_P_SHIFT;
211 oi->status |= (p_bits << OTPS_GUP_SHIFT);
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.
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, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
224 oi->swbase = oi->hwlim;
225 } else
226 oi->swbase = oi->hwbase;
228 /* subtract fuse and checksum from beginning */
229 oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
231 if (oi->status & OTPS_GUP_SW) {
232 oi->swlim =
233 ipxotp_otpr(oi, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
234 oi->fbase = oi->swlim;
235 } else
236 oi->fbase = oi->swbase;
238 oi->flim = oi->wsize;
241 static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
243 /* Make sure we're running IPX OTP */
244 if (!OTPTYPE_IPX(ai_get_ccrev(sih)))
245 return -EBADE;
247 /* Make sure OTP is not disabled */
248 if (ai_is_otp_disabled(sih))
249 return -EBADE;
251 /* Check for otp size */
252 switch ((ai_get_cccaps(sih) & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
253 case 0:
254 /* Nothing there */
255 return -EBADE;
256 case 1: /* 32x64 */
257 oi->rows = 32;
258 oi->cols = 64;
259 oi->wsize = 128;
260 break;
261 case 2: /* 64x64 */
262 oi->rows = 64;
263 oi->cols = 64;
264 oi->wsize = 256;
265 break;
266 case 5: /* 96x64 */
267 oi->rows = 96;
268 oi->cols = 64;
269 oi->wsize = 384;
270 break;
271 case 7: /* 16x64 *//* 1024 bits */
272 oi->rows = 16;
273 oi->cols = 64;
274 oi->wsize = 64;
275 break;
276 default:
277 /* Don't know the geometry */
278 return -EBADE;
281 /* Retrieve OTP region info */
282 _ipxotp_init(oi);
283 return 0;
286 static int
287 ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
289 uint base, i, sz;
291 /* Validate region selection */
292 switch (region) {
293 case OTP_HW_RGN:
294 sz = (uint) oi->hwlim - oi->hwbase;
295 if (!(oi->status & OTPS_GUP_HW)) {
296 *wlen = sz;
297 return -ENODATA;
299 if (*wlen < sz) {
300 *wlen = sz;
301 return -EOVERFLOW;
303 base = oi->hwbase;
304 break;
305 case OTP_SW_RGN:
306 sz = ((uint) oi->swlim - oi->swbase);
307 if (!(oi->status & OTPS_GUP_SW)) {
308 *wlen = sz;
309 return -ENODATA;
311 if (*wlen < sz) {
312 *wlen = sz;
313 return -EOVERFLOW;
315 base = oi->swbase;
316 break;
317 case OTP_CI_RGN:
318 sz = OTPGU_CI_SZ;
319 if (!(oi->status & OTPS_GUP_CI)) {
320 *wlen = sz;
321 return -ENODATA;
323 if (*wlen < sz) {
324 *wlen = sz;
325 return -EOVERFLOW;
327 base = oi->otpgu_base + OTPGU_CI_OFF;
328 break;
329 case OTP_FUSE_RGN:
330 sz = (uint) oi->flim - oi->fbase;
331 if (!(oi->status & OTPS_GUP_FUSE)) {
332 *wlen = sz;
333 return -ENODATA;
335 if (*wlen < sz) {
336 *wlen = sz;
337 return -EOVERFLOW;
339 base = oi->fbase;
340 break;
341 case OTP_ALL_RGN:
342 sz = ((uint) oi->flim - oi->hwbase);
343 if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
344 *wlen = sz;
345 return -ENODATA;
347 if (*wlen < sz) {
348 *wlen = sz;
349 return -EOVERFLOW;
351 base = oi->hwbase;
352 break;
353 default:
354 return -EINVAL;
357 /* Read the data */
358 for (i = 0; i < sz; i++)
359 data[i] = ipxotp_otpr(oi, base + i);
361 *wlen = sz;
362 return 0;
365 static const struct otp_fn_s ipxotp_fn = {
366 (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
367 (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
370 static int otp_init(struct si_pub *sih, struct otpinfo *oi)
372 int ret;
374 memset(oi, 0, sizeof(struct otpinfo));
376 oi->core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
378 if (OTPTYPE_IPX(ai_get_ccrev(sih)))
379 oi->fn = &ipxotp_fn;
381 if (oi->fn == NULL)
382 return -EBADE;
384 oi->sih = sih;
386 ret = (oi->fn->init)(sih, oi);
388 return ret;
392 otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
393 struct otpinfo otpinfo;
394 struct otpinfo *oi = &otpinfo;
395 int err = 0;
397 if (ai_is_otp_disabled(sih)) {
398 err = -EPERM;
399 goto out;
402 err = otp_init(sih, oi);
403 if (err)
404 goto out;
406 err = ((oi)->fn->read_region)(oi, region, data, wlen);
408 out:
409 return err;