Root/drivers/bcma/sprom.c

1/*
2 * Broadcom specific AMBA
3 * SPROM reading
4 *
5 * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6 *
7 * Licensed under the GNU/GPL. See COPYING for details.
8 */
9
10#include "bcma_private.h"
11
12#include <linux/bcma/bcma.h>
13#include <linux/bcma/bcma_regs.h>
14#include <linux/pci.h>
15#include <linux/io.h>
16#include <linux/dma-mapping.h>
17#include <linux/slab.h>
18
19static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
20
21/**
22 * bcma_arch_register_fallback_sprom - Registers a method providing a
23 * fallback SPROM if no SPROM is found.
24 *
25 * @sprom_callback: The callback function.
26 *
27 * With this function the architecture implementation may register a
28 * callback handler which fills the SPROM data structure. The fallback is
29 * used for PCI based BCMA devices, where no valid SPROM can be found
30 * in the shadow registers and to provide the SPROM for SoCs where BCMA is
31 * to controll the system bus.
32 *
33 * This function is useful for weird architectures that have a half-assed
34 * BCMA device hardwired to their PCI bus.
35 *
36 * This function is available for architecture code, only. So it is not
37 * exported.
38 */
39int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
40                     struct ssb_sprom *out))
41{
42    if (get_fallback_sprom)
43        return -EEXIST;
44    get_fallback_sprom = sprom_callback;
45
46    return 0;
47}
48
49static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
50                     struct ssb_sprom *out)
51{
52    int err;
53
54    if (!get_fallback_sprom) {
55        err = -ENOENT;
56        goto fail;
57    }
58
59    err = get_fallback_sprom(bus, out);
60    if (err)
61        goto fail;
62
63    bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
64           bus->sprom.revision);
65    return 0;
66fail:
67    bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
68    return err;
69}
70
71/**************************************************
72 * R/W ops.
73 **************************************************/
74
75static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
76{
77    int i;
78    for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
79        sprom[i] = bcma_read16(bus->drv_cc.core,
80                       offset + (i * 2));
81}
82
83/**************************************************
84 * Validation.
85 **************************************************/
86
87static inline u8 bcma_crc8(u8 crc, u8 data)
88{
89    /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
90    static const u8 t[] = {
91        0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
92        0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
93        0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
94        0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
95        0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
96        0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
97        0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
98        0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
99        0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
100        0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
101        0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
102        0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
103        0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
104        0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
105        0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
106        0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
107        0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
108        0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
109        0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
110        0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
111        0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
112        0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
113        0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
114        0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
115        0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
116        0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
117        0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
118        0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
119        0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
120        0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
121        0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
122        0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
123    };
124    return t[crc ^ data];
125}
126
127static u8 bcma_sprom_crc(const u16 *sprom)
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;
167    if (revision != 8 && revision != 9) {
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
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
184#define SPEX32(_field, _offset, _mask, _shift) \
185    bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
186                sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
187
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
200static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
201{
202    u16 v, o;
203    int i;
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));
210
211    bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
212        SSB_SPROM_REVISION_REV;
213
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    }
218
219    SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
220
221    SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
222         SSB_SPROM4_TXPID2G0_SHIFT);
223    SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
224         SSB_SPROM4_TXPID2G1_SHIFT);
225    SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
226         SSB_SPROM4_TXPID2G2_SHIFT);
227    SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
228         SSB_SPROM4_TXPID2G3_SHIFT);
229
230    SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
231         SSB_SPROM4_TXPID5GL0_SHIFT);
232    SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
233         SSB_SPROM4_TXPID5GL1_SHIFT);
234    SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
235         SSB_SPROM4_TXPID5GL2_SHIFT);
236    SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
237         SSB_SPROM4_TXPID5GL3_SHIFT);
238
239    SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
240         SSB_SPROM4_TXPID5G0_SHIFT);
241    SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
242         SSB_SPROM4_TXPID5G1_SHIFT);
243    SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
244         SSB_SPROM4_TXPID5G2_SHIFT);
245    SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
246         SSB_SPROM4_TXPID5G3_SHIFT);
247
248    SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
249         SSB_SPROM4_TXPID5GH0_SHIFT);
250    SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
251         SSB_SPROM4_TXPID5GH1_SHIFT);
252    SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
253         SSB_SPROM4_TXPID5GH2_SHIFT);
254    SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
255         SSB_SPROM4_TXPID5GH3_SHIFT);
256
257    SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
258    SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
259    SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
260    SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
261
262    SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
263    SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
264
265    /* Extract cores power info info */
266    for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
267        o = pwr_info_offset[i];
268        SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
269            SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
270        SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
271            SSB_SPROM8_2G_MAXP, 0);
272
273        SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
274        SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
275        SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
276
277        SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
278            SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
279        SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
280            SSB_SPROM8_5G_MAXP, 0);
281        SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
282            SSB_SPROM8_5GH_MAXP, 0);
283        SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
284            SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
285
286        SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
287        SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
288        SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
289        SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
290        SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
291        SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
292        SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
293        SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
294        SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
295    }
296
297    SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
298         SSB_SROM8_FEM_TSSIPOS_SHIFT);
299    SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
300         SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
301    SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
302         SSB_SROM8_FEM_PDET_RANGE_SHIFT);
303    SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
304         SSB_SROM8_FEM_TR_ISO_SHIFT);
305    SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
306         SSB_SROM8_FEM_ANTSWLUT_SHIFT);
307
308    SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
309         SSB_SROM8_FEM_TSSIPOS_SHIFT);
310    SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
311         SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
312    SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
313         SSB_SROM8_FEM_PDET_RANGE_SHIFT);
314    SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
315         SSB_SROM8_FEM_TR_ISO_SHIFT);
316    SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
317         SSB_SROM8_FEM_ANTSWLUT_SHIFT);
318
319    SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
320         SSB_SPROM8_ANTAVAIL_A_SHIFT);
321    SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
322         SSB_SPROM8_ANTAVAIL_BG_SHIFT);
323    SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
324    SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
325         SSB_SPROM8_ITSSI_BG_SHIFT);
326    SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
327    SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
328         SSB_SPROM8_ITSSI_A_SHIFT);
329    SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
330    SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
331         SSB_SPROM8_MAXP_AL_SHIFT);
332    SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
333    SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
334         SSB_SPROM8_GPIOA_P1_SHIFT);
335    SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
336    SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
337         SSB_SPROM8_GPIOB_P3_SHIFT);
338    SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
339    SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
340         SSB_SPROM8_TRI5G_SHIFT);
341    SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
342    SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
343         SSB_SPROM8_TRI5GH_SHIFT);
344    SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
345         SSB_SPROM8_RXPO2G_SHIFT);
346    SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
347         SSB_SPROM8_RXPO5G_SHIFT);
348    SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
349    SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
350         SSB_SPROM8_RSSISMC2G_SHIFT);
351    SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
352         SSB_SPROM8_RSSISAV2G_SHIFT);
353    SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
354         SSB_SPROM8_BXA2G_SHIFT);
355    SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
356    SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
357         SSB_SPROM8_RSSISMC5G_SHIFT);
358    SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
359         SSB_SPROM8_RSSISAV5G_SHIFT);
360    SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
361         SSB_SPROM8_BXA5G_SHIFT);
362
363    SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
364    SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
365    SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
366    SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
367    SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
368    SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
369    SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
370    SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
371    SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
372    SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
373    SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
374    SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
375    SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
376    SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
377    SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
378    SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
379    SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
380
381    /* Extract the antenna gain values. */
382    SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
383         SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
384    SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
385         SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
386    SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
387         SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
388    SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
389         SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
390
391    SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
392         SSB_SPROM8_LEDDC_ON_SHIFT);
393    SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
394         SSB_SPROM8_LEDDC_OFF_SHIFT);
395
396    SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
397         SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
398    SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
399         SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
400    SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
401         SSB_SPROM8_TXRXC_SWITCH_SHIFT);
402
403    SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
404
405    SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
406    SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
407    SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
408    SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
409
410    SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
411         SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
412    SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
413         SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
414    SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
415         SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
416         SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
417    SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
418         SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
419    SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
420         SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
421         SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
422    SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
423         SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
424         SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
425    SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
426         SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
427         SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
428    SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
429         SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
430
431    SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
432    SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
433    SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
434    SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
435
436    SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
437         SSB_SPROM8_THERMAL_TRESH_SHIFT);
438    SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
439         SSB_SPROM8_THERMAL_OFFSET_SHIFT);
440    SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
441         SSB_SPROM8_TEMPDELTA_PHYCAL,
442         SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
443    SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
444         SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
445    SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
446         SSB_SPROM8_TEMPDELTA_HYSTERESIS,
447         SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
448}
449
450/*
451 * Indicates the presence of external SPROM.
452 */
453static bool bcma_sprom_ext_available(struct bcma_bus *bus)
454{
455    u32 chip_status;
456    u32 srom_control;
457    u32 present_mask;
458
459    if (bus->drv_cc.core->id.rev >= 31) {
460        if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
461            return false;
462
463        srom_control = bcma_read32(bus->drv_cc.core,
464                       BCMA_CC_SROM_CONTROL);
465        return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
466    }
467
468    /* older chipcommon revisions use chip status register */
469    chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
470    switch (bus->chipinfo.id) {
471    case BCMA_CHIP_ID_BCM4313:
472        present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
473        break;
474
475    case BCMA_CHIP_ID_BCM4331:
476        present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
477        break;
478
479    default:
480        return true;
481    }
482
483    return chip_status & present_mask;
484}
485
486/*
487 * Indicates that on-chip OTP memory is present and enabled.
488 */
489static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
490{
491    u32 chip_status;
492    u32 otpsize = 0;
493    bool present;
494
495    chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
496    switch (bus->chipinfo.id) {
497    case BCMA_CHIP_ID_BCM4313:
498        present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
499        break;
500
501    case BCMA_CHIP_ID_BCM4331:
502        present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
503        break;
504
505    case BCMA_CHIP_ID_BCM43224:
506    case BCMA_CHIP_ID_BCM43225:
507        /* for these chips OTP is always available */
508        present = true;
509        break;
510    case BCMA_CHIP_ID_BCM43227:
511    case BCMA_CHIP_ID_BCM43228:
512    case BCMA_CHIP_ID_BCM43428:
513        present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
514        break;
515    default:
516        present = false;
517        break;
518    }
519
520    if (present) {
521        otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
522        otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
523    }
524
525    return otpsize != 0;
526}
527
528/*
529 * Verify OTP is filled and determine the byte
530 * offset where SPROM data is located.
531 *
532 * On error, returns 0; byte offset otherwise.
533 */
534static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
535{
536    struct bcma_device *cc = bus->drv_cc.core;
537    u32 offset;
538
539    /* verify OTP status */
540    if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
541        return 0;
542
543    /* obtain bit offset from otplayout register */
544    offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
545    return BCMA_CC_SPROM + (offset >> 3);
546}
547
548int bcma_sprom_get(struct bcma_bus *bus)
549{
550    u16 offset = BCMA_CC_SPROM;
551    u16 *sprom;
552    int err = 0;
553
554    if (!bus->drv_cc.core)
555        return -EOPNOTSUPP;
556
557    if (!bcma_sprom_ext_available(bus)) {
558        bool sprom_onchip;
559
560        /*
561         * External SPROM takes precedence so check
562         * on-chip OTP only when no external SPROM
563         * is present.
564         */
565        sprom_onchip = bcma_sprom_onchip_available(bus);
566        if (sprom_onchip) {
567            /* determine offset */
568            offset = bcma_sprom_onchip_offset(bus);
569        }
570        if (!offset || !sprom_onchip) {
571            /*
572             * Maybe there is no SPROM on the device?
573             * Now we ask the arch code if there is some sprom
574             * available for this device in some other storage.
575             */
576            err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
577            return err;
578        }
579    }
580
581    sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
582            GFP_KERNEL);
583    if (!sprom)
584        return -ENOMEM;
585
586    if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
587        bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
588        bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
589
590    bcma_debug(bus, "SPROM offset 0x%x\n", offset);
591    bcma_sprom_read(bus, offset, sprom);
592
593    if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
594        bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
595        bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
596
597    err = bcma_sprom_valid(sprom);
598    if (err) {
599        bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
600        err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
601        goto out;
602    }
603
604    bcma_sprom_extract_r8(bus, sprom);
605
606out:
607    kfree(sprom);
608    return err;
609}
610

Archive Download this file



interactive