]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/bcma/sprom.c
Merge tag 'fbdev-updates-for-3.4' of git://github.com/schandinat/linux-2.6
[mv-sheeva.git] / drivers / bcma / sprom.c
1 /*
2  * Broadcom specific AMBA
3  * SPROM reading
4  *
5  * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6  *
7  * Licensed under the GNU/GPL. See COPYING for details.
8  */
9
10 #include "bcma_private.h"
11
12 #include <linux/bcma/bcma.h>
13 #include <linux/bcma/bcma_regs.h>
14 #include <linux/pci.h>
15 #include <linux/io.h>
16 #include <linux/dma-mapping.h>
17 #include <linux/slab.h>
18
19 static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
20
21 /**
22  * bcma_arch_register_fallback_sprom - Registers a method providing a
23  * fallback SPROM if no SPROM is found.
24  *
25  * @sprom_callback: The callback function.
26  *
27  * With this function the architecture implementation may register a
28  * callback handler which fills the SPROM data structure. The fallback is
29  * used for PCI based BCMA devices, where no valid SPROM can be found
30  * in the shadow registers and to provide the SPROM for SoCs where BCMA is
31  * to controll the system bus.
32  *
33  * This function is useful for weird architectures that have a half-assed
34  * BCMA device hardwired to their PCI bus.
35  *
36  * This function is available for architecture code, only. So it is not
37  * exported.
38  */
39 int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
40                                      struct ssb_sprom *out))
41 {
42         if (get_fallback_sprom)
43                 return -EEXIST;
44         get_fallback_sprom = sprom_callback;
45
46         return 0;
47 }
48
49 static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
50                                          struct ssb_sprom *out)
51 {
52         int err;
53
54         if (!get_fallback_sprom) {
55                 err = -ENOENT;
56                 goto fail;
57         }
58
59         err = get_fallback_sprom(bus, out);
60         if (err)
61                 goto fail;
62
63         pr_debug("Using SPROM revision %d provided by"
64                  " platform.\n", bus->sprom.revision);
65         return 0;
66 fail:
67         pr_warn("Using fallback SPROM failed (err %d)\n", err);
68         return err;
69 }
70
71 /**************************************************
72  * R/W ops.
73  **************************************************/
74
75 static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
76 {
77         int i;
78         for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
79                 sprom[i] = bcma_read16(bus->drv_cc.core,
80                                        offset + (i * 2));
81 }
82
83 /**************************************************
84  * Validation.
85  **************************************************/
86
87 static inline u8 bcma_crc8(u8 crc, u8 data)
88 {
89         /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
90         static const u8 t[] = {
91                 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
92                 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
93                 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
94                 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
95                 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
96                 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
97                 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
98                 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
99                 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
100                 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
101                 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
102                 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
103                 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
104                 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
105                 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
106                 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
107                 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
108                 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
109                 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
110                 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
111                 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
112                 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
113                 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
114                 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
115                 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
116                 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
117                 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
118                 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
119                 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
120                 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
121                 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
122                 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
123         };
124         return t[crc ^ data];
125 }
126
127 static u8 bcma_sprom_crc(const u16 *sprom)
128 {
129         int word;
130         u8 crc = 0xFF;
131
132         for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
133                 crc = bcma_crc8(crc, sprom[word] & 0x00FF);
134                 crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
135         }
136         crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
137         crc ^= 0xFF;
138
139         return crc;
140 }
141
142 static int bcma_sprom_check_crc(const u16 *sprom)
143 {
144         u8 crc;
145         u8 expected_crc;
146         u16 tmp;
147
148         crc = bcma_sprom_crc(sprom);
149         tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
150         expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
151         if (crc != expected_crc)
152                 return -EPROTO;
153
154         return 0;
155 }
156
157 static int bcma_sprom_valid(const u16 *sprom)
158 {
159         u16 revision;
160         int err;
161
162         err = bcma_sprom_check_crc(sprom);
163         if (err)
164                 return err;
165
166         revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
167         if (revision != 8 && revision != 9) {
168                 pr_err("Unsupported SPROM revision: %d\n", revision);
169                 return -ENOENT;
170         }
171
172         return 0;
173 }
174
175 /**************************************************
176  * SPROM extraction.
177  **************************************************/
178
179 #define SPOFF(offset)   ((offset) / sizeof(u16))
180
181 #define SPEX(_field, _offset, _mask, _shift)    \
182         bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
183
184 static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
185 {
186         u16 v, o;
187         int i;
188         u16 pwr_info_offset[] = {
189                 SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
190                 SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
191         };
192         BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
193                         ARRAY_SIZE(bus->sprom.core_pwr_info));
194
195         bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
196                 SSB_SPROM_REVISION_REV;
197
198         for (i = 0; i < 3; i++) {
199                 v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
200                 *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
201         }
202
203         SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
204
205         SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
206              SSB_SPROM4_TXPID2G0_SHIFT);
207         SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
208              SSB_SPROM4_TXPID2G1_SHIFT);
209         SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
210              SSB_SPROM4_TXPID2G2_SHIFT);
211         SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
212              SSB_SPROM4_TXPID2G3_SHIFT);
213
214         SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
215              SSB_SPROM4_TXPID5GL0_SHIFT);
216         SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
217              SSB_SPROM4_TXPID5GL1_SHIFT);
218         SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
219              SSB_SPROM4_TXPID5GL2_SHIFT);
220         SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
221              SSB_SPROM4_TXPID5GL3_SHIFT);
222
223         SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
224              SSB_SPROM4_TXPID5G0_SHIFT);
225         SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
226              SSB_SPROM4_TXPID5G1_SHIFT);
227         SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
228              SSB_SPROM4_TXPID5G2_SHIFT);
229         SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
230              SSB_SPROM4_TXPID5G3_SHIFT);
231
232         SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
233              SSB_SPROM4_TXPID5GH0_SHIFT);
234         SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
235              SSB_SPROM4_TXPID5GH1_SHIFT);
236         SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
237              SSB_SPROM4_TXPID5GH2_SHIFT);
238         SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
239              SSB_SPROM4_TXPID5GH3_SHIFT);
240
241         SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
242         SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
243         SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
244         SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
245
246         SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0);
247
248         /* Extract cores power info info */
249         for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
250                 o = pwr_info_offset[i];
251                 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
252                         SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
253                 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
254                         SSB_SPROM8_2G_MAXP, 0);
255
256                 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
257                 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
258                 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
259
260                 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
261                         SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
262                 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
263                         SSB_SPROM8_5G_MAXP, 0);
264                 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
265                         SSB_SPROM8_5GH_MAXP, 0);
266                 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
267                         SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
268
269                 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
270                 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
271                 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
272                 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
273                 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
274                 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
275                 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
276                 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
277                 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
278         }
279
280         SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
281              SSB_SROM8_FEM_TSSIPOS_SHIFT);
282         SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
283              SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
284         SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
285              SSB_SROM8_FEM_PDET_RANGE_SHIFT);
286         SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
287              SSB_SROM8_FEM_TR_ISO_SHIFT);
288         SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
289              SSB_SROM8_FEM_ANTSWLUT_SHIFT);
290
291         SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
292              SSB_SROM8_FEM_TSSIPOS_SHIFT);
293         SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
294              SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
295         SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
296              SSB_SROM8_FEM_PDET_RANGE_SHIFT);
297         SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
298              SSB_SROM8_FEM_TR_ISO_SHIFT);
299         SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
300              SSB_SROM8_FEM_ANTSWLUT_SHIFT);
301 }
302
303 /*
304  * Indicates the presence of external SPROM.
305  */
306 static bool bcma_sprom_ext_available(struct bcma_bus *bus)
307 {
308         u32 chip_status;
309         u32 srom_control;
310         u32 present_mask;
311
312         if (bus->drv_cc.core->id.rev >= 31) {
313                 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
314                         return false;
315
316                 srom_control = bcma_read32(bus->drv_cc.core,
317                                            BCMA_CC_SROM_CONTROL);
318                 return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
319         }
320
321         /* older chipcommon revisions use chip status register */
322         chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
323         switch (bus->chipinfo.id) {
324         case 0x4313:
325                 present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
326                 break;
327
328         case 0x4331:
329                 present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
330                 break;
331
332         default:
333                 return true;
334         }
335
336         return chip_status & present_mask;
337 }
338
339 /*
340  * Indicates that on-chip OTP memory is present and enabled.
341  */
342 static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
343 {
344         u32 chip_status;
345         u32 otpsize = 0;
346         bool present;
347
348         chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
349         switch (bus->chipinfo.id) {
350         case 0x4313:
351                 present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
352                 break;
353
354         case 0x4331:
355                 present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
356                 break;
357
358         case 43224:
359         case 43225:
360                 /* for these chips OTP is always available */
361                 present = true;
362                 break;
363
364         default:
365                 present = false;
366                 break;
367         }
368
369         if (present) {
370                 otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
371                 otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
372         }
373
374         return otpsize != 0;
375 }
376
377 /*
378  * Verify OTP is filled and determine the byte
379  * offset where SPROM data is located.
380  *
381  * On error, returns 0; byte offset otherwise.
382  */
383 static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
384 {
385         struct bcma_device *cc = bus->drv_cc.core;
386         u32 offset;
387
388         /* verify OTP status */
389         if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
390                 return 0;
391
392         /* obtain bit offset from otplayout register */
393         offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
394         return BCMA_CC_SPROM + (offset >> 3);
395 }
396
397 int bcma_sprom_get(struct bcma_bus *bus)
398 {
399         u16 offset = BCMA_CC_SPROM;
400         u16 *sprom;
401         int err = 0;
402
403         if (!bus->drv_cc.core)
404                 return -EOPNOTSUPP;
405
406         if (!bcma_sprom_ext_available(bus)) {
407                 /*
408                  * External SPROM takes precedence so check
409                  * on-chip OTP only when no external SPROM
410                  * is present.
411                  */
412                 if (bcma_sprom_onchip_available(bus)) {
413                         /* determine offset */
414                         offset = bcma_sprom_onchip_offset(bus);
415                 }
416                 if (!offset) {
417                         /*
418                          * Maybe there is no SPROM on the device?
419                          * Now we ask the arch code if there is some sprom
420                          * available for this device in some other storage.
421                          */
422                         err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
423                         return err;
424                 }
425         }
426
427         sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
428                         GFP_KERNEL);
429         if (!sprom)
430                 return -ENOMEM;
431
432         if (bus->chipinfo.id == 0x4331)
433                 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
434
435         pr_debug("SPROM offset 0x%x\n", offset);
436         bcma_sprom_read(bus, offset, sprom);
437
438         if (bus->chipinfo.id == 0x4331)
439                 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
440
441         err = bcma_sprom_valid(sprom);
442         if (err)
443                 goto out;
444
445         bcma_sprom_extract_r8(bus, sprom);
446
447 out:
448         kfree(sprom);
449         return err;
450 }