drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / bcma / sprom.c
CommitLineData
27f18dc2
RM
1/*
2 * Broadcom specific AMBA
3 * SPROM reading
4 *
a027237a
HM
5 * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6 *
27f18dc2
RM
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
a027237a
HM
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{
4ac887cf 52 int err;
a027237a 53
4ac887cf
AS
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
3d9d8af3
RM
63 bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
64 bus->sprom.revision);
4ac887cf
AS
65 return 0;
66fail:
3d9d8af3 67 bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
4ac887cf 68 return err;
a027237a
HM
69}
70
27f18dc2
RM
71/**************************************************
72 * R/W ops.
73 **************************************************/
74
eb1577b7 75static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
27f18dc2
RM
76{
77 int i;
78 for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
79 sprom[i] = bcma_read16(bus->drv_cc.core,
eb1577b7 80 offset + (i * 2));
27f18dc2
RM
81}
82
83/**************************************************
84 * Validation.
85 **************************************************/
86
87static inline u8 bcma_crc8(u8 crc, u8 data)
88{
89 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
90 static const u8 t[] = {
91 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
92 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
93 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
94 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
95 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
96 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
97 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
98 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
99 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
100 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
101 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
102 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
103 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
104 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
105 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
106 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
107 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
108 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
109 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
110 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
111 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
112 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
113 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
114 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
115 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
116 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
117 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
118 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
119 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
120 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
121 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
122 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
123 };
124 return t[crc ^ data];
125}
126
127static u8 bcma_sprom_crc(const u16 *sprom)
128{
129 int word;
130 u8 crc = 0xFF;
131
132 for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
133 crc = bcma_crc8(crc, sprom[word] & 0x00FF);
134 crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
135 }
136 crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
137 crc ^= 0xFF;
138
139 return crc;
140}
141
142static int bcma_sprom_check_crc(const u16 *sprom)
143{
144 u8 crc;
145 u8 expected_crc;
146 u16 tmp;
147
148 crc = bcma_sprom_crc(sprom);
149 tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
150 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
151 if (crc != expected_crc)
152 return -EPROTO;
153
154 return 0;
155}
156
157static int bcma_sprom_valid(const u16 *sprom)
158{
159 u16 revision;
160 int err;
161
162 err = bcma_sprom_check_crc(sprom);
163 if (err)
164 return err;
165
166 revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
c54dcd19 167 if (revision != 8 && revision != 9) {
27f18dc2
RM
168 pr_err("Unsupported SPROM revision: %d\n", revision);
169 return -ENOENT;
170 }
171
172 return 0;
173}
174
175/**************************************************
176 * SPROM extraction.
177 **************************************************/
178
b35a9aca
RM
179#define SPOFF(offset) ((offset) / sizeof(u16))
180
181#define SPEX(_field, _offset, _mask, _shift) \
182 bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
183
432c4d1e
HM
184#define SPEX32(_field, _offset, _mask, _shift) \
185 bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
186 sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
187
e2da4bd3
HM
188#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
189 do { \
190 SPEX(_field[0], _offset + 0, _mask, _shift); \
191 SPEX(_field[1], _offset + 2, _mask, _shift); \
192 SPEX(_field[2], _offset + 4, _mask, _shift); \
193 SPEX(_field[3], _offset + 6, _mask, _shift); \
194 SPEX(_field[4], _offset + 8, _mask, _shift); \
195 SPEX(_field[5], _offset + 10, _mask, _shift); \
196 SPEX(_field[6], _offset + 12, _mask, _shift); \
197 SPEX(_field[7], _offset + 14, _mask, _shift); \
198 } while (0)
199
27f18dc2
RM
200static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
201{
507f9a71 202 u16 v, o;
27f18dc2 203 int i;
507f9a71
RM
204 u16 pwr_info_offset[] = {
205 SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
206 SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
207 };
208 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
209 ARRAY_SIZE(bus->sprom.core_pwr_info));
27f18dc2 210
daadc6b3
RM
211 bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
212 SSB_SPROM_REVISION_REV;
213
27f18dc2
RM
214 for (i = 0; i < 3; i++) {
215 v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
216 *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
217 }
d703a5ae 218
b35a9aca 219 SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
7b828f09 220 SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
b35a9aca
RM
221
222 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);
230
231 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);
239
240 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);
248
249 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);
257
258 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);
262
bf7d420b
HM
263 SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
264 SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
b35a9aca 265
507f9a71
RM
266 /* 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
b35a9aca
RM
298 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);
308
309 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);
432c4d1e
HM
319
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);
e2da4bd3
HM
391
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);
27f18dc2
RM
449}
450
10d8493c
AS
451/*
452 * Indicates the presence of external SPROM.
453 */
454static bool bcma_sprom_ext_available(struct bcma_bus *bus)
a027237a 455{
10d8493c
AS
456 u32 chip_status;
457 u32 srom_control;
458 u32 present_mask;
a027237a 459
10d8493c
AS
460 if (bus->drv_cc.core->id.rev >= 31) {
461 if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
462 return false;
a027237a 463
10d8493c
AS
464 srom_control = bcma_read32(bus->drv_cc.core,
465 BCMA_CC_SROM_CONTROL);
466 return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
a027237a 467 }
10d8493c
AS
468
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) {
4b4f5be2 472 case BCMA_CHIP_ID_BCM4313:
10d8493c
AS
473 present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
474 break;
475
4b4f5be2 476 case BCMA_CHIP_ID_BCM4331:
10d8493c
AS
477 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) {
4b4f5be2 498 case BCMA_CHIP_ID_BCM4313:
10d8493c
AS
499 present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
500 break;
501
4b4f5be2 502 case BCMA_CHIP_ID_BCM4331:
10d8493c
AS
503 present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
504 break;
505
4b4f5be2
HM
506 case BCMA_CHIP_ID_BCM43224:
507 case BCMA_CHIP_ID_BCM43225:
10d8493c
AS
508 /* for these chips OTP is always available */
509 present = true;
510 break;
646e0827 511 case BCMA_CHIP_ID_BCM43227:
c263c2c1 512 case BCMA_CHIP_ID_BCM43228:
646e0827 513 case BCMA_CHIP_ID_BCM43428:
c263c2c1
RM
514 present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
515 break;
10d8493c
AS
516 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);
a027237a
HM
547}
548
27f18dc2
RM
549int bcma_sprom_get(struct bcma_bus *bus)
550{
10d8493c 551 u16 offset = BCMA_CC_SPROM;
27f18dc2
RM
552 u16 *sprom;
553 int err = 0;
554
555 if (!bus->drv_cc.core)
556 return -EOPNOTSUPP;
557
10d8493c 558 if (!bcma_sprom_ext_available(bus)) {
32998cc9
HM
559 bool sprom_onchip;
560
a027237a 561 /*
10d8493c
AS
562 * External SPROM takes precedence so check
563 * on-chip OTP only when no external SPROM
564 * is present.
a027237a 565 */
32998cc9
HM
566 sprom_onchip = bcma_sprom_onchip_available(bus);
567 if (sprom_onchip) {
10d8493c
AS
568 /* determine offset */
569 offset = bcma_sprom_onchip_offset(bus);
570 }
32998cc9 571 if (!offset || !sprom_onchip) {
10d8493c
AS
572 /*
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 }
d6865dcc
HM
580 }
581
27f18dc2
RM
582 sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
583 GFP_KERNEL);
584 if (!sprom)
585 return -ENOMEM;
586
4b4f5be2
HM
587 if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
588 bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
984e5bef
RM
589 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
590
3d9d8af3 591 bcma_debug(bus, "SPROM offset 0x%x\n", offset);
eb1577b7 592 bcma_sprom_read(bus, offset, sprom);
27f18dc2 593
4b4f5be2
HM
594 if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
595 bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
984e5bef
RM
596 bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
597
27f18dc2 598 err = bcma_sprom_valid(sprom);
017c4c3b
HM
599 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);
27f18dc2 602 goto out;
017c4c3b 603 }
27f18dc2
RM
604
605 bcma_sprom_extract_r8(bus, sprom);
606
607out:
608 kfree(sprom);
609 return err;
610}