]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/net/wireless/brcm80211/brcmsmac/otp.c
brcm80211: smac: use inline access functions for struct si_pub fields
[mirror_ubuntu-bionic-kernel.git] / drivers / net / wireless / brcm80211 / brcmsmac / otp.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/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
70 struct otpinfo;
71
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);
77 };
78
79 struct 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
135 static u16
136 ipxotp_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 */
145 static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
146 {
147 int ret = 0;
148
149 switch (ai_get_chip_id(sih)) {
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
164 static 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->ccrev == 21 || oi->ccrev == 24
174 || oi->ccrev == 27) {
175 oi->otpgu_base = REVA4_OTPGU_BASE;
176 } else if (oi->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->ccrev == 23 || oi->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 ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID)
205 || (ai_get_chip_id(oi->sih) == 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
241 static 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(oi->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 ((ai_get_cccaps(sih) & 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
295 static int
296 ipxotp_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
380 static 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
385 static 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 = ai_get_ccrev(sih);
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
407 int
408 otp_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 }