xref: /linux/drivers/bcma/sprom.c (revision 5e8c0fb6a95728b852d56c0a9244425d474670c0)
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(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 
204 static 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 
221 static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
222 {
223 	u16 v, o;
224 	int i;
225 	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  */
480 static 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  */
516 static 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  */
563 static 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 
577 int bcma_sprom_get(struct bcma_bus *bus)
578 {
579 	u16 offset = BCMA_CC_SPROM;
580 	u16 *sprom;
581 	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
582 				 SSB_SPROMSIZE_WORDS_R10, };
583 	int i, err = 0;
584 
585 	if (!bus->drv_cc.core)
586 		return -EOPNOTSUPP;
587 
588 	if (!bcma_sprom_ext_available(bus)) {
589 		bool sprom_onchip;
590 
591 		/*
592 		 * External SPROM takes precedence so check
593 		 * on-chip OTP only when no external SPROM
594 		 * is present.
595 		 */
596 		sprom_onchip = bcma_sprom_onchip_available(bus);
597 		if (sprom_onchip) {
598 			/* determine offset */
599 			offset = bcma_sprom_onchip_offset(bus);
600 		}
601 		if (!offset || !sprom_onchip) {
602 			/*
603 			 * Maybe there is no SPROM on the device?
604 			 * Now we ask the arch code if there is some sprom
605 			 * available for this device in some other storage.
606 			 */
607 			err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
608 			return err;
609 		}
610 	}
611 
612 	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
613 	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
614 		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
615 
616 	bcma_debug(bus, "SPROM offset 0x%x\n", offset);
617 	for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
618 		size_t words = sprom_sizes[i];
619 
620 		sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
621 		if (!sprom)
622 			return -ENOMEM;
623 
624 		bcma_sprom_read(bus, offset, sprom, words);
625 		err = bcma_sprom_valid(bus, sprom, words);
626 		if (!err)
627 			break;
628 
629 		kfree(sprom);
630 	}
631 
632 	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
633 	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
634 		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
635 
636 	if (err) {
637 		bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
638 		err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
639 	} else {
640 		bcma_sprom_extract_r8(bus, sprom);
641 		kfree(sprom);
642 	}
643 
644 	return err;
645 }
646