Root/drivers/ssb/pci.c

1/*
2 * Sonics Silicon Backplane PCI-Hostbus related functions.
3 *
4 * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
5 * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
6 * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
7 * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
8 * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
9 *
10 * Derived from the Broadcom 4400 device driver.
11 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
12 * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
13 * Copyright (C) 2006 Broadcom Corporation.
14 *
15 * Licensed under the GNU/GPL. See COPYING for details.
16 */
17
18#include <linux/ssb/ssb.h>
19#include <linux/ssb/ssb_regs.h>
20#include <linux/slab.h>
21#include <linux/pci.h>
22#include <linux/delay.h>
23
24#include "ssb_private.h"
25
26
27/* Define the following to 1 to enable a printk on each coreswitch. */
28#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
29
30
31/* Lowlevel coreswitching */
32int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
33{
34    int err;
35    int attempts = 0;
36    u32 cur_core;
37
38    while (1) {
39        err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
40                         (coreidx * SSB_CORE_SIZE)
41                         + SSB_ENUM_BASE);
42        if (err)
43            goto error;
44        err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
45                        &cur_core);
46        if (err)
47            goto error;
48        cur_core = (cur_core - SSB_ENUM_BASE)
49               / SSB_CORE_SIZE;
50        if (cur_core == coreidx)
51            break;
52
53        if (attempts++ > SSB_BAR0_MAX_RETRIES)
54            goto error;
55        udelay(10);
56    }
57    return 0;
58error:
59    ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
60    return -ENODEV;
61}
62
63int ssb_pci_switch_core(struct ssb_bus *bus,
64            struct ssb_device *dev)
65{
66    int err;
67    unsigned long flags;
68
69#if SSB_VERBOSE_PCICORESWITCH_DEBUG
70    ssb_printk(KERN_INFO PFX
71           "Switching to %s core, index %d\n",
72           ssb_core_name(dev->id.coreid),
73           dev->core_index);
74#endif
75
76    spin_lock_irqsave(&bus->bar_lock, flags);
77    err = ssb_pci_switch_coreidx(bus, dev->core_index);
78    if (!err)
79        bus->mapped_device = dev;
80    spin_unlock_irqrestore(&bus->bar_lock, flags);
81
82    return err;
83}
84
85/* Enable/disable the on board crystal oscillator and/or PLL. */
86int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
87{
88    int err;
89    u32 in, out, outenable;
90    u16 pci_status;
91
92    if (bus->bustype != SSB_BUSTYPE_PCI)
93        return 0;
94
95    err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
96    if (err)
97        goto err_pci;
98    err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
99    if (err)
100        goto err_pci;
101    err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
102    if (err)
103        goto err_pci;
104
105    outenable |= what;
106
107    if (turn_on) {
108        /* Avoid glitching the clock if GPRS is already using it.
109         * We can't actually read the state of the PLLPD so we infer it
110         * by the value of XTAL_PU which *is* readable via gpioin.
111         */
112        if (!(in & SSB_GPIO_XTAL)) {
113            if (what & SSB_GPIO_XTAL) {
114                /* Turn the crystal on */
115                out |= SSB_GPIO_XTAL;
116                if (what & SSB_GPIO_PLL)
117                    out |= SSB_GPIO_PLL;
118                err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
119                if (err)
120                    goto err_pci;
121                err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
122                                 outenable);
123                if (err)
124                    goto err_pci;
125                msleep(1);
126            }
127            if (what & SSB_GPIO_PLL) {
128                /* Turn the PLL on */
129                out &= ~SSB_GPIO_PLL;
130                err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
131                if (err)
132                    goto err_pci;
133                msleep(5);
134            }
135        }
136
137        err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
138        if (err)
139            goto err_pci;
140        pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
141        err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
142        if (err)
143            goto err_pci;
144    } else {
145        if (what & SSB_GPIO_XTAL) {
146            /* Turn the crystal off */
147            out &= ~SSB_GPIO_XTAL;
148        }
149        if (what & SSB_GPIO_PLL) {
150            /* Turn the PLL off */
151            out |= SSB_GPIO_PLL;
152        }
153        err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
154        if (err)
155            goto err_pci;
156        err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
157        if (err)
158            goto err_pci;
159    }
160
161out:
162    return err;
163
164err_pci:
165    printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
166    err = -EBUSY;
167    goto out;
168}
169
170/* Get the word-offset for a SSB_SPROM_XXX define. */
171#define SPOFF(offset) ((offset) / sizeof(u16))
172/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
173#define SPEX16(_outvar, _offset, _mask, _shift) \
174    out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
175#define SPEX32(_outvar, _offset, _mask, _shift) \
176    out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
177               in[SPOFF(_offset)]) & (_mask)) >> (_shift))
178#define SPEX(_outvar, _offset, _mask, _shift) \
179    SPEX16(_outvar, _offset, _mask, _shift)
180
181#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
182    do { \
183        SPEX(_field[0], _offset + 0, _mask, _shift); \
184        SPEX(_field[1], _offset + 2, _mask, _shift); \
185        SPEX(_field[2], _offset + 4, _mask, _shift); \
186        SPEX(_field[3], _offset + 6, _mask, _shift); \
187        SPEX(_field[4], _offset + 8, _mask, _shift); \
188        SPEX(_field[5], _offset + 10, _mask, _shift); \
189        SPEX(_field[6], _offset + 12, _mask, _shift); \
190        SPEX(_field[7], _offset + 14, _mask, _shift); \
191    } while (0)
192
193
194static inline u8 ssb_crc8(u8 crc, u8 data)
195{
196    /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
197    static const u8 t[] = {
198        0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
199        0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
200        0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
201        0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
202        0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
203        0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
204        0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
205        0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
206        0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
207        0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
208        0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
209        0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
210        0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
211        0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
212        0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
213        0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
214        0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
215        0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
216        0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
217        0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
218        0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
219        0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
220        0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
221        0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
222        0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
223        0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
224        0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
225        0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
226        0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
227        0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
228        0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
229        0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
230    };
231    return t[crc ^ data];
232}
233
234static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
235{
236    int word;
237    u8 crc = 0xFF;
238
239    for (word = 0; word < size - 1; word++) {
240        crc = ssb_crc8(crc, sprom[word] & 0x00FF);
241        crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
242    }
243    crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
244    crc ^= 0xFF;
245
246    return crc;
247}
248
249static int sprom_check_crc(const u16 *sprom, size_t size)
250{
251    u8 crc;
252    u8 expected_crc;
253    u16 tmp;
254
255    crc = ssb_sprom_crc(sprom, size);
256    tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
257    expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
258    if (crc != expected_crc)
259        return -EPROTO;
260
261    return 0;
262}
263
264static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
265{
266    int i;
267
268    for (i = 0; i < bus->sprom_size; i++)
269        sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
270
271    return 0;
272}
273
274static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
275{
276    struct pci_dev *pdev = bus->host_pci;
277    int i, err;
278    u32 spromctl;
279    u16 size = bus->sprom_size;
280
281    ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
282    err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
283    if (err)
284        goto err_ctlreg;
285    spromctl |= SSB_SPROMCTL_WE;
286    err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
287    if (err)
288        goto err_ctlreg;
289    ssb_printk(KERN_NOTICE PFX "[ 0%%");
290    msleep(500);
291    for (i = 0; i < size; i++) {
292        if (i == size / 4)
293            ssb_printk("25%%");
294        else if (i == size / 2)
295            ssb_printk("50%%");
296        else if (i == (size * 3) / 4)
297            ssb_printk("75%%");
298        else if (i % 2)
299            ssb_printk(".");
300        writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
301        mmiowb();
302        msleep(20);
303    }
304    err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
305    if (err)
306        goto err_ctlreg;
307    spromctl &= ~SSB_SPROMCTL_WE;
308    err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
309    if (err)
310        goto err_ctlreg;
311    msleep(500);
312    ssb_printk("100%% ]\n");
313    ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
314
315    return 0;
316err_ctlreg:
317    ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
318    return err;
319}
320
321static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
322                   u16 mask, u16 shift)
323{
324    u16 v;
325    u8 gain;
326
327    v = in[SPOFF(SSB_SPROM1_AGAIN)];
328    gain = (v & mask) >> shift;
329    if (gain == 0xFF)
330        gain = 2; /* If unset use 2dBm */
331    if (sprom_revision == 1) {
332        /* Convert to Q5.2 */
333        gain <<= 2;
334    } else {
335        /* Q5.2 Fractional part is stored in 0xC0 */
336        gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
337    }
338
339    return (s8)gain;
340}
341
342static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
343{
344    int i;
345    u16 v;
346    u16 loc[3];
347
348    if (out->revision == 3) /* rev 3 moved MAC */
349        loc[0] = SSB_SPROM3_IL0MAC;
350    else {
351        loc[0] = SSB_SPROM1_IL0MAC;
352        loc[1] = SSB_SPROM1_ET0MAC;
353        loc[2] = SSB_SPROM1_ET1MAC;
354    }
355    for (i = 0; i < 3; i++) {
356        v = in[SPOFF(loc[0]) + i];
357        *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
358    }
359    if (out->revision < 3) { /* only rev 1-2 have et0, et1 */
360        for (i = 0; i < 3; i++) {
361            v = in[SPOFF(loc[1]) + i];
362            *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
363        }
364        for (i = 0; i < 3; i++) {
365            v = in[SPOFF(loc[2]) + i];
366            *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
367        }
368    }
369    SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
370    SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
371         SSB_SPROM1_ETHPHY_ET1A_SHIFT);
372    SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
373    SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
374    SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
375    if (out->revision == 1)
376        SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
377             SSB_SPROM1_BINF_CCODE_SHIFT);
378    SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
379         SSB_SPROM1_BINF_ANTA_SHIFT);
380    SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
381         SSB_SPROM1_BINF_ANTBG_SHIFT);
382    SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
383    SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
384    SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
385    SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
386    SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
387    SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
388    SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
389    SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
390         SSB_SPROM1_GPIOA_P1_SHIFT);
391    SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
392    SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
393         SSB_SPROM1_GPIOB_P3_SHIFT);
394    SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
395         SSB_SPROM1_MAXPWR_A_SHIFT);
396    SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
397    SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
398         SSB_SPROM1_ITSSI_A_SHIFT);
399    SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
400    SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
401    if (out->revision >= 2)
402        SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
403    SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
404    SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
405
406    /* Extract the antenna gain values. */
407    out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
408                            SSB_SPROM1_AGAIN_BG,
409                            SSB_SPROM1_AGAIN_BG_SHIFT);
410    out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
411                            SSB_SPROM1_AGAIN_A,
412                            SSB_SPROM1_AGAIN_A_SHIFT);
413}
414
415/* Revs 4 5 and 8 have partially shared layout */
416static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
417{
418    SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
419         SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
420    SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
421         SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
422    SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
423         SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
424    SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
425         SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
426
427    SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
428         SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
429    SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
430         SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
431    SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
432         SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
433    SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
434         SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
435
436    SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
437         SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
438    SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
439         SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
440    SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
441         SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
442    SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
443         SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
444
445    SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
446         SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
447    SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
448         SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
449    SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
450         SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
451    SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
452         SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
453}
454
455static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
456{
457    int i;
458    u16 v;
459    u16 il0mac_offset;
460
461    if (out->revision == 4)
462        il0mac_offset = SSB_SPROM4_IL0MAC;
463    else
464        il0mac_offset = SSB_SPROM5_IL0MAC;
465    /* extract the MAC address */
466    for (i = 0; i < 3; i++) {
467        v = in[SPOFF(il0mac_offset) + i];
468        *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
469    }
470    SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
471    SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
472         SSB_SPROM4_ETHPHY_ET1A_SHIFT);
473    SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
474    if (out->revision == 4) {
475        SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
476        SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
477        SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
478        SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
479        SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
480        SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
481    } else {
482        SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
483        SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
484        SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
485        SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
486        SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
487        SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
488    }
489    SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
490         SSB_SPROM4_ANTAVAIL_A_SHIFT);
491    SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
492         SSB_SPROM4_ANTAVAIL_BG_SHIFT);
493    SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
494    SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
495         SSB_SPROM4_ITSSI_BG_SHIFT);
496    SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
497    SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
498         SSB_SPROM4_ITSSI_A_SHIFT);
499    if (out->revision == 4) {
500        SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
501        SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
502             SSB_SPROM4_GPIOA_P1_SHIFT);
503        SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
504        SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
505             SSB_SPROM4_GPIOB_P3_SHIFT);
506    } else {
507        SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
508        SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
509             SSB_SPROM5_GPIOA_P1_SHIFT);
510        SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
511        SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
512             SSB_SPROM5_GPIOB_P3_SHIFT);
513    }
514
515    /* Extract the antenna gain values. */
516    SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01,
517         SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
518    SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01,
519         SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
520    SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23,
521         SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
522    SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23,
523         SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
524
525    sprom_extract_r458(out, in);
526
527    /* TODO - get remaining rev 4 stuff needed */
528}
529
530static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
531{
532    int i;
533    u16 v, o;
534    u16 pwr_info_offset[] = {
535        SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
536        SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
537    };
538    BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
539            ARRAY_SIZE(out->core_pwr_info));
540
541    /* extract the MAC address */
542    for (i = 0; i < 3; i++) {
543        v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
544        *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
545    }
546    SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
547    SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
548    SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
549    SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
550    SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
551    SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
552    SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
553    SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
554         SSB_SPROM8_ANTAVAIL_A_SHIFT);
555    SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
556         SSB_SPROM8_ANTAVAIL_BG_SHIFT);
557    SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
558    SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
559         SSB_SPROM8_ITSSI_BG_SHIFT);
560    SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
561    SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
562         SSB_SPROM8_ITSSI_A_SHIFT);
563    SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
564    SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
565         SSB_SPROM8_MAXP_AL_SHIFT);
566    SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
567    SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
568         SSB_SPROM8_GPIOA_P1_SHIFT);
569    SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
570    SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
571         SSB_SPROM8_GPIOB_P3_SHIFT);
572    SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
573    SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
574         SSB_SPROM8_TRI5G_SHIFT);
575    SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
576    SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
577         SSB_SPROM8_TRI5GH_SHIFT);
578    SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
579    SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
580         SSB_SPROM8_RXPO5G_SHIFT);
581    SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
582    SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
583         SSB_SPROM8_RSSISMC2G_SHIFT);
584    SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
585         SSB_SPROM8_RSSISAV2G_SHIFT);
586    SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
587         SSB_SPROM8_BXA2G_SHIFT);
588    SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
589    SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
590         SSB_SPROM8_RSSISMC5G_SHIFT);
591    SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
592         SSB_SPROM8_RSSISAV5G_SHIFT);
593    SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
594         SSB_SPROM8_BXA5G_SHIFT);
595    SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
596    SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
597    SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
598    SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
599    SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
600    SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
601    SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
602    SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
603    SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
604    SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
605    SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
606    SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
607    SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
608    SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
609    SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
610    SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
611    SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
612
613    /* Extract the antenna gain values. */
614    SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
615         SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
616    SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
617         SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
618    SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
619         SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
620    SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
621         SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
622
623    /* Extract cores power info info */
624    for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
625        o = pwr_info_offset[i];
626        SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
627            SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
628        SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
629            SSB_SPROM8_2G_MAXP, 0);
630
631        SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
632        SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
633        SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
634
635        SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
636            SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
637        SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
638            SSB_SPROM8_5G_MAXP, 0);
639        SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
640            SSB_SPROM8_5GH_MAXP, 0);
641        SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
642            SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
643
644        SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
645        SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
646        SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
647        SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
648        SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
649        SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
650        SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
651        SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
652        SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
653    }
654
655    /* Extract FEM info */
656    SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
657        SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
658    SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
659        SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
660    SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
661        SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
662    SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
663        SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
664    SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
665        SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
666
667    SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
668        SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
669    SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
670        SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
671    SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
672        SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
673    SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
674        SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
675    SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
676        SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
677
678    SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
679         SSB_SPROM8_LEDDC_ON_SHIFT);
680    SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
681         SSB_SPROM8_LEDDC_OFF_SHIFT);
682
683    SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
684         SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
685    SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
686         SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
687    SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
688         SSB_SPROM8_TXRXC_SWITCH_SHIFT);
689
690    SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
691
692    SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
693    SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
694    SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
695    SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
696
697    SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
698         SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
699    SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
700         SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
701    SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
702         SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
703         SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
704    SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
705         SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
706    SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
707         SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
708         SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
709    SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
710         SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
711         SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
712    SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
713         SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
714         SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
715    SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
716         SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
717
718    SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
719    SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
720    SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
721    SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
722
723    SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
724         SSB_SPROM8_THERMAL_TRESH_SHIFT);
725    SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
726         SSB_SPROM8_THERMAL_OFFSET_SHIFT);
727    SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
728         SSB_SPROM8_TEMPDELTA_PHYCAL,
729         SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
730    SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
731         SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
732    SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
733         SSB_SPROM8_TEMPDELTA_HYSTERESIS,
734         SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
735    sprom_extract_r458(out, in);
736
737    /* TODO - get remaining rev 8 stuff needed */
738}
739
740static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
741             const u16 *in, u16 size)
742{
743    memset(out, 0, sizeof(*out));
744
745    out->revision = in[size - 1] & 0x00FF;
746    ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
747    memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
748    memset(out->et1mac, 0xFF, 6);
749
750    if ((bus->chip_id & 0xFF00) == 0x4400) {
751        /* Workaround: The BCM44XX chip has a stupid revision
752         * number stored in the SPROM.
753         * Always extract r1. */
754        out->revision = 1;
755        ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
756    }
757
758    switch (out->revision) {
759    case 1:
760    case 2:
761    case 3:
762        sprom_extract_r123(out, in);
763        break;
764    case 4:
765    case 5:
766        sprom_extract_r45(out, in);
767        break;
768    case 8:
769        sprom_extract_r8(out, in);
770        break;
771    default:
772        ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
773               " revision %d detected. Will extract"
774               " v1\n", out->revision);
775        out->revision = 1;
776        sprom_extract_r123(out, in);
777    }
778
779    if (out->boardflags_lo == 0xFFFF)
780        out->boardflags_lo = 0; /* per specs */
781    if (out->boardflags_hi == 0xFFFF)
782        out->boardflags_hi = 0; /* per specs */
783
784    return 0;
785}
786
787static int ssb_pci_sprom_get(struct ssb_bus *bus,
788                 struct ssb_sprom *sprom)
789{
790    int err;
791    u16 *buf;
792
793    if (!ssb_is_sprom_available(bus)) {
794        ssb_printk(KERN_ERR PFX "No SPROM available!\n");
795        return -ENODEV;
796    }
797    if (bus->chipco.dev) { /* can be unavailable! */
798        /*
799         * get SPROM offset: SSB_SPROM_BASE1 except for
800         * chipcommon rev >= 31 or chip ID is 0x4312 and
801         * chipcommon status & 3 == 2
802         */
803        if (bus->chipco.dev->id.revision >= 31)
804            bus->sprom_offset = SSB_SPROM_BASE31;
805        else if (bus->chip_id == 0x4312 &&
806             (bus->chipco.status & 0x03) == 2)
807            bus->sprom_offset = SSB_SPROM_BASE31;
808        else
809            bus->sprom_offset = SSB_SPROM_BASE1;
810    } else {
811        bus->sprom_offset = SSB_SPROM_BASE1;
812    }
813    ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
814
815    buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
816    if (!buf)
817        return -ENOMEM;
818    bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
819    sprom_do_read(bus, buf);
820    err = sprom_check_crc(buf, bus->sprom_size);
821    if (err) {
822        /* try for a 440 byte SPROM - revision 4 and higher */
823        kfree(buf);
824        buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
825                  GFP_KERNEL);
826        if (!buf)
827            return -ENOMEM;
828        bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
829        sprom_do_read(bus, buf);
830        err = sprom_check_crc(buf, bus->sprom_size);
831        if (err) {
832            /* All CRC attempts failed.
833             * Maybe there is no SPROM on the device?
834             * Now we ask the arch code if there is some sprom
835             * available for this device in some other storage */
836            err = ssb_fill_sprom_with_fallback(bus, sprom);
837            if (err) {
838                ssb_printk(KERN_WARNING PFX "WARNING: Using"
839                       " fallback SPROM failed (err %d)\n",
840                       err);
841            } else {
842                ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
843                        " revision %d provided by"
844                        " platform.\n", sprom->revision);
845                err = 0;
846                goto out_free;
847            }
848            ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
849                   " SPROM CRC (corrupt SPROM)\n");
850        }
851    }
852    err = sprom_extract(bus, sprom, buf, bus->sprom_size);
853
854out_free:
855    kfree(buf);
856    return err;
857}
858
859static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
860                  struct ssb_boardinfo *bi)
861{
862    bi->vendor = bus->host_pci->subsystem_vendor;
863    bi->type = bus->host_pci->subsystem_device;
864}
865
866int ssb_pci_get_invariants(struct ssb_bus *bus,
867               struct ssb_init_invariants *iv)
868{
869    int err;
870
871    err = ssb_pci_sprom_get(bus, &iv->sprom);
872    if (err)
873        goto out;
874    ssb_pci_get_boardinfo(bus, &iv->boardinfo);
875
876out:
877    return err;
878}
879
880#ifdef CONFIG_SSB_DEBUG
881static int ssb_pci_assert_buspower(struct ssb_bus *bus)
882{
883    if (likely(bus->powered_up))
884        return 0;
885
886    printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
887           "while accessing PCI MMIO space\n");
888    if (bus->power_warn_count <= 10) {
889        bus->power_warn_count++;
890        dump_stack();
891    }
892
893    return -ENODEV;
894}
895#else /* DEBUG */
896static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
897{
898    return 0;
899}
900#endif /* DEBUG */
901
902static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
903{
904    struct ssb_bus *bus = dev->bus;
905
906    if (unlikely(ssb_pci_assert_buspower(bus)))
907        return 0xFF;
908    if (unlikely(bus->mapped_device != dev)) {
909        if (unlikely(ssb_pci_switch_core(bus, dev)))
910            return 0xFF;
911    }
912    return ioread8(bus->mmio + offset);
913}
914
915static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
916{
917    struct ssb_bus *bus = dev->bus;
918
919    if (unlikely(ssb_pci_assert_buspower(bus)))
920        return 0xFFFF;
921    if (unlikely(bus->mapped_device != dev)) {
922        if (unlikely(ssb_pci_switch_core(bus, dev)))
923            return 0xFFFF;
924    }
925    return ioread16(bus->mmio + offset);
926}
927
928static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
929{
930    struct ssb_bus *bus = dev->bus;
931
932    if (unlikely(ssb_pci_assert_buspower(bus)))
933        return 0xFFFFFFFF;
934    if (unlikely(bus->mapped_device != dev)) {
935        if (unlikely(ssb_pci_switch_core(bus, dev)))
936            return 0xFFFFFFFF;
937    }
938    return ioread32(bus->mmio + offset);
939}
940
941#ifdef CONFIG_SSB_BLOCKIO
942static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
943                   size_t count, u16 offset, u8 reg_width)
944{
945    struct ssb_bus *bus = dev->bus;
946    void __iomem *addr = bus->mmio + offset;
947
948    if (unlikely(ssb_pci_assert_buspower(bus)))
949        goto error;
950    if (unlikely(bus->mapped_device != dev)) {
951        if (unlikely(ssb_pci_switch_core(bus, dev)))
952            goto error;
953    }
954    switch (reg_width) {
955    case sizeof(u8):
956        ioread8_rep(addr, buffer, count);
957        break;
958    case sizeof(u16):
959        SSB_WARN_ON(count & 1);
960        ioread16_rep(addr, buffer, count >> 1);
961        break;
962    case sizeof(u32):
963        SSB_WARN_ON(count & 3);
964        ioread32_rep(addr, buffer, count >> 2);
965        break;
966    default:
967        SSB_WARN_ON(1);
968    }
969
970    return;
971error:
972    memset(buffer, 0xFF, count);
973}
974#endif /* CONFIG_SSB_BLOCKIO */
975
976static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
977{
978    struct ssb_bus *bus = dev->bus;
979
980    if (unlikely(ssb_pci_assert_buspower(bus)))
981        return;
982    if (unlikely(bus->mapped_device != dev)) {
983        if (unlikely(ssb_pci_switch_core(bus, dev)))
984            return;
985    }
986    iowrite8(value, bus->mmio + offset);
987}
988
989static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
990{
991    struct ssb_bus *bus = dev->bus;
992
993    if (unlikely(ssb_pci_assert_buspower(bus)))
994        return;
995    if (unlikely(bus->mapped_device != dev)) {
996        if (unlikely(ssb_pci_switch_core(bus, dev)))
997            return;
998    }
999    iowrite16(value, bus->mmio + offset);
1000}
1001
1002static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
1003{
1004    struct ssb_bus *bus = dev->bus;
1005
1006    if (unlikely(ssb_pci_assert_buspower(bus)))
1007        return;
1008    if (unlikely(bus->mapped_device != dev)) {
1009        if (unlikely(ssb_pci_switch_core(bus, dev)))
1010            return;
1011    }
1012    iowrite32(value, bus->mmio + offset);
1013}
1014
1015#ifdef CONFIG_SSB_BLOCKIO
1016static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1017                size_t count, u16 offset, u8 reg_width)
1018{
1019    struct ssb_bus *bus = dev->bus;
1020    void __iomem *addr = bus->mmio + offset;
1021
1022    if (unlikely(ssb_pci_assert_buspower(bus)))
1023        return;
1024    if (unlikely(bus->mapped_device != dev)) {
1025        if (unlikely(ssb_pci_switch_core(bus, dev)))
1026            return;
1027    }
1028    switch (reg_width) {
1029    case sizeof(u8):
1030        iowrite8_rep(addr, buffer, count);
1031        break;
1032    case sizeof(u16):
1033        SSB_WARN_ON(count & 1);
1034        iowrite16_rep(addr, buffer, count >> 1);
1035        break;
1036    case sizeof(u32):
1037        SSB_WARN_ON(count & 3);
1038        iowrite32_rep(addr, buffer, count >> 2);
1039        break;
1040    default:
1041        SSB_WARN_ON(1);
1042    }
1043}
1044#endif /* CONFIG_SSB_BLOCKIO */
1045
1046/* Not "static", as it's used in main.c */
1047const struct ssb_bus_ops ssb_pci_ops = {
1048    .read8 = ssb_pci_read8,
1049    .read16 = ssb_pci_read16,
1050    .read32 = ssb_pci_read32,
1051    .write8 = ssb_pci_write8,
1052    .write16 = ssb_pci_write16,
1053    .write32 = ssb_pci_write32,
1054#ifdef CONFIG_SSB_BLOCKIO
1055    .block_read = ssb_pci_block_read,
1056    .block_write = ssb_pci_block_write,
1057#endif
1058};
1059
1060static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
1061                       struct device_attribute *attr,
1062                       char *buf)
1063{
1064    struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
1065    struct ssb_bus *bus;
1066
1067    bus = ssb_pci_dev_to_bus(pdev);
1068    if (!bus)
1069        return -ENODEV;
1070
1071    return ssb_attr_sprom_show(bus, buf, sprom_do_read);
1072}
1073
1074static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
1075                    struct device_attribute *attr,
1076                    const char *buf, size_t count)
1077{
1078    struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
1079    struct ssb_bus *bus;
1080
1081    bus = ssb_pci_dev_to_bus(pdev);
1082    if (!bus)
1083        return -ENODEV;
1084
1085    return ssb_attr_sprom_store(bus, buf, count,
1086                    sprom_check_crc, sprom_do_write);
1087}
1088
1089static DEVICE_ATTR(ssb_sprom, 0600,
1090           ssb_pci_attr_sprom_show,
1091           ssb_pci_attr_sprom_store);
1092
1093void ssb_pci_exit(struct ssb_bus *bus)
1094{
1095    struct pci_dev *pdev;
1096
1097    if (bus->bustype != SSB_BUSTYPE_PCI)
1098        return;
1099
1100    pdev = bus->host_pci;
1101    device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
1102}
1103
1104int ssb_pci_init(struct ssb_bus *bus)
1105{
1106    struct pci_dev *pdev;
1107    int err;
1108
1109    if (bus->bustype != SSB_BUSTYPE_PCI)
1110        return 0;
1111
1112    pdev = bus->host_pci;
1113    mutex_init(&bus->sprom_mutex);
1114    err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
1115    if (err)
1116        goto out;
1117
1118out:
1119    return err;
1120}
1121

Archive Download this file



interactive