Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/bcma/sprom.c
26278 views
1
/*
2
* Broadcom specific AMBA
3
* SPROM reading
4
*
5
* Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
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
19
static 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 control 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
*/
39
int 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
49
static 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;
66
fail:
67
bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
68
return err;
69
}
70
71
/**************************************************
72
* R/W ops.
73
**************************************************/
74
75
static 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
87
static 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
127
static 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
142
static 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
157
static 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 > 11) {
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
204
static 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
221
static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
222
{
223
u16 v, o;
224
int i;
225
static const 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 core's power 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
*/
480
static 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
*/
516
static 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_BCM43131:
538
case BCMA_CHIP_ID_BCM43217:
539
case BCMA_CHIP_ID_BCM43227:
540
case BCMA_CHIP_ID_BCM43228:
541
case BCMA_CHIP_ID_BCM43428:
542
present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
543
break;
544
default:
545
present = false;
546
break;
547
}
548
549
if (present) {
550
otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
551
otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
552
}
553
554
return otpsize != 0;
555
}
556
557
/*
558
* Verify OTP is filled and determine the byte
559
* offset where SPROM data is located.
560
*
561
* On error, returns 0; byte offset otherwise.
562
*/
563
static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
564
{
565
struct bcma_device *cc = bus->drv_cc.core;
566
u32 offset;
567
568
/* verify OTP status */
569
if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
570
return 0;
571
572
/* obtain bit offset from otplayout register */
573
offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
574
return BCMA_CC_SPROM + (offset >> 3);
575
}
576
577
int bcma_sprom_get(struct bcma_bus *bus)
578
{
579
u16 offset = BCMA_CC_SPROM;
580
u16 *sprom;
581
static const size_t sprom_sizes[] = {
582
SSB_SPROMSIZE_WORDS_R4,
583
SSB_SPROMSIZE_WORDS_R10,
584
SSB_SPROMSIZE_WORDS_R11,
585
};
586
int i, err = 0;
587
588
if (!bus->drv_cc.core)
589
return -EOPNOTSUPP;
590
591
if (!bcma_sprom_ext_available(bus)) {
592
bool sprom_onchip;
593
594
/*
595
* External SPROM takes precedence so check
596
* on-chip OTP only when no external SPROM
597
* is present.
598
*/
599
sprom_onchip = bcma_sprom_onchip_available(bus);
600
if (sprom_onchip) {
601
/* determine offset */
602
offset = bcma_sprom_onchip_offset(bus);
603
}
604
if (!offset || !sprom_onchip) {
605
/*
606
* Maybe there is no SPROM on the device?
607
* Now we ask the arch code if there is some sprom
608
* available for this device in some other storage.
609
*/
610
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
611
return err;
612
}
613
}
614
615
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
616
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
617
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
618
619
bcma_debug(bus, "SPROM offset 0x%x\n", offset);
620
for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
621
size_t words = sprom_sizes[i];
622
623
sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
624
if (!sprom)
625
return -ENOMEM;
626
627
bcma_sprom_read(bus, offset, sprom, words);
628
err = bcma_sprom_valid(bus, sprom, words);
629
if (!err)
630
break;
631
632
kfree(sprom);
633
}
634
635
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
636
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
637
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
638
639
if (err) {
640
bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
641
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
642
} else {
643
bcma_sprom_extract_r8(bus, sprom);
644
kfree(sprom);
645
}
646
647
return err;
648
}
649
650