xref: /openbmc/linux/drivers/bcma/sprom.c (revision 2d6bed9c)
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 
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  */
453 static 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 BCMA_CHIP_ID_BCM4313:
472 		present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
473 		break;
474 
475 	case BCMA_CHIP_ID_BCM4331:
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  */
489 static 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 BCMA_CHIP_ID_BCM4313:
498 		present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
499 		break;
500 
501 	case BCMA_CHIP_ID_BCM4331:
502 		present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
503 		break;
504 
505 	case BCMA_CHIP_ID_BCM43224:
506 	case BCMA_CHIP_ID_BCM43225:
507 		/* for these chips OTP is always available */
508 		present = true;
509 		break;
510 	case BCMA_CHIP_ID_BCM43227:
511 	case BCMA_CHIP_ID_BCM43228:
512 	case BCMA_CHIP_ID_BCM43428:
513 		present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
514 		break;
515 	default:
516 		present = false;
517 		break;
518 	}
519 
520 	if (present) {
521 		otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
522 		otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
523 	}
524 
525 	return otpsize != 0;
526 }
527 
528 /*
529  * Verify OTP is filled and determine the byte
530  * offset where SPROM data is located.
531  *
532  * On error, returns 0; byte offset otherwise.
533  */
534 static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
535 {
536 	struct bcma_device *cc = bus->drv_cc.core;
537 	u32 offset;
538 
539 	/* verify OTP status */
540 	if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
541 		return 0;
542 
543 	/* obtain bit offset from otplayout register */
544 	offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
545 	return BCMA_CC_SPROM + (offset >> 3);
546 }
547 
548 int bcma_sprom_get(struct bcma_bus *bus)
549 {
550 	u16 offset = BCMA_CC_SPROM;
551 	u16 *sprom;
552 	int err = 0;
553 
554 	if (!bus->drv_cc.core)
555 		return -EOPNOTSUPP;
556 
557 	if (!bcma_sprom_ext_available(bus)) {
558 		bool sprom_onchip;
559 
560 		/*
561 		 * External SPROM takes precedence so check
562 		 * on-chip OTP only when no external SPROM
563 		 * is present.
564 		 */
565 		sprom_onchip = bcma_sprom_onchip_available(bus);
566 		if (sprom_onchip) {
567 			/* determine offset */
568 			offset = bcma_sprom_onchip_offset(bus);
569 		}
570 		if (!offset || !sprom_onchip) {
571 			/*
572 			 * Maybe there is no SPROM on the device?
573 			 * Now we ask the arch code if there is some sprom
574 			 * available for this device in some other storage.
575 			 */
576 			err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
577 			return err;
578 		}
579 	}
580 
581 	sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
582 			GFP_KERNEL);
583 	if (!sprom)
584 		return -ENOMEM;
585 
586 	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
587 	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
588 		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
589 
590 	bcma_debug(bus, "SPROM offset 0x%x\n", offset);
591 	bcma_sprom_read(bus, offset, sprom);
592 
593 	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
594 	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
595 		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
596 
597 	err = bcma_sprom_valid(sprom);
598 	if (err)
599 		goto out;
600 
601 	bcma_sprom_extract_r8(bus, sprom);
602 
603 out:
604 	kfree(sprom);
605 	return err;
606 }
607