]> Pileus Git - ~andy/linux/blob - drivers/bcma/sprom.c
5386cddba43ef0b90dc109b5267036757aa6b5b3
[~andy/linux] / 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         bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
64                    bus->sprom.revision);
65         return 0;
66 fail:
67         bcma_warn(bus, "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                             size_t words)
77 {
78         int i;
79         for (i = 0; i < words; i++)
80                 sprom[i] = bcma_read16(bus->drv_cc.core, 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, size_t words)
128 {
129         int word;
130         u8 crc = 0xFF;
131
132         for (word = 0; word < words - 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[words - 1] & 0x00FF);
137         crc ^= 0xFF;
138
139         return crc;
140 }
141
142 static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
143 {
144         u8 crc;
145         u8 expected_crc;
146         u16 tmp;
147
148         crc = bcma_sprom_crc(sprom, words);
149         tmp = sprom[words - 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, size_t words)
158 {
159         u16 revision;
160         int err;
161
162         err = bcma_sprom_check_crc(sprom, words);
163         if (err)
164                 return err;
165
166         revision = sprom[words - 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 #define SPEX32(_field, _offset, _mask, _shift)  \
185         bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
186                                 sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
187
188 #define SPEX_ARRAY8(_field, _offset, _mask, _shift)     \
189         do {    \
190                 SPEX(_field[0], _offset +  0, _mask, _shift);   \
191                 SPEX(_field[1], _offset +  2, _mask, _shift);   \
192                 SPEX(_field[2], _offset +  4, _mask, _shift);   \
193                 SPEX(_field[3], _offset +  6, _mask, _shift);   \
194                 SPEX(_field[4], _offset +  8, _mask, _shift);   \
195                 SPEX(_field[5], _offset + 10, _mask, _shift);   \
196                 SPEX(_field[6], _offset + 12, _mask, _shift);   \
197                 SPEX(_field[7], _offset + 14, _mask, _shift);   \
198         } while (0)
199
200 static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
201 {
202         u16 v, o;
203         int i;
204         u16 pwr_info_offset[] = {
205                 SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
206                 SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
207         };
208         BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
209                         ARRAY_SIZE(bus->sprom.core_pwr_info));
210
211         bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
212                 SSB_SPROM_REVISION_REV;
213
214         for (i = 0; i < 3; i++) {
215                 v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
216                 *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
217         }
218
219         SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
220         SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
221
222         SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
223              SSB_SPROM4_TXPID2G0_SHIFT);
224         SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
225              SSB_SPROM4_TXPID2G1_SHIFT);
226         SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
227              SSB_SPROM4_TXPID2G2_SHIFT);
228         SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
229              SSB_SPROM4_TXPID2G3_SHIFT);
230
231         SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
232              SSB_SPROM4_TXPID5GL0_SHIFT);
233         SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
234              SSB_SPROM4_TXPID5GL1_SHIFT);
235         SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
236              SSB_SPROM4_TXPID5GL2_SHIFT);
237         SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
238              SSB_SPROM4_TXPID5GL3_SHIFT);
239
240         SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
241              SSB_SPROM4_TXPID5G0_SHIFT);
242         SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
243              SSB_SPROM4_TXPID5G1_SHIFT);
244         SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
245              SSB_SPROM4_TXPID5G2_SHIFT);
246         SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
247              SSB_SPROM4_TXPID5G3_SHIFT);
248
249         SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
250              SSB_SPROM4_TXPID5GH0_SHIFT);
251         SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
252              SSB_SPROM4_TXPID5GH1_SHIFT);
253         SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
254              SSB_SPROM4_TXPID5GH2_SHIFT);
255         SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
256              SSB_SPROM4_TXPID5GH3_SHIFT);
257
258         SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
259         SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
260         SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
261         SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
262
263         SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
264         SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
265
266         /* Extract cores power info info */
267         for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
268                 o = pwr_info_offset[i];
269                 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
270                         SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
271                 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
272                         SSB_SPROM8_2G_MAXP, 0);
273
274                 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
275                 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
276                 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
277
278                 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
279                         SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
280                 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
281                         SSB_SPROM8_5G_MAXP, 0);
282                 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
283                         SSB_SPROM8_5GH_MAXP, 0);
284                 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
285                         SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
286
287                 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
288                 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
289                 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
290                 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
291                 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
292                 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
293                 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
294                 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
295                 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
296         }
297
298         SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
299              SSB_SROM8_FEM_TSSIPOS_SHIFT);
300         SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
301              SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
302         SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
303              SSB_SROM8_FEM_PDET_RANGE_SHIFT);
304         SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
305              SSB_SROM8_FEM_TR_ISO_SHIFT);
306         SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
307              SSB_SROM8_FEM_ANTSWLUT_SHIFT);
308
309         SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
310              SSB_SROM8_FEM_TSSIPOS_SHIFT);
311         SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
312              SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
313         SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
314              SSB_SROM8_FEM_PDET_RANGE_SHIFT);
315         SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
316              SSB_SROM8_FEM_TR_ISO_SHIFT);
317         SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
318              SSB_SROM8_FEM_ANTSWLUT_SHIFT);
319
320         SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
321              SSB_SPROM8_ANTAVAIL_A_SHIFT);
322         SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
323              SSB_SPROM8_ANTAVAIL_BG_SHIFT);
324         SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
325         SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
326              SSB_SPROM8_ITSSI_BG_SHIFT);
327         SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
328         SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
329              SSB_SPROM8_ITSSI_A_SHIFT);
330         SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
331         SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
332              SSB_SPROM8_MAXP_AL_SHIFT);
333         SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
334         SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
335              SSB_SPROM8_GPIOA_P1_SHIFT);
336         SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
337         SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
338              SSB_SPROM8_GPIOB_P3_SHIFT);
339         SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
340         SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
341              SSB_SPROM8_TRI5G_SHIFT);
342         SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
343         SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
344              SSB_SPROM8_TRI5GH_SHIFT);
345         SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
346              SSB_SPROM8_RXPO2G_SHIFT);
347         SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
348              SSB_SPROM8_RXPO5G_SHIFT);
349         SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
350         SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
351              SSB_SPROM8_RSSISMC2G_SHIFT);
352         SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
353              SSB_SPROM8_RSSISAV2G_SHIFT);
354         SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
355              SSB_SPROM8_BXA2G_SHIFT);
356         SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
357         SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
358              SSB_SPROM8_RSSISMC5G_SHIFT);
359         SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
360              SSB_SPROM8_RSSISAV5G_SHIFT);
361         SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
362              SSB_SPROM8_BXA5G_SHIFT);
363
364         SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
365         SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
366         SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
367         SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
368         SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
369         SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
370         SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
371         SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
372         SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
373         SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
374         SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
375         SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
376         SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
377         SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
378         SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
379         SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
380         SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
381
382         /* Extract the antenna gain values. */
383         SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
384              SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
385         SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
386              SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
387         SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
388              SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
389         SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
390              SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
391
392         SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
393              SSB_SPROM8_LEDDC_ON_SHIFT);
394         SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
395              SSB_SPROM8_LEDDC_OFF_SHIFT);
396
397         SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
398              SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
399         SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
400              SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
401         SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
402              SSB_SPROM8_TXRXC_SWITCH_SHIFT);
403
404         SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
405
406         SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
407         SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
408         SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
409         SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
410
411         SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
412              SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
413         SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
414              SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
415         SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
416              SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
417              SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
418         SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
419              SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
420         SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
421              SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
422              SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
423         SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
424              SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
425              SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
426         SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
427              SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
428              SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
429         SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
430              SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
431
432         SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
433         SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
434         SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
435         SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
436
437         SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
438              SSB_SPROM8_THERMAL_TRESH_SHIFT);
439         SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
440              SSB_SPROM8_THERMAL_OFFSET_SHIFT);
441         SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
442              SSB_SPROM8_TEMPDELTA_PHYCAL,
443              SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
444         SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
445              SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
446         SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
447              SSB_SPROM8_TEMPDELTA_HYSTERESIS,
448              SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
449 }
450
451 /*
452  * Indicates the presence of external SPROM.
453  */
454 static bool bcma_sprom_ext_available(struct bcma_bus *bus)
455 {
456         u32 chip_status;
457         u32 srom_control;
458         u32 present_mask;
459
460         if (bus->drv_cc.core->id.rev >= 31) {
461                 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
462                         return false;
463
464                 srom_control = bcma_read32(bus->drv_cc.core,
465                                            BCMA_CC_SROM_CONTROL);
466                 return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
467         }
468
469         /* older chipcommon revisions use chip status register */
470         chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
471         switch (bus->chipinfo.id) {
472         case BCMA_CHIP_ID_BCM4313:
473                 present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
474                 break;
475
476         case BCMA_CHIP_ID_BCM4331:
477                 present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
478                 break;
479
480         default:
481                 return true;
482         }
483
484         return chip_status & present_mask;
485 }
486
487 /*
488  * Indicates that on-chip OTP memory is present and enabled.
489  */
490 static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
491 {
492         u32 chip_status;
493         u32 otpsize = 0;
494         bool present;
495
496         chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
497         switch (bus->chipinfo.id) {
498         case BCMA_CHIP_ID_BCM4313:
499                 present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
500                 break;
501
502         case BCMA_CHIP_ID_BCM4331:
503                 present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
504                 break;
505
506         case BCMA_CHIP_ID_BCM43224:
507         case BCMA_CHIP_ID_BCM43225:
508                 /* for these chips OTP is always available */
509                 present = true;
510                 break;
511         case BCMA_CHIP_ID_BCM43227:
512         case BCMA_CHIP_ID_BCM43228:
513         case BCMA_CHIP_ID_BCM43428:
514                 present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
515                 break;
516         default:
517                 present = false;
518                 break;
519         }
520
521         if (present) {
522                 otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
523                 otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
524         }
525
526         return otpsize != 0;
527 }
528
529 /*
530  * Verify OTP is filled and determine the byte
531  * offset where SPROM data is located.
532  *
533  * On error, returns 0; byte offset otherwise.
534  */
535 static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
536 {
537         struct bcma_device *cc = bus->drv_cc.core;
538         u32 offset;
539
540         /* verify OTP status */
541         if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
542                 return 0;
543
544         /* obtain bit offset from otplayout register */
545         offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
546         return BCMA_CC_SPROM + (offset >> 3);
547 }
548
549 int bcma_sprom_get(struct bcma_bus *bus)
550 {
551         u16 offset = BCMA_CC_SPROM;
552         u16 *sprom;
553         int err = 0;
554
555         if (!bus->drv_cc.core)
556                 return -EOPNOTSUPP;
557
558         if (!bcma_sprom_ext_available(bus)) {
559                 bool sprom_onchip;
560
561                 /*
562                  * External SPROM takes precedence so check
563                  * on-chip OTP only when no external SPROM
564                  * is present.
565                  */
566                 sprom_onchip = bcma_sprom_onchip_available(bus);
567                 if (sprom_onchip) {
568                         /* determine offset */
569                         offset = bcma_sprom_onchip_offset(bus);
570                 }
571                 if (!offset || !sprom_onchip) {
572                         /*
573                          * Maybe there is no SPROM on the device?
574                          * Now we ask the arch code if there is some sprom
575                          * available for this device in some other storage.
576                          */
577                         err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
578                         return err;
579                 }
580         }
581
582         sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
583                         GFP_KERNEL);
584         if (!sprom)
585                 return -ENOMEM;
586
587         if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
588             bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
589                 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
590
591         bcma_debug(bus, "SPROM offset 0x%x\n", offset);
592         bcma_sprom_read(bus, offset, sprom, SSB_SPROMSIZE_WORDS_R4);
593
594         if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
595             bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
596                 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
597
598         err = bcma_sprom_valid(sprom, SSB_SPROMSIZE_WORDS_R4);
599         if (err) {
600                 bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
601                 err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
602                 goto out;
603         }
604
605         bcma_sprom_extract_r8(bus, sprom);
606
607 out:
608         kfree(sprom);
609         return err;
610 }