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