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