linux/drivers/ssb/pci.c
<<
>>
Prefs
   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
 182static inline u8 ssb_crc8(u8 crc, u8 data)
 183{
 184        /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
 185        static const u8 t[] = {
 186                0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
 187                0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
 188                0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
 189                0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
 190                0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
 191                0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
 192                0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
 193                0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
 194                0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
 195                0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
 196                0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
 197                0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
 198                0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
 199                0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
 200                0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
 201                0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
 202                0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
 203                0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
 204                0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
 205                0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
 206                0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
 207                0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
 208                0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
 209                0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
 210                0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
 211                0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
 212                0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
 213                0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
 214                0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
 215                0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
 216                0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
 217                0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
 218        };
 219        return t[crc ^ data];
 220}
 221
 222static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
 223{
 224        int word;
 225        u8 crc = 0xFF;
 226
 227        for (word = 0; word < size - 1; word++) {
 228                crc = ssb_crc8(crc, sprom[word] & 0x00FF);
 229                crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
 230        }
 231        crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
 232        crc ^= 0xFF;
 233
 234        return crc;
 235}
 236
 237static int sprom_check_crc(const u16 *sprom, size_t size)
 238{
 239        u8 crc;
 240        u8 expected_crc;
 241        u16 tmp;
 242
 243        crc = ssb_sprom_crc(sprom, size);
 244        tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
 245        expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
 246        if (crc != expected_crc)
 247                return -EPROTO;
 248
 249        return 0;
 250}
 251
 252static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
 253{
 254        int i;
 255
 256        for (i = 0; i < bus->sprom_size; i++)
 257                sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
 258
 259        return 0;
 260}
 261
 262static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
 263{
 264        struct pci_dev *pdev = bus->host_pci;
 265        int i, err;
 266        u32 spromctl;
 267        u16 size = bus->sprom_size;
 268
 269        ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
 270        err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
 271        if (err)
 272                goto err_ctlreg;
 273        spromctl |= SSB_SPROMCTL_WE;
 274        err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
 275        if (err)
 276                goto err_ctlreg;
 277        ssb_printk(KERN_NOTICE PFX "[ 0%%");
 278        msleep(500);
 279        for (i = 0; i < size; i++) {
 280                if (i == size / 4)
 281                        ssb_printk("25%%");
 282                else if (i == size / 2)
 283                        ssb_printk("50%%");
 284                else if (i == (size * 3) / 4)
 285                        ssb_printk("75%%");
 286                else if (i % 2)
 287                        ssb_printk(".");
 288                writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
 289                mmiowb();
 290                msleep(20);
 291        }
 292        err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
 293        if (err)
 294                goto err_ctlreg;
 295        spromctl &= ~SSB_SPROMCTL_WE;
 296        err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
 297        if (err)
 298                goto err_ctlreg;
 299        msleep(500);
 300        ssb_printk("100%% ]\n");
 301        ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
 302
 303        return 0;
 304err_ctlreg:
 305        ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
 306        return err;
 307}
 308
 309static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
 310                               u16 mask, u16 shift)
 311{
 312        u16 v;
 313        u8 gain;
 314
 315        v = in[SPOFF(SSB_SPROM1_AGAIN)];
 316        gain = (v & mask) >> shift;
 317        if (gain == 0xFF)
 318                gain = 2; /* If unset use 2dBm */
 319        if (sprom_revision == 1) {
 320                /* Convert to Q5.2 */
 321                gain <<= 2;
 322        } else {
 323                /* Q5.2 Fractional part is stored in 0xC0 */
 324                gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
 325        }
 326
 327        return (s8)gain;
 328}
 329
 330static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
 331{
 332        int i;
 333        u16 v;
 334        s8 gain;
 335        u16 loc[3];
 336
 337        if (out->revision == 3)                 /* rev 3 moved MAC */
 338                loc[0] = SSB_SPROM3_IL0MAC;
 339        else {
 340                loc[0] = SSB_SPROM1_IL0MAC;
 341                loc[1] = SSB_SPROM1_ET0MAC;
 342                loc[2] = SSB_SPROM1_ET1MAC;
 343        }
 344        for (i = 0; i < 3; i++) {
 345                v = in[SPOFF(loc[0]) + i];
 346                *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 347        }
 348        if (out->revision < 3) {        /* only rev 1-2 have et0, et1 */
 349                for (i = 0; i < 3; i++) {
 350                        v = in[SPOFF(loc[1]) + i];
 351                        *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
 352                }
 353                for (i = 0; i < 3; i++) {
 354                        v = in[SPOFF(loc[2]) + i];
 355                        *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
 356                }
 357        }
 358        SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
 359        SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
 360             SSB_SPROM1_ETHPHY_ET1A_SHIFT);
 361        SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
 362        SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
 363        SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
 364        SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
 365             SSB_SPROM1_BINF_CCODE_SHIFT);
 366        SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
 367             SSB_SPROM1_BINF_ANTA_SHIFT);
 368        SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
 369             SSB_SPROM1_BINF_ANTBG_SHIFT);
 370        SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
 371        SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
 372        SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
 373        SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
 374        SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
 375        SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
 376        SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
 377        SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
 378             SSB_SPROM1_GPIOA_P1_SHIFT);
 379        SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
 380        SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
 381             SSB_SPROM1_GPIOB_P3_SHIFT);
 382        SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
 383             SSB_SPROM1_MAXPWR_A_SHIFT);
 384        SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
 385        SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
 386             SSB_SPROM1_ITSSI_A_SHIFT);
 387        SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
 388        SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
 389        if (out->revision >= 2)
 390                SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
 391
 392        /* Extract the antenna gain values. */
 393        gain = r123_extract_antgain(out->revision, in,
 394                                    SSB_SPROM1_AGAIN_BG,
 395                                    SSB_SPROM1_AGAIN_BG_SHIFT);
 396        out->antenna_gain.ghz24.a0 = gain;
 397        out->antenna_gain.ghz24.a1 = gain;
 398        out->antenna_gain.ghz24.a2 = gain;
 399        out->antenna_gain.ghz24.a3 = gain;
 400        gain = r123_extract_antgain(out->revision, in,
 401                                    SSB_SPROM1_AGAIN_A,
 402                                    SSB_SPROM1_AGAIN_A_SHIFT);
 403        out->antenna_gain.ghz5.a0 = gain;
 404        out->antenna_gain.ghz5.a1 = gain;
 405        out->antenna_gain.ghz5.a2 = gain;
 406        out->antenna_gain.ghz5.a3 = gain;
 407}
 408
 409/* Revs 4 5 and 8 have partially shared layout */
 410static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
 411{
 412        SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
 413             SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
 414        SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
 415             SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
 416        SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
 417             SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
 418        SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
 419             SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
 420
 421        SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
 422             SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
 423        SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
 424             SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
 425        SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
 426             SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
 427        SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
 428             SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
 429
 430        SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
 431             SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
 432        SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
 433             SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
 434        SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
 435             SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
 436        SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
 437             SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
 438
 439        SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
 440             SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
 441        SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
 442             SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
 443        SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
 444             SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
 445        SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
 446             SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
 447}
 448
 449static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
 450{
 451        int i;
 452        u16 v;
 453        u16 il0mac_offset;
 454
 455        if (out->revision == 4)
 456                il0mac_offset = SSB_SPROM4_IL0MAC;
 457        else
 458                il0mac_offset = SSB_SPROM5_IL0MAC;
 459        /* extract the MAC address */
 460        for (i = 0; i < 3; i++) {
 461                v = in[SPOFF(il0mac_offset) + i];
 462                *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 463        }
 464        SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
 465        SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
 466             SSB_SPROM4_ETHPHY_ET1A_SHIFT);
 467        if (out->revision == 4) {
 468                SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
 469                SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
 470                SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
 471                SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
 472                SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
 473        } else {
 474                SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
 475                SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
 476                SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
 477                SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
 478                SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
 479        }
 480        SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
 481             SSB_SPROM4_ANTAVAIL_A_SHIFT);
 482        SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
 483             SSB_SPROM4_ANTAVAIL_BG_SHIFT);
 484        SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
 485        SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
 486             SSB_SPROM4_ITSSI_BG_SHIFT);
 487        SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
 488        SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
 489             SSB_SPROM4_ITSSI_A_SHIFT);
 490        if (out->revision == 4) {
 491                SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
 492                SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
 493                     SSB_SPROM4_GPIOA_P1_SHIFT);
 494                SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
 495                SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
 496                     SSB_SPROM4_GPIOB_P3_SHIFT);
 497        } else {
 498                SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
 499                SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
 500                     SSB_SPROM5_GPIOA_P1_SHIFT);
 501                SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
 502                SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
 503                     SSB_SPROM5_GPIOB_P3_SHIFT);
 504        }
 505
 506        /* Extract the antenna gain values. */
 507        SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
 508             SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
 509        SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
 510             SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
 511        SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
 512             SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
 513        SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
 514             SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
 515        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
 516               sizeof(out->antenna_gain.ghz5));
 517
 518        sprom_extract_r458(out, in);
 519
 520        /* TODO - get remaining rev 4 stuff needed */
 521}
 522
 523static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
 524{
 525        int i;
 526        u16 v;
 527
 528        /* extract the MAC address */
 529        for (i = 0; i < 3; i++) {
 530                v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
 531                *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 532        }
 533        SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0);
 534        SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
 535        SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
 536        SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
 537        SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
 538        SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
 539             SSB_SPROM8_ANTAVAIL_A_SHIFT);
 540        SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
 541             SSB_SPROM8_ANTAVAIL_BG_SHIFT);
 542        SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
 543        SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
 544             SSB_SPROM8_ITSSI_BG_SHIFT);
 545        SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
 546        SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
 547             SSB_SPROM8_ITSSI_A_SHIFT);
 548        SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
 549        SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
 550             SSB_SPROM8_MAXP_AL_SHIFT);
 551        SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
 552        SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
 553             SSB_SPROM8_GPIOA_P1_SHIFT);
 554        SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
 555        SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
 556             SSB_SPROM8_GPIOB_P3_SHIFT);
 557        SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
 558        SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
 559             SSB_SPROM8_TRI5G_SHIFT);
 560        SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
 561        SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
 562             SSB_SPROM8_TRI5GH_SHIFT);
 563        SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
 564        SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
 565             SSB_SPROM8_RXPO5G_SHIFT);
 566        SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
 567        SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
 568             SSB_SPROM8_RSSISMC2G_SHIFT);
 569        SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
 570             SSB_SPROM8_RSSISAV2G_SHIFT);
 571        SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
 572             SSB_SPROM8_BXA2G_SHIFT);
 573        SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
 574        SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
 575             SSB_SPROM8_RSSISMC5G_SHIFT);
 576        SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
 577             SSB_SPROM8_RSSISAV5G_SHIFT);
 578        SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
 579             SSB_SPROM8_BXA5G_SHIFT);
 580        SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
 581        SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
 582        SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
 583        SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
 584        SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
 585        SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
 586        SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
 587        SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
 588        SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
 589        SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
 590        SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
 591        SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
 592        SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
 593        SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
 594        SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
 595        SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
 596        SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
 597
 598        /* Extract the antenna gain values. */
 599        SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01,
 600             SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
 601        SPEX(antenna_gain.ghz24.a1, SSB_SPROM8_AGAIN01,
 602             SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
 603        SPEX(antenna_gain.ghz24.a2, SSB_SPROM8_AGAIN23,
 604             SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
 605        SPEX(antenna_gain.ghz24.a3, SSB_SPROM8_AGAIN23,
 606             SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
 607        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
 608               sizeof(out->antenna_gain.ghz5));
 609
 610        /* Extract FEM info */
 611        SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
 612                SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
 613        SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
 614                SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 615        SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
 616                SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 617        SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
 618                SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
 619        SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
 620                SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 621
 622        SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
 623                SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
 624        SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
 625                SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 626        SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
 627                SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 628        SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
 629                SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
 630        SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
 631                SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 632
 633        sprom_extract_r458(out, in);
 634
 635        /* TODO - get remaining rev 8 stuff needed */
 636}
 637
 638static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
 639                         const u16 *in, u16 size)
 640{
 641        memset(out, 0, sizeof(*out));
 642
 643        out->revision = in[size - 1] & 0x00FF;
 644        ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
 645        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
 646        memset(out->et1mac, 0xFF, 6);
 647
 648        if ((bus->chip_id & 0xFF00) == 0x4400) {
 649                /* Workaround: The BCM44XX chip has a stupid revision
 650                 * number stored in the SPROM.
 651                 * Always extract r1. */
 652                out->revision = 1;
 653                ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
 654        }
 655
 656        switch (out->revision) {
 657        case 1:
 658        case 2:
 659        case 3:
 660                sprom_extract_r123(out, in);
 661                break;
 662        case 4:
 663        case 5:
 664                sprom_extract_r45(out, in);
 665                break;
 666        case 8:
 667                sprom_extract_r8(out, in);
 668                break;
 669        default:
 670                ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
 671                           " revision %d detected. Will extract"
 672                           " v1\n", out->revision);
 673                out->revision = 1;
 674                sprom_extract_r123(out, in);
 675        }
 676
 677        if (out->boardflags_lo == 0xFFFF)
 678                out->boardflags_lo = 0;  /* per specs */
 679        if (out->boardflags_hi == 0xFFFF)
 680                out->boardflags_hi = 0;  /* per specs */
 681
 682        return 0;
 683}
 684
 685static int ssb_pci_sprom_get(struct ssb_bus *bus,
 686                             struct ssb_sprom *sprom)
 687{
 688        int err;
 689        u16 *buf;
 690
 691        if (!ssb_is_sprom_available(bus)) {
 692                ssb_printk(KERN_ERR PFX "No SPROM available!\n");
 693                return -ENODEV;
 694        }
 695        if (bus->chipco.dev) {  /* can be unavailable! */
 696                /*
 697                 * get SPROM offset: SSB_SPROM_BASE1 except for
 698                 * chipcommon rev >= 31 or chip ID is 0x4312 and
 699                 * chipcommon status & 3 == 2
 700                 */
 701                if (bus->chipco.dev->id.revision >= 31)
 702                        bus->sprom_offset = SSB_SPROM_BASE31;
 703                else if (bus->chip_id == 0x4312 &&
 704                         (bus->chipco.status & 0x03) == 2)
 705                        bus->sprom_offset = SSB_SPROM_BASE31;
 706                else
 707                        bus->sprom_offset = SSB_SPROM_BASE1;
 708        } else {
 709                bus->sprom_offset = SSB_SPROM_BASE1;
 710        }
 711        ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
 712
 713        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
 714        if (!buf)
 715                return -ENOMEM;
 716        bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
 717        sprom_do_read(bus, buf);
 718        err = sprom_check_crc(buf, bus->sprom_size);
 719        if (err) {
 720                /* try for a 440 byte SPROM - revision 4 and higher */
 721                kfree(buf);
 722                buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
 723                              GFP_KERNEL);
 724                if (!buf)
 725                        return -ENOMEM;
 726                bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
 727                sprom_do_read(bus, buf);
 728                err = sprom_check_crc(buf, bus->sprom_size);
 729                if (err) {
 730                        /* All CRC attempts failed.
 731                         * Maybe there is no SPROM on the device?
 732                         * Now we ask the arch code if there is some sprom
 733                         * available for this device in some other storage */
 734                        err = ssb_fill_sprom_with_fallback(bus, sprom);
 735                        if (err) {
 736                                ssb_printk(KERN_WARNING PFX "WARNING: Using"
 737                                           " fallback SPROM failed (err %d)\n",
 738                                           err);
 739                        } else {
 740                                ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
 741                                            " revision %d provided by"
 742                                            " platform.\n", sprom->revision);
 743                                err = 0;
 744                                goto out_free;
 745                        }
 746                        ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
 747                                   " SPROM CRC (corrupt SPROM)\n");
 748                }
 749        }
 750        err = sprom_extract(bus, sprom, buf, bus->sprom_size);
 751
 752out_free:
 753        kfree(buf);
 754        return err;
 755}
 756
 757static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
 758                                  struct ssb_boardinfo *bi)
 759{
 760        bi->vendor = bus->host_pci->subsystem_vendor;
 761        bi->type = bus->host_pci->subsystem_device;
 762        bi->rev = bus->host_pci->revision;
 763}
 764
 765int ssb_pci_get_invariants(struct ssb_bus *bus,
 766                           struct ssb_init_invariants *iv)
 767{
 768        int err;
 769
 770        err = ssb_pci_sprom_get(bus, &iv->sprom);
 771        if (err)
 772                goto out;
 773        ssb_pci_get_boardinfo(bus, &iv->boardinfo);
 774
 775out:
 776        return err;
 777}
 778
 779#ifdef CONFIG_SSB_DEBUG
 780static int ssb_pci_assert_buspower(struct ssb_bus *bus)
 781{
 782        if (likely(bus->powered_up))
 783                return 0;
 784
 785        printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
 786               "while accessing PCI MMIO space\n");
 787        if (bus->power_warn_count <= 10) {
 788                bus->power_warn_count++;
 789                dump_stack();
 790        }
 791
 792        return -ENODEV;
 793}
 794#else /* DEBUG */
 795static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
 796{
 797        return 0;
 798}
 799#endif /* DEBUG */
 800
 801static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
 802{
 803        struct ssb_bus *bus = dev->bus;
 804
 805        if (unlikely(ssb_pci_assert_buspower(bus)))
 806                return 0xFF;
 807        if (unlikely(bus->mapped_device != dev)) {
 808                if (unlikely(ssb_pci_switch_core(bus, dev)))
 809                        return 0xFF;
 810        }
 811        return ioread8(bus->mmio + offset);
 812}
 813
 814static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
 815{
 816        struct ssb_bus *bus = dev->bus;
 817
 818        if (unlikely(ssb_pci_assert_buspower(bus)))
 819                return 0xFFFF;
 820        if (unlikely(bus->mapped_device != dev)) {
 821                if (unlikely(ssb_pci_switch_core(bus, dev)))
 822                        return 0xFFFF;
 823        }
 824        return ioread16(bus->mmio + offset);
 825}
 826
 827static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
 828{
 829        struct ssb_bus *bus = dev->bus;
 830
 831        if (unlikely(ssb_pci_assert_buspower(bus)))
 832                return 0xFFFFFFFF;
 833        if (unlikely(bus->mapped_device != dev)) {
 834                if (unlikely(ssb_pci_switch_core(bus, dev)))
 835                        return 0xFFFFFFFF;
 836        }
 837        return ioread32(bus->mmio + offset);
 838}
 839
 840#ifdef CONFIG_SSB_BLOCKIO
 841static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
 842                               size_t count, u16 offset, u8 reg_width)
 843{
 844        struct ssb_bus *bus = dev->bus;
 845        void __iomem *addr = bus->mmio + offset;
 846
 847        if (unlikely(ssb_pci_assert_buspower(bus)))
 848                goto error;
 849        if (unlikely(bus->mapped_device != dev)) {
 850                if (unlikely(ssb_pci_switch_core(bus, dev)))
 851                        goto error;
 852        }
 853        switch (reg_width) {
 854        case sizeof(u8):
 855                ioread8_rep(addr, buffer, count);
 856                break;
 857        case sizeof(u16):
 858                SSB_WARN_ON(count & 1);
 859                ioread16_rep(addr, buffer, count >> 1);
 860                break;
 861        case sizeof(u32):
 862                SSB_WARN_ON(count & 3);
 863                ioread32_rep(addr, buffer, count >> 2);
 864                break;
 865        default:
 866                SSB_WARN_ON(1);
 867        }
 868
 869        return;
 870error:
 871        memset(buffer, 0xFF, count);
 872}
 873#endif /* CONFIG_SSB_BLOCKIO */
 874
 875static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
 876{
 877        struct ssb_bus *bus = dev->bus;
 878
 879        if (unlikely(ssb_pci_assert_buspower(bus)))
 880                return;
 881        if (unlikely(bus->mapped_device != dev)) {
 882                if (unlikely(ssb_pci_switch_core(bus, dev)))
 883                        return;
 884        }
 885        iowrite8(value, bus->mmio + offset);
 886}
 887
 888static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
 889{
 890        struct ssb_bus *bus = dev->bus;
 891
 892        if (unlikely(ssb_pci_assert_buspower(bus)))
 893                return;
 894        if (unlikely(bus->mapped_device != dev)) {
 895                if (unlikely(ssb_pci_switch_core(bus, dev)))
 896                        return;
 897        }
 898        iowrite16(value, bus->mmio + offset);
 899}
 900
 901static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
 902{
 903        struct ssb_bus *bus = dev->bus;
 904
 905        if (unlikely(ssb_pci_assert_buspower(bus)))
 906                return;
 907        if (unlikely(bus->mapped_device != dev)) {
 908                if (unlikely(ssb_pci_switch_core(bus, dev)))
 909                        return;
 910        }
 911        iowrite32(value, bus->mmio + offset);
 912}
 913
 914#ifdef CONFIG_SSB_BLOCKIO
 915static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
 916                                size_t count, u16 offset, u8 reg_width)
 917{
 918        struct ssb_bus *bus = dev->bus;
 919        void __iomem *addr = bus->mmio + offset;
 920
 921        if (unlikely(ssb_pci_assert_buspower(bus)))
 922                return;
 923        if (unlikely(bus->mapped_device != dev)) {
 924                if (unlikely(ssb_pci_switch_core(bus, dev)))
 925                        return;
 926        }
 927        switch (reg_width) {
 928        case sizeof(u8):
 929                iowrite8_rep(addr, buffer, count);
 930                break;
 931        case sizeof(u16):
 932                SSB_WARN_ON(count & 1);
 933                iowrite16_rep(addr, buffer, count >> 1);
 934                break;
 935        case sizeof(u32):
 936                SSB_WARN_ON(count & 3);
 937                iowrite32_rep(addr, buffer, count >> 2);
 938                break;
 939        default:
 940                SSB_WARN_ON(1);
 941        }
 942}
 943#endif /* CONFIG_SSB_BLOCKIO */
 944
 945/* Not "static", as it's used in main.c */
 946const struct ssb_bus_ops ssb_pci_ops = {
 947        .read8          = ssb_pci_read8,
 948        .read16         = ssb_pci_read16,
 949        .read32         = ssb_pci_read32,
 950        .write8         = ssb_pci_write8,
 951        .write16        = ssb_pci_write16,
 952        .write32        = ssb_pci_write32,
 953#ifdef CONFIG_SSB_BLOCKIO
 954        .block_read     = ssb_pci_block_read,
 955        .block_write    = ssb_pci_block_write,
 956#endif
 957};
 958
 959static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
 960                                       struct device_attribute *attr,
 961                                       char *buf)
 962{
 963        struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
 964        struct ssb_bus *bus;
 965
 966        bus = ssb_pci_dev_to_bus(pdev);
 967        if (!bus)
 968                return -ENODEV;
 969
 970        return ssb_attr_sprom_show(bus, buf, sprom_do_read);
 971}
 972
 973static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
 974                                        struct device_attribute *attr,
 975                                        const char *buf, size_t count)
 976{
 977        struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
 978        struct ssb_bus *bus;
 979
 980        bus = ssb_pci_dev_to_bus(pdev);
 981        if (!bus)
 982                return -ENODEV;
 983
 984        return ssb_attr_sprom_store(bus, buf, count,
 985                                    sprom_check_crc, sprom_do_write);
 986}
 987
 988static DEVICE_ATTR(ssb_sprom, 0600,
 989                   ssb_pci_attr_sprom_show,
 990                   ssb_pci_attr_sprom_store);
 991
 992void ssb_pci_exit(struct ssb_bus *bus)
 993{
 994        struct pci_dev *pdev;
 995
 996        if (bus->bustype != SSB_BUSTYPE_PCI)
 997                return;
 998
 999        pdev = bus->host_pci;
1000        device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
1001}
1002
1003int ssb_pci_init(struct ssb_bus *bus)
1004{
1005        struct pci_dev *pdev;
1006        int err;
1007
1008        if (bus->bustype != SSB_BUSTYPE_PCI)
1009                return 0;
1010
1011        pdev = bus->host_pci;
1012        mutex_init(&bus->sprom_mutex);
1013        err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
1014        if (err)
1015                goto out;
1016
1017out:
1018        return err;
1019}
1020
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.