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