sprom.c revision 92eb164258cfce173060d3fe7aaffa2afaf735d7
1/*
2 * Broadcom specific AMBA
3 * SPROM reading
4 *
5 * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6 *
7 * Licensed under the GNU/GPL. See COPYING for details.
8 */
9
10#include "bcma_private.h"
11
12#include <linux/bcma/bcma.h>
13#include <linux/bcma/bcma_regs.h>
14#include <linux/pci.h>
15#include <linux/io.h>
16#include <linux/dma-mapping.h>
17#include <linux/slab.h>
18
19static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
20
21/**
22 * bcma_arch_register_fallback_sprom - Registers a method providing a
23 * fallback SPROM if no SPROM is found.
24 *
25 * @sprom_callback: The callback function.
26 *
27 * With this function the architecture implementation may register a
28 * callback handler which fills the SPROM data structure. The fallback is
29 * used for PCI based BCMA devices, where no valid SPROM can be found
30 * in the shadow registers and to provide the SPROM for SoCs where BCMA is
31 * to controll the system bus.
32 *
33 * This function is useful for weird architectures that have a half-assed
34 * BCMA device hardwired to their PCI bus.
35 *
36 * This function is available for architecture code, only. So it is not
37 * exported.
38 */
39int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
40				     struct ssb_sprom *out))
41{
42	if (get_fallback_sprom)
43		return -EEXIST;
44	get_fallback_sprom = sprom_callback;
45
46	return 0;
47}
48
49static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
50					 struct ssb_sprom *out)
51{
52	int err;
53
54	if (!get_fallback_sprom) {
55		err = -ENOENT;
56		goto fail;
57	}
58
59	err = get_fallback_sprom(bus, out);
60	if (err)
61		goto fail;
62
63	bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
64		   bus->sprom.revision);
65	return 0;
66fail:
67	bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
68	return err;
69}
70
71/**************************************************
72 * R/W ops.
73 **************************************************/
74
75static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
76			    size_t words)
77{
78	int i;
79	for (i = 0; i < words; i++)
80		sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
81}
82
83/**************************************************
84 * Validation.
85 **************************************************/
86
87static inline u8 bcma_crc8(u8 crc, u8 data)
88{
89	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
90	static const u8 t[] = {
91		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
92		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
93		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
94		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
95		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
96		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
97		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
98		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
99		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
100		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
101		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
102		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
103		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
104		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
105		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
106		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
107		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
108		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
109		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
110		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
111		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
112		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
113		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
114		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
115		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
116		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
117		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
118		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
119		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
120		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
121		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
122		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
123	};
124	return t[crc ^ data];
125}
126
127static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
128{
129	int word;
130	u8 crc = 0xFF;
131
132	for (word = 0; word < words - 1; word++) {
133		crc = bcma_crc8(crc, sprom[word] & 0x00FF);
134		crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
135	}
136	crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
137	crc ^= 0xFF;
138
139	return crc;
140}
141
142static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
143{
144	u8 crc;
145	u8 expected_crc;
146	u16 tmp;
147
148	crc = bcma_sprom_crc(sprom, words);
149	tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
150	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
151	if (crc != expected_crc)
152		return -EPROTO;
153
154	return 0;
155}
156
157static int bcma_sprom_valid(const u16 *sprom, size_t words)
158{
159	u16 revision;
160	int err;
161
162	err = bcma_sprom_check_crc(sprom, words);
163	if (err)
164		return err;
165
166	revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
167	if (revision != 8 && revision != 9) {
168		pr_err("Unsupported SPROM revision: %d\n", revision);
169		return -ENOENT;
170	}
171
172	return 0;
173}
174
175/**************************************************
176 * SPROM extraction.
177 **************************************************/
178
179#define SPOFF(offset)	((offset) / sizeof(u16))
180
181#define SPEX(_field, _offset, _mask, _shift)	\
182	bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
183
184#define SPEX32(_field, _offset, _mask, _shift)	\
185	bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
186				sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
187
188#define SPEX_ARRAY8(_field, _offset, _mask, _shift)	\
189	do {	\
190		SPEX(_field[0], _offset +  0, _mask, _shift);	\
191		SPEX(_field[1], _offset +  2, _mask, _shift);	\
192		SPEX(_field[2], _offset +  4, _mask, _shift);	\
193		SPEX(_field[3], _offset +  6, _mask, _shift);	\
194		SPEX(_field[4], _offset +  8, _mask, _shift);	\
195		SPEX(_field[5], _offset + 10, _mask, _shift);	\
196		SPEX(_field[6], _offset + 12, _mask, _shift);	\
197		SPEX(_field[7], _offset + 14, _mask, _shift);	\
198	} while (0)
199
200static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
201{
202	u16 v, o;
203	int i;
204	u16 pwr_info_offset[] = {
205		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
206		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
207	};
208	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
209			ARRAY_SIZE(bus->sprom.core_pwr_info));
210
211	bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
212		SSB_SPROM_REVISION_REV;
213
214	for (i = 0; i < 3; i++) {
215		v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
216		*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
217	}
218
219	SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
220	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 */
454static 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 */
490static 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	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 */
534static 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
548int bcma_sprom_get(struct bcma_bus *bus)
549{
550	u16 offset = BCMA_CC_SPROM;
551	u16 *sprom;
552	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, };
553	int i, 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	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
583	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
584		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
585
586	bcma_debug(bus, "SPROM offset 0x%x\n", offset);
587	for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
588		size_t words = sprom_sizes[i];
589
590		sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
591		if (!sprom)
592			return -ENOMEM;
593
594		bcma_sprom_read(bus, offset, sprom, words);
595		err = bcma_sprom_valid(sprom, words);
596		if (!err)
597			break;
598
599		kfree(sprom);
600	}
601
602	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
603	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
604		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
605
606	if (err) {
607		bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
608		err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
609	} else {
610		bcma_sprom_extract_r8(bus, sprom);
611		kfree(sprom);
612	}
613
614	return err;
615}
616