blob: 72bf4540f5658425b4836303d8ed6d95b43a6702 [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łecki5179ed72013-05-13 22:07:51 +020075static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
76 size_t words)
Rafał Miłecki27f18dc2011-06-02 02:08:51 +020077{
78 int i;
Rafał Miłecki5179ed72013-05-13 22:07:51 +020079 for (i = 0; i < words; i++)
80 sprom[i] = bcma_read16(bus->drv_cc.core, 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
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200127static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200128{
129 int word;
130 u8 crc = 0xFF;
131
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200132 for (word = 0; word < words - 1; word++) {
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200133 crc = bcma_crc8(crc, sprom[word] & 0x00FF);
134 crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
135 }
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200136 crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200137 crc ^= 0xFF;
138
139 return crc;
140}
141
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200142static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200143{
144 u8 crc;
145 u8 expected_crc;
146 u16 tmp;
147
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200148 crc = bcma_sprom_crc(sprom, words);
149 tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200150 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
151 if (crc != expected_crc)
152 return -EPROTO;
153
154 return 0;
155}
156
Rafał Miłecki78e578c2013-05-13 22:07:53 +0200157static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
158 size_t words)
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200159{
160 u16 revision;
161 int err;
162
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200163 err = bcma_sprom_check_crc(sprom, words);
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200164 if (err)
165 return err;
166
Rafał Miłecki5179ed72013-05-13 22:07:51 +0200167 revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
Rafał Miłecki78e578c2013-05-13 22:07:53 +0200168 if (revision != 8 && revision != 9 && revision != 10) {
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200169 pr_err("Unsupported SPROM revision: %d\n", revision);
170 return -ENOENT;
171 }
172
Rafał Miłecki78e578c2013-05-13 22:07:53 +0200173 bus->sprom.revision = revision;
174 bcma_debug(bus, "Found SPROM revision %d\n", revision);
175
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200176 return 0;
177}
178
179/**************************************************
180 * SPROM extraction.
181 **************************************************/
182
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100183#define SPOFF(offset) ((offset) / sizeof(u16))
184
185#define SPEX(_field, _offset, _mask, _shift) \
186 bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
187
Hauke Mehrtens432c4d12012-04-29 02:04:12 +0200188#define SPEX32(_field, _offset, _mask, _shift) \
189 bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
190 sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
191
Hauke Mehrtense2da4bd2012-04-29 02:04:13 +0200192#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
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200204static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
205{
Rafał Miłecki507f9a72012-01-02 08:41:25 +0100206 u16 v, o;
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200207 int i;
Rafał Miłecki507f9a72012-01-02 08:41:25 +0100208 u16 pwr_info_offset[] = {
209 SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
210 SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
211 };
212 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
213 ARRAY_SIZE(bus->sprom.core_pwr_info));
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200214
215 for (i = 0; i < 3; i++) {
216 v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
217 *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
218 }
Rafał Miłeckid703a5a2011-08-28 18:47:23 +0200219
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100220 SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
Rafał Miłecki7b828f02013-03-19 13:18:44 +0100221 SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
Rafał Miłeckid703a5a2011-08-28 18:47:23 +0200222
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100223 SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
224 SSB_SPROM4_TXPID2G0_SHIFT);
225 SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
226 SSB_SPROM4_TXPID2G1_SHIFT);
227 SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
228 SSB_SPROM4_TXPID2G2_SHIFT);
229 SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
230 SSB_SPROM4_TXPID2G3_SHIFT);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100231
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100232 SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
233 SSB_SPROM4_TXPID5GL0_SHIFT);
234 SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
235 SSB_SPROM4_TXPID5GL1_SHIFT);
236 SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
237 SSB_SPROM4_TXPID5GL2_SHIFT);
238 SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
239 SSB_SPROM4_TXPID5GL3_SHIFT);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100240
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100241 SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
242 SSB_SPROM4_TXPID5G0_SHIFT);
243 SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
244 SSB_SPROM4_TXPID5G1_SHIFT);
245 SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
246 SSB_SPROM4_TXPID5G2_SHIFT);
247 SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
248 SSB_SPROM4_TXPID5G3_SHIFT);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100249
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100250 SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
251 SSB_SPROM4_TXPID5GH0_SHIFT);
252 SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
253 SSB_SPROM4_TXPID5GH1_SHIFT);
254 SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
255 SSB_SPROM4_TXPID5GH2_SHIFT);
256 SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
257 SSB_SPROM4_TXPID5GH3_SHIFT);
Rafał Miłeckidaadc6b2011-12-12 21:33:12 +0100258
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100259 SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
260 SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
261 SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
262 SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
Rafał Miłeckid703a5a2011-08-28 18:47:23 +0200263
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200264 SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
265 SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
Rafał Miłeckiaee5ed52011-12-08 18:02:22 +0100266
Rafał Miłecki507f9a72012-01-02 08:41:25 +0100267 /* Extract cores power info info */
268 for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
269 o = pwr_info_offset[i];
270 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
271 SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
272 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
273 SSB_SPROM8_2G_MAXP, 0);
274
275 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
276 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
277 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
278
279 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
280 SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
281 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
282 SSB_SPROM8_5G_MAXP, 0);
283 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
284 SSB_SPROM8_5GH_MAXP, 0);
285 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
286 SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
287
288 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
289 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
290 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
291 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
292 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
293 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
294 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
295 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
296 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
297 }
298
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100299 SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
300 SSB_SROM8_FEM_TSSIPOS_SHIFT);
301 SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
302 SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
303 SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
304 SSB_SROM8_FEM_PDET_RANGE_SHIFT);
305 SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
306 SSB_SROM8_FEM_TR_ISO_SHIFT);
307 SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
308 SSB_SROM8_FEM_ANTSWLUT_SHIFT);
Rafał Miłeckiaee5ed52011-12-08 18:02:22 +0100309
Rafał Miłeckib35a9ac2012-01-02 08:41:24 +0100310 SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
311 SSB_SROM8_FEM_TSSIPOS_SHIFT);
312 SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
313 SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
314 SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
315 SSB_SROM8_FEM_PDET_RANGE_SHIFT);
316 SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
317 SSB_SROM8_FEM_TR_ISO_SHIFT);
318 SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
319 SSB_SROM8_FEM_ANTSWLUT_SHIFT);
Hauke Mehrtens432c4d12012-04-29 02:04:12 +0200320
321 SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
322 SSB_SPROM8_ANTAVAIL_A_SHIFT);
323 SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
324 SSB_SPROM8_ANTAVAIL_BG_SHIFT);
325 SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
326 SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
327 SSB_SPROM8_ITSSI_BG_SHIFT);
328 SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
329 SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
330 SSB_SPROM8_ITSSI_A_SHIFT);
331 SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
332 SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
333 SSB_SPROM8_MAXP_AL_SHIFT);
334 SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
335 SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
336 SSB_SPROM8_GPIOA_P1_SHIFT);
337 SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
338 SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
339 SSB_SPROM8_GPIOB_P3_SHIFT);
340 SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
341 SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
342 SSB_SPROM8_TRI5G_SHIFT);
343 SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
344 SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
345 SSB_SPROM8_TRI5GH_SHIFT);
346 SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
347 SSB_SPROM8_RXPO2G_SHIFT);
348 SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
349 SSB_SPROM8_RXPO5G_SHIFT);
350 SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
351 SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
352 SSB_SPROM8_RSSISMC2G_SHIFT);
353 SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
354 SSB_SPROM8_RSSISAV2G_SHIFT);
355 SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
356 SSB_SPROM8_BXA2G_SHIFT);
357 SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
358 SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
359 SSB_SPROM8_RSSISMC5G_SHIFT);
360 SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
361 SSB_SPROM8_RSSISAV5G_SHIFT);
362 SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
363 SSB_SPROM8_BXA5G_SHIFT);
364
365 SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
366 SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
367 SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
368 SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
369 SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
370 SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
371 SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
372 SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
373 SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
374 SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
375 SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
376 SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
377 SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
378 SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
379 SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
380 SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
381 SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
382
383 /* Extract the antenna gain values. */
384 SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
385 SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
386 SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
387 SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
388 SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
389 SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
390 SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
391 SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
Hauke Mehrtense2da4bd2012-04-29 02:04:13 +0200392
393 SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
394 SSB_SPROM8_LEDDC_ON_SHIFT);
395 SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
396 SSB_SPROM8_LEDDC_OFF_SHIFT);
397
398 SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
399 SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
400 SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
401 SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
402 SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
403 SSB_SPROM8_TXRXC_SWITCH_SHIFT);
404
405 SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
406
407 SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
408 SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
409 SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
410 SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
411
412 SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
413 SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
414 SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
415 SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
416 SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
417 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
418 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
419 SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
420 SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
421 SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
422 SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
423 SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
424 SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
425 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
426 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
427 SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
428 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
429 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
430 SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
431 SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
432
433 SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
434 SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
435 SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
436 SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
437
438 SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
439 SSB_SPROM8_THERMAL_TRESH_SHIFT);
440 SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
441 SSB_SPROM8_THERMAL_OFFSET_SHIFT);
442 SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
443 SSB_SPROM8_TEMPDELTA_PHYCAL,
444 SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
445 SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
446 SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
447 SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
448 SSB_SPROM8_TEMPDELTA_HYSTERESIS,
449 SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200450}
451
Arend van Spriel10d84932012-03-06 15:50:48 +0100452/*
453 * Indicates the presence of external SPROM.
454 */
455static bool bcma_sprom_ext_available(struct bcma_bus *bus)
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100456{
Arend van Spriel10d84932012-03-06 15:50:48 +0100457 u32 chip_status;
458 u32 srom_control;
459 u32 present_mask;
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100460
Arend van Spriel10d84932012-03-06 15:50:48 +0100461 if (bus->drv_cc.core->id.rev >= 31) {
462 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
463 return false;
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100464
Arend van Spriel10d84932012-03-06 15:50:48 +0100465 srom_control = bcma_read32(bus->drv_cc.core,
466 BCMA_CC_SROM_CONTROL);
467 return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100468 }
Arend van Spriel10d84932012-03-06 15:50:48 +0100469
470 /* older chipcommon revisions use chip status register */
471 chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
472 switch (bus->chipinfo.id) {
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200473 case BCMA_CHIP_ID_BCM4313:
Arend van Spriel10d84932012-03-06 15:50:48 +0100474 present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
475 break;
476
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200477 case BCMA_CHIP_ID_BCM4331:
Arend van Spriel10d84932012-03-06 15:50:48 +0100478 present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
479 break;
480
481 default:
482 return true;
483 }
484
485 return chip_status & present_mask;
486}
487
488/*
489 * Indicates that on-chip OTP memory is present and enabled.
490 */
491static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
492{
493 u32 chip_status;
494 u32 otpsize = 0;
495 bool present;
496
497 chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
498 switch (bus->chipinfo.id) {
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200499 case BCMA_CHIP_ID_BCM4313:
Arend van Spriel10d84932012-03-06 15:50:48 +0100500 present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
501 break;
502
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200503 case BCMA_CHIP_ID_BCM4331:
Arend van Spriel10d84932012-03-06 15:50:48 +0100504 present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
505 break;
Rafał Miłecki88f9b652013-06-26 10:02:11 +0200506 case BCMA_CHIP_ID_BCM43142:
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200507 case BCMA_CHIP_ID_BCM43224:
508 case BCMA_CHIP_ID_BCM43225:
Arend van Spriel10d84932012-03-06 15:50:48 +0100509 /* for these chips OTP is always available */
510 present = true;
511 break;
Rafał Miłecki646e0822012-09-21 08:38:38 +0200512 case BCMA_CHIP_ID_BCM43227:
Rafał Miłeckic263c2c2012-07-23 18:20:12 +0200513 case BCMA_CHIP_ID_BCM43228:
Rafał Miłecki646e0822012-09-21 08:38:38 +0200514 case BCMA_CHIP_ID_BCM43428:
Rafał Miłeckic263c2c2012-07-23 18:20:12 +0200515 present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
516 break;
Arend van Spriel10d84932012-03-06 15:50:48 +0100517 default:
518 present = false;
519 break;
520 }
521
522 if (present) {
523 otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
524 otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
525 }
526
527 return otpsize != 0;
528}
529
530/*
531 * Verify OTP is filled and determine the byte
532 * offset where SPROM data is located.
533 *
534 * On error, returns 0; byte offset otherwise.
535 */
536static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
537{
538 struct bcma_device *cc = bus->drv_cc.core;
539 u32 offset;
540
541 /* verify OTP status */
542 if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
543 return 0;
544
545 /* obtain bit offset from otplayout register */
546 offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
547 return BCMA_CC_SPROM + (offset >> 3);
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100548}
549
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200550int bcma_sprom_get(struct bcma_bus *bus)
551{
Arend van Spriel10d84932012-03-06 15:50:48 +0100552 u16 offset = BCMA_CC_SPROM;
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200553 u16 *sprom;
Rafał Miłecki78e578c2013-05-13 22:07:53 +0200554 size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
555 SSB_SPROMSIZE_WORDS_R10, };
Rafał Miłecki92eb1642013-05-13 22:07:52 +0200556 int i, err = 0;
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200557
558 if (!bus->drv_cc.core)
559 return -EOPNOTSUPP;
560
Arend van Spriel10d84932012-03-06 15:50:48 +0100561 if (!bcma_sprom_ext_available(bus)) {
Hauke Mehrtens32998cc2012-04-14 14:38:54 +0200562 bool sprom_onchip;
563
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100564 /*
Arend van Spriel10d84932012-03-06 15:50:48 +0100565 * External SPROM takes precedence so check
566 * on-chip OTP only when no external SPROM
567 * is present.
Hauke Mehrtensa0272372012-02-28 00:56:10 +0100568 */
Hauke Mehrtens32998cc2012-04-14 14:38:54 +0200569 sprom_onchip = bcma_sprom_onchip_available(bus);
570 if (sprom_onchip) {
Arend van Spriel10d84932012-03-06 15:50:48 +0100571 /* determine offset */
572 offset = bcma_sprom_onchip_offset(bus);
573 }
Hauke Mehrtens32998cc2012-04-14 14:38:54 +0200574 if (!offset || !sprom_onchip) {
Arend van Spriel10d84932012-03-06 15:50:48 +0100575 /*
576 * Maybe there is no SPROM on the device?
577 * Now we ask the arch code if there is some sprom
578 * available for this device in some other storage.
579 */
580 err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
581 return err;
582 }
Hauke Mehrtensd6865dcc2012-01-31 00:03:37 +0100583 }
584
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200585 if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
586 bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
Rafał Miłecki984e5be2011-08-11 23:46:44 +0200587 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
588
Rafał Miłecki3d9d8af2012-07-05 22:07:32 +0200589 bcma_debug(bus, "SPROM offset 0x%x\n", offset);
Rafał Miłecki92eb1642013-05-13 22:07:52 +0200590 for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
591 size_t words = sprom_sizes[i];
592
593 sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
594 if (!sprom)
595 return -ENOMEM;
596
597 bcma_sprom_read(bus, offset, sprom, words);
Rafał Miłecki78e578c2013-05-13 22:07:53 +0200598 err = bcma_sprom_valid(bus, sprom, words);
Rafał Miłecki92eb1642013-05-13 22:07:52 +0200599 if (!err)
600 break;
601
602 kfree(sprom);
603 }
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200604
Hauke Mehrtens4b4f5be2012-06-30 01:44:38 +0200605 if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
606 bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
Rafał Miłecki984e5be2011-08-11 23:46:44 +0200607 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
608
Hauke Mehrtens017c4c32012-09-29 20:38:11 +0200609 if (err) {
Rafał Miłecki92eb1642013-05-13 22:07:52 +0200610 bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
Hauke Mehrtens017c4c32012-09-29 20:38:11 +0200611 err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
Rafał Miłecki92eb1642013-05-13 22:07:52 +0200612 } else {
613 bcma_sprom_extract_r8(bus, sprom);
614 kfree(sprom);
Hauke Mehrtens017c4c32012-09-29 20:38:11 +0200615 }
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200616
Rafał Miłecki27f18dc2011-06-02 02:08:51 +0200617 return err;
618}