xref: /openbmc/linux/drivers/bcma/sprom.c (revision f35e839a)
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 {
77 	int i;
78 	for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
79 		sprom[i] = bcma_read16(bus->drv_cc.core,
80 				       offset + (i * 2));
81 }
82 
83 /**************************************************
84  * Validation.
85  **************************************************/
86 
87 static inline u8 bcma_crc8(u8 crc, u8 data)
88 {
89 	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
90 	static const u8 t[] = {
91 		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
92 		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
93 		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
94 		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
95 		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
96 		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
97 		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
98 		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
99 		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
100 		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
101 		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
102 		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
103 		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
104 		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
105 		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
106 		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
107 		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
108 		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
109 		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
110 		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
111 		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
112 		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
113 		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
114 		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
115 		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
116 		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
117 		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
118 		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
119 		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
120 		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
121 		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
122 		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
123 	};
124 	return t[crc ^ data];
125 }
126 
127 static u8 bcma_sprom_crc(const u16 *sprom)
128 {
129 	int word;
130 	u8 crc = 0xFF;
131 
132 	for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
133 		crc = bcma_crc8(crc, sprom[word] & 0x00FF);
134 		crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
135 	}
136 	crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
137 	crc ^= 0xFF;
138 
139 	return crc;
140 }
141 
142 static int bcma_sprom_check_crc(const u16 *sprom)
143 {
144 	u8 crc;
145 	u8 expected_crc;
146 	u16 tmp;
147 
148 	crc = bcma_sprom_crc(sprom);
149 	tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
150 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
151 	if (crc != expected_crc)
152 		return -EPROTO;
153 
154 	return 0;
155 }
156 
157 static int bcma_sprom_valid(const u16 *sprom)
158 {
159 	u16 revision;
160 	int err;
161 
162 	err = bcma_sprom_check_crc(sprom);
163 	if (err)
164 		return err;
165 
166 	revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
167 	if (revision != 8 && revision != 9) {
168 		pr_err("Unsupported SPROM revision: %d\n", revision);
169 		return -ENOENT;
170 	}
171 
172 	return 0;
173 }
174 
175 /**************************************************
176  * SPROM extraction.
177  **************************************************/
178 
179 #define SPOFF(offset)	((offset) / sizeof(u16))
180 
181 #define SPEX(_field, _offset, _mask, _shift)	\
182 	bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
183 
184 #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);
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);
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 }
611