blob: 8934298a638dfdbfb6d2e5e4fa6e43cb65aeac8b [file] [log] [blame]
Rafał Miłecki27f18dc2011-06-02 02:08:51 +02001/*
2 * Broadcom specific AMBA
3 * SPROM reading
4 *
Hauke Mehrtensa0272372012-02-28 00:56:10 +01005 * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6 *
Rafał Miłecki27f18dc2011-06-02 02:08:51 +02007 * 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
Hauke Mehrtensa0272372012-02-28 00:56:10 +010019static 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{
Arend van Spriel4ac887c2012-03-06 15:50:47 +010052 int err;
Hauke Mehrtensa0272372012-02-28 00:56:10 +010053
Arend van Spriel4ac887c2012-03-06 15:50:47 +010054 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
Rafał Miłecki3d9d8af2012-07-05 22:07:32 +020063 bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
64 bus->sprom.revision);
Arend van Spriel4ac887c2012-03-06 15:50:47 +010065 return 0;
66fail:
Rafał Miłecki3d9d8af2012-07-05 22:07:32 +020067 bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
Arend van Spriel4ac887c2012-03-06 15:50:47 +010068 return err;
Hauke Mehrtensa0272372012-02-28 00:56:10 +010069}
70
Rafał Miłecki27f18dc2011-06-02 02:08:51 +020071/**************************************************
72 * R/W ops.
73 **************************************************/
74
Rafał Miłeckieb1577b2011-07-17 11:00:59 +020075static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
Rafał Miłecki27f18dc2011-06-02 02:08:51 +020076{
77 int i;
78 for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
79 sprom[i] = bcma_read16(bus->drv_cc.core,
Rafał Miłeckieb1577b2011-07-17 11:00:59 +020080 offset + (i * 2));
Rafał Miłecki27f18dc2011-06-02 02:08:51 +020081}
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;
Rafał Miłeckic54dcd12011-07-14 21:49:21 +0200167 if (revision != 8 && revision != 9) {
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200168 pr_err("Unsupported SPROM revision: %d\n", revision);
169 return -ENOENT;
170 }
171
172 return 0;
173}
174
175/**************************************************
176 * SPROM extraction.
177 **************************************************/
178
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100179#define SPOFF(offset) ((offset) / sizeof(u16))
180
181#define SPEX(_field, _offset, _mask, _shift) \
182 bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
183
Hauke Mehrtens432c4d12012-04-29 02:04:12 +0200184#define SPEX32(_field, _offset, _mask, _shift) \
185 bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
186 sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
187
Hauke Mehrtense2da4bd2012-04-29 02:04:13 +0200188#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
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200200static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
201{
Rafał Miłecki507f9a72012-01-02 08:41:25 +0100202 u16 v, o;
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200203 int i;
Rafał Miłecki507f9a72012-01-02 08:41:25 +0100204 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));
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200210
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100211 bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
212 SSB_SPROM_REVISION_REV;
213
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200214 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 }
Rafał Miłeckid703a5a2011-08-28 18:47:23 +0200218
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100219 SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
Rafał Miłecki7b828f02013-03-19 13:18:44 +0100220 SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
Rafał Miłeckid703a5a2011-08-28 18:47:23 +0200221
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100222 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);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100230
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100231 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);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100239
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100240 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);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100248
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100249 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);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100257
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100258 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);
Rafał Miłeckid703a5a2011-08-28 18:47:23 +0200262
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200263 SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
264 SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
Rafał Miłeckiaee5ed52011-12-08 18:02:22 +0100265
Rafał Miłecki507f9a72012-01-02 08:41:25 +0100266 /* 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
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100298 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);
Rafał Miłeckiaee5ed52011-12-08 18:02:22 +0100308
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100309 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);
Hauke Mehrtens432c4d12012-04-29 02:04:12 +0200319
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);
Hauke Mehrtense2da4bd2012-04-29 02:04:13 +0200391
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);
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200449}
450
Arend van Spriel10d84932012-03-06 15:50:48 +0100451/*
452 * Indicates the presence of external SPROM.
453 */
454static bool bcma_sprom_ext_available(struct bcma_bus *bus)
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100455{
Arend van Spriel10d84932012-03-06 15:50:48 +0100456 u32 chip_status;
457 u32 srom_control;
458 u32 present_mask;
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100459
Arend van Spriel10d84932012-03-06 15:50:48 +0100460 if (bus->drv_cc.core->id.rev >= 31) {
461 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
462 return false;
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100463
Arend van Spriel10d84932012-03-06 15:50:48 +0100464 srom_control = bcma_read32(bus->drv_cc.core,
465 BCMA_CC_SROM_CONTROL);
466 return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100467 }
Arend van Spriel10d84932012-03-06 15:50:48 +0100468
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) {
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200472 case BCMA_CHIP_ID_BCM4313:
Arend van Spriel10d84932012-03-06 15:50:48 +0100473 present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
474 break;
475
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200476 case BCMA_CHIP_ID_BCM4331:
Arend van Spriel10d84932012-03-06 15:50:48 +0100477 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) {
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200498 case BCMA_CHIP_ID_BCM4313:
Arend van Spriel10d84932012-03-06 15:50:48 +0100499 present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
500 break;
501
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200502 case BCMA_CHIP_ID_BCM4331:
Arend van Spriel10d84932012-03-06 15:50:48 +0100503 present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
504 break;
505
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200506 case BCMA_CHIP_ID_BCM43224:
507 case BCMA_CHIP_ID_BCM43225:
Arend van Spriel10d84932012-03-06 15:50:48 +0100508 /* for these chips OTP is always available */
509 present = true;
510 break;
Rafał Miłecki646e0822012-09-21 08:38:38 +0200511 case BCMA_CHIP_ID_BCM43227:
Rafał Miłeckic263c2c2012-07-23 18:20:12 +0200512 case BCMA_CHIP_ID_BCM43228:
Rafał Miłecki646e0822012-09-21 08:38:38 +0200513 case BCMA_CHIP_ID_BCM43428:
Rafał Miłeckic263c2c2012-07-23 18:20:12 +0200514 present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
515 break;
Arend van Spriel10d84932012-03-06 15:50:48 +0100516 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 */
535static 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);
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100547}
548
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200549int bcma_sprom_get(struct bcma_bus *bus)
550{
Arend van Spriel10d84932012-03-06 15:50:48 +0100551 u16 offset = BCMA_CC_SPROM;
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200552 u16 *sprom;
553 int err = 0;
554
555 if (!bus->drv_cc.core)
556 return -EOPNOTSUPP;
557
Arend van Spriel10d84932012-03-06 15:50:48 +0100558 if (!bcma_sprom_ext_available(bus)) {
Hauke Mehrtens32998cc2012-04-14 14:38:54 +0200559 bool sprom_onchip;
560
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100561 /*
Arend van Spriel10d84932012-03-06 15:50:48 +0100562 * External SPROM takes precedence so check
563 * on-chip OTP only when no external SPROM
564 * is present.
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100565 */
Hauke Mehrtens32998cc2012-04-14 14:38:54 +0200566 sprom_onchip = bcma_sprom_onchip_available(bus);
567 if (sprom_onchip) {
Arend van Spriel10d84932012-03-06 15:50:48 +0100568 /* determine offset */
569 offset = bcma_sprom_onchip_offset(bus);
570 }
Hauke Mehrtens32998cc2012-04-14 14:38:54 +0200571 if (!offset || !sprom_onchip) {
Arend van Spriel10d84932012-03-06 15:50:48 +0100572 /*
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 }
Hauke Mehrtensd6865dcc2012-01-31 00:03:37 +0100580 }
581
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200582 sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
583 GFP_KERNEL);
584 if (!sprom)
585 return -ENOMEM;
586
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200587 if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
588 bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
Rafał Miłecki984e5be2011-08-11 23:46:44 +0200589 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
590
Rafał Miłecki3d9d8af2012-07-05 22:07:32 +0200591 bcma_debug(bus, "SPROM offset 0x%x\n", offset);
Rafał Miłeckieb1577b2011-07-17 11:00:59 +0200592 bcma_sprom_read(bus, offset, sprom);
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200593
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200594 if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
595 bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
Rafał Miłecki984e5be2011-08-11 23:46:44 +0200596 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
597
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200598 err = bcma_sprom_valid(sprom);
Hauke Mehrtens017c4c32012-09-29 20:38:11 +0200599 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);
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200602 goto out;
Hauke Mehrtens017c4c32012-09-29 20:38:11 +0200603 }
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200604
605 bcma_sprom_extract_r8(bus, sprom);
606
607out:
608 kfree(sprom);
609 return err;
610}