sprom.c revision 3d9d8af330a891f141db420115238f01e4c6ece7
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{
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
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)
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
142static 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
157static 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
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
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 */
453static 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 */
489static 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
511	default:
512		present = false;
513		break;
514	}
515
516	if (present) {
517		otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
518		otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
519	}
520
521	return otpsize != 0;
522}
523
524/*
525 * Verify OTP is filled and determine the byte
526 * offset where SPROM data is located.
527 *
528 * On error, returns 0; byte offset otherwise.
529 */
530static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
531{
532	struct bcma_device *cc = bus->drv_cc.core;
533	u32 offset;
534
535	/* verify OTP status */
536	if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
537		return 0;
538
539	/* obtain bit offset from otplayout register */
540	offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
541	return BCMA_CC_SPROM + (offset >> 3);
542}
543
544int bcma_sprom_get(struct bcma_bus *bus)
545{
546	u16 offset = BCMA_CC_SPROM;
547	u16 *sprom;
548	int err = 0;
549
550	if (!bus->drv_cc.core)
551		return -EOPNOTSUPP;
552
553	if (!bcma_sprom_ext_available(bus)) {
554		bool sprom_onchip;
555
556		/*
557		 * External SPROM takes precedence so check
558		 * on-chip OTP only when no external SPROM
559		 * is present.
560		 */
561		sprom_onchip = bcma_sprom_onchip_available(bus);
562		if (sprom_onchip) {
563			/* determine offset */
564			offset = bcma_sprom_onchip_offset(bus);
565		}
566		if (!offset || !sprom_onchip) {
567			/*
568			 * Maybe there is no SPROM on the device?
569			 * Now we ask the arch code if there is some sprom
570			 * available for this device in some other storage.
571			 */
572			err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
573			return err;
574		}
575	}
576
577	sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
578			GFP_KERNEL);
579	if (!sprom)
580		return -ENOMEM;
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	bcma_sprom_read(bus, offset, sprom);
588
589	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
590	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
591		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
592
593	err = bcma_sprom_valid(sprom);
594	if (err)
595		goto out;
596
597	bcma_sprom_extract_r8(bus, sprom);
598
599out:
600	kfree(sprom);
601	return err;
602}
603