linux/drivers/ssb/pcmcia.c
<<
>>
Prefs
   1/*
   2 * Sonics Silicon Backplane
   3 * PCMCIA-Hostbus related functions
   4 *
   5 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
   6 * Copyright 2007-2008 Michael Buesch <m@bues.ch>
   7 *
   8 * Licensed under the GNU/GPL. See COPYING for details.
   9 */
  10
  11#include <linux/ssb/ssb.h>
  12#include <linux/delay.h>
  13#include <linux/io.h>
  14#include <linux/etherdevice.h>
  15
  16#include <pcmcia/cistpl.h>
  17#include <pcmcia/ciscode.h>
  18#include <pcmcia/ds.h>
  19#include <pcmcia/cisreg.h>
  20
  21#include "ssb_private.h"
  22
  23
  24/* Define the following to 1 to enable a printk on each coreswitch. */
  25#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG              0
  26
  27
  28/* PCMCIA configuration registers */
  29#define SSB_PCMCIA_ADDRESS0             0x2E
  30#define SSB_PCMCIA_ADDRESS1             0x30
  31#define SSB_PCMCIA_ADDRESS2             0x32
  32#define SSB_PCMCIA_MEMSEG               0x34
  33#define SSB_PCMCIA_SPROMCTL             0x36
  34#define  SSB_PCMCIA_SPROMCTL_IDLE       0
  35#define  SSB_PCMCIA_SPROMCTL_WRITE      1
  36#define  SSB_PCMCIA_SPROMCTL_READ       2
  37#define  SSB_PCMCIA_SPROMCTL_WRITEEN    4
  38#define  SSB_PCMCIA_SPROMCTL_WRITEDIS   7
  39#define  SSB_PCMCIA_SPROMCTL_DONE       8
  40#define SSB_PCMCIA_SPROM_DATALO         0x38
  41#define SSB_PCMCIA_SPROM_DATAHI         0x3A
  42#define SSB_PCMCIA_SPROM_ADDRLO         0x3C
  43#define SSB_PCMCIA_SPROM_ADDRHI         0x3E
  44
  45/* Hardware invariants CIS tuples */
  46#define SSB_PCMCIA_CIS                  0x80
  47#define  SSB_PCMCIA_CIS_ID              0x01
  48#define  SSB_PCMCIA_CIS_BOARDREV        0x02
  49#define  SSB_PCMCIA_CIS_PA              0x03
  50#define   SSB_PCMCIA_CIS_PA_PA0B0_LO    0
  51#define   SSB_PCMCIA_CIS_PA_PA0B0_HI    1
  52#define   SSB_PCMCIA_CIS_PA_PA0B1_LO    2
  53#define   SSB_PCMCIA_CIS_PA_PA0B1_HI    3
  54#define   SSB_PCMCIA_CIS_PA_PA0B2_LO    4
  55#define   SSB_PCMCIA_CIS_PA_PA0B2_HI    5
  56#define   SSB_PCMCIA_CIS_PA_ITSSI       6
  57#define   SSB_PCMCIA_CIS_PA_MAXPOW      7
  58#define  SSB_PCMCIA_CIS_OEMNAME         0x04
  59#define  SSB_PCMCIA_CIS_CCODE           0x05
  60#define  SSB_PCMCIA_CIS_ANTENNA         0x06
  61#define  SSB_PCMCIA_CIS_ANTGAIN         0x07
  62#define  SSB_PCMCIA_CIS_BFLAGS          0x08
  63#define  SSB_PCMCIA_CIS_LEDS            0x09
  64
  65/* PCMCIA SPROM size. */
  66#define SSB_PCMCIA_SPROM_SIZE           256
  67#define SSB_PCMCIA_SPROM_SIZE_BYTES     (SSB_PCMCIA_SPROM_SIZE * sizeof(u16))
  68
  69
  70/* Write to a PCMCIA configuration register. */
  71static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value)
  72{
  73        int res;
  74
  75        res = pcmcia_write_config_byte(bus->host_pcmcia, offset, value);
  76        if (unlikely(res != 0))
  77                return -EBUSY;
  78
  79        return 0;
  80}
  81
  82/* Read from a PCMCIA configuration register. */
  83static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value)
  84{
  85        int res;
  86
  87        res = pcmcia_read_config_byte(bus->host_pcmcia, offset, value);
  88        if (unlikely(res != 0))
  89                return -EBUSY;
  90
  91        return 0;
  92}
  93
  94int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
  95                              u8 coreidx)
  96{
  97        int err;
  98        int attempts = 0;
  99        u32 cur_core;
 100        u32 addr;
 101        u32 read_addr;
 102        u8 val;
 103
 104        addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
 105        while (1) {
 106                err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS0,
 107                                           (addr & 0x0000F000) >> 12);
 108                if (err)
 109                        goto error;
 110                err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS1,
 111                                           (addr & 0x00FF0000) >> 16);
 112                if (err)
 113                        goto error;
 114                err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS2,
 115                                           (addr & 0xFF000000) >> 24);
 116                if (err)
 117                        goto error;
 118
 119                read_addr = 0;
 120
 121                err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS0, &val);
 122                if (err)
 123                        goto error;
 124                read_addr |= ((u32)(val & 0x0F)) << 12;
 125                err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS1, &val);
 126                if (err)
 127                        goto error;
 128                read_addr |= ((u32)val) << 16;
 129                err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS2, &val);
 130                if (err)
 131                        goto error;
 132                read_addr |= ((u32)val) << 24;
 133
 134                cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
 135                if (cur_core == coreidx)
 136                        break;
 137
 138                err = -ETIMEDOUT;
 139                if (attempts++ > SSB_BAR0_MAX_RETRIES)
 140                        goto error;
 141                udelay(10);
 142        }
 143
 144        return 0;
 145error:
 146        ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
 147        return err;
 148}
 149
 150int ssb_pcmcia_switch_core(struct ssb_bus *bus,
 151                           struct ssb_device *dev)
 152{
 153        int err;
 154
 155#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
 156        ssb_printk(KERN_INFO PFX
 157                   "Switching to %s core, index %d\n",
 158                   ssb_core_name(dev->id.coreid),
 159                   dev->core_index);
 160#endif
 161
 162        err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
 163        if (!err)
 164                bus->mapped_device = dev;
 165
 166        return err;
 167}
 168
 169int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
 170{
 171        int attempts = 0;
 172        int err;
 173        u8 val;
 174
 175        SSB_WARN_ON((seg != 0) && (seg != 1));
 176        while (1) {
 177                err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_MEMSEG, seg);
 178                if (err)
 179                        goto error;
 180                err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_MEMSEG, &val);
 181                if (err)
 182                        goto error;
 183                if (val == seg)
 184                        break;
 185
 186                err = -ETIMEDOUT;
 187                if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
 188                        goto error;
 189                udelay(10);
 190        }
 191        bus->mapped_pcmcia_seg = seg;
 192
 193        return 0;
 194error:
 195        ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
 196        return err;
 197}
 198
 199static int select_core_and_segment(struct ssb_device *dev,
 200                                   u16 *offset)
 201{
 202        struct ssb_bus *bus = dev->bus;
 203        int err;
 204        u8 need_segment;
 205
 206        if (*offset >= 0x800) {
 207                *offset -= 0x800;
 208                need_segment = 1;
 209        } else
 210                need_segment = 0;
 211
 212        if (unlikely(dev != bus->mapped_device)) {
 213                err = ssb_pcmcia_switch_core(bus, dev);
 214                if (unlikely(err))
 215                        return err;
 216        }
 217        if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {
 218                err = ssb_pcmcia_switch_segment(bus, need_segment);
 219                if (unlikely(err))
 220                        return err;
 221        }
 222
 223        return 0;
 224}
 225
 226static u8 ssb_pcmcia_read8(struct ssb_device *dev, u16 offset)
 227{
 228        struct ssb_bus *bus = dev->bus;
 229        unsigned long flags;
 230        int err;
 231        u8 value = 0xFF;
 232
 233        spin_lock_irqsave(&bus->bar_lock, flags);
 234        err = select_core_and_segment(dev, &offset);
 235        if (likely(!err))
 236                value = readb(bus->mmio + offset);
 237        spin_unlock_irqrestore(&bus->bar_lock, flags);
 238
 239        return value;
 240}
 241
 242static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
 243{
 244        struct ssb_bus *bus = dev->bus;
 245        unsigned long flags;
 246        int err;
 247        u16 value = 0xFFFF;
 248
 249        spin_lock_irqsave(&bus->bar_lock, flags);
 250        err = select_core_and_segment(dev, &offset);
 251        if (likely(!err))
 252                value = readw(bus->mmio + offset);
 253        spin_unlock_irqrestore(&bus->bar_lock, flags);
 254
 255        return value;
 256}
 257
 258static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
 259{
 260        struct ssb_bus *bus = dev->bus;
 261        unsigned long flags;
 262        int err;
 263        u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
 264
 265        spin_lock_irqsave(&bus->bar_lock, flags);
 266        err = select_core_and_segment(dev, &offset);
 267        if (likely(!err)) {
 268                lo = readw(bus->mmio + offset);
 269                hi = readw(bus->mmio + offset + 2);
 270        }
 271        spin_unlock_irqrestore(&bus->bar_lock, flags);
 272
 273        return (lo | (hi << 16));
 274}
 275
 276#ifdef CONFIG_SSB_BLOCKIO
 277static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer,
 278                                  size_t count, u16 offset, u8 reg_width)
 279{
 280        struct ssb_bus *bus = dev->bus;
 281        unsigned long flags;
 282        void __iomem *addr = bus->mmio + offset;
 283        int err;
 284
 285        spin_lock_irqsave(&bus->bar_lock, flags);
 286        err = select_core_and_segment(dev, &offset);
 287        if (unlikely(err)) {
 288                memset(buffer, 0xFF, count);
 289                goto unlock;
 290        }
 291        switch (reg_width) {
 292        case sizeof(u8): {
 293                u8 *buf = buffer;
 294
 295                while (count) {
 296                        *buf = __raw_readb(addr);
 297                        buf++;
 298                        count--;
 299                }
 300                break;
 301        }
 302        case sizeof(u16): {
 303                __le16 *buf = buffer;
 304
 305                SSB_WARN_ON(count & 1);
 306                while (count) {
 307                        *buf = (__force __le16)__raw_readw(addr);
 308                        buf++;
 309                        count -= 2;
 310                }
 311                break;
 312        }
 313        case sizeof(u32): {
 314                __le16 *buf = buffer;
 315
 316                SSB_WARN_ON(count & 3);
 317                while (count) {
 318                        *buf = (__force __le16)__raw_readw(addr);
 319                        buf++;
 320                        *buf = (__force __le16)__raw_readw(addr + 2);
 321                        buf++;
 322                        count -= 4;
 323                }
 324                break;
 325        }
 326        default:
 327                SSB_WARN_ON(1);
 328        }
 329unlock:
 330        spin_unlock_irqrestore(&bus->bar_lock, flags);
 331}
 332#endif /* CONFIG_SSB_BLOCKIO */
 333
 334static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value)
 335{
 336        struct ssb_bus *bus = dev->bus;
 337        unsigned long flags;
 338        int err;
 339
 340        spin_lock_irqsave(&bus->bar_lock, flags);
 341        err = select_core_and_segment(dev, &offset);
 342        if (likely(!err))
 343                writeb(value, bus->mmio + offset);
 344        mmiowb();
 345        spin_unlock_irqrestore(&bus->bar_lock, flags);
 346}
 347
 348static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
 349{
 350        struct ssb_bus *bus = dev->bus;
 351        unsigned long flags;
 352        int err;
 353
 354        spin_lock_irqsave(&bus->bar_lock, flags);
 355        err = select_core_and_segment(dev, &offset);
 356        if (likely(!err))
 357                writew(value, bus->mmio + offset);
 358        mmiowb();
 359        spin_unlock_irqrestore(&bus->bar_lock, flags);
 360}
 361
 362static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
 363{
 364        struct ssb_bus *bus = dev->bus;
 365        unsigned long flags;
 366        int err;
 367
 368        spin_lock_irqsave(&bus->bar_lock, flags);
 369        err = select_core_and_segment(dev, &offset);
 370        if (likely(!err)) {
 371                writew((value & 0x0000FFFF), bus->mmio + offset);
 372                writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
 373        }
 374        mmiowb();
 375        spin_unlock_irqrestore(&bus->bar_lock, flags);
 376}
 377
 378#ifdef CONFIG_SSB_BLOCKIO
 379static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer,
 380                                   size_t count, u16 offset, u8 reg_width)
 381{
 382        struct ssb_bus *bus = dev->bus;
 383        unsigned long flags;
 384        void __iomem *addr = bus->mmio + offset;
 385        int err;
 386
 387        spin_lock_irqsave(&bus->bar_lock, flags);
 388        err = select_core_and_segment(dev, &offset);
 389        if (unlikely(err))
 390                goto unlock;
 391        switch (reg_width) {
 392        case sizeof(u8): {
 393                const u8 *buf = buffer;
 394
 395                while (count) {
 396                        __raw_writeb(*buf, addr);
 397                        buf++;
 398                        count--;
 399                }
 400                break;
 401        }
 402        case sizeof(u16): {
 403                const __le16 *buf = buffer;
 404
 405                SSB_WARN_ON(count & 1);
 406                while (count) {
 407                        __raw_writew((__force u16)(*buf), addr);
 408                        buf++;
 409                        count -= 2;
 410                }
 411                break;
 412        }
 413        case sizeof(u32): {
 414                const __le16 *buf = buffer;
 415
 416                SSB_WARN_ON(count & 3);
 417                while (count) {
 418                        __raw_writew((__force u16)(*buf), addr);
 419                        buf++;
 420                        __raw_writew((__force u16)(*buf), addr + 2);
 421                        buf++;
 422                        count -= 4;
 423                }
 424                break;
 425        }
 426        default:
 427                SSB_WARN_ON(1);
 428        }
 429unlock:
 430        mmiowb();
 431        spin_unlock_irqrestore(&bus->bar_lock, flags);
 432}
 433#endif /* CONFIG_SSB_BLOCKIO */
 434
 435/* Not "static", as it's used in main.c */
 436const struct ssb_bus_ops ssb_pcmcia_ops = {
 437        .read8          = ssb_pcmcia_read8,
 438        .read16         = ssb_pcmcia_read16,
 439        .read32         = ssb_pcmcia_read32,
 440        .write8         = ssb_pcmcia_write8,
 441        .write16        = ssb_pcmcia_write16,
 442        .write32        = ssb_pcmcia_write32,
 443#ifdef CONFIG_SSB_BLOCKIO
 444        .block_read     = ssb_pcmcia_block_read,
 445        .block_write    = ssb_pcmcia_block_write,
 446#endif
 447};
 448
 449static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command)
 450{
 451        unsigned int i;
 452        int err;
 453        u8 value;
 454
 455        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROMCTL, command);
 456        if (err)
 457                return err;
 458        for (i = 0; i < 1000; i++) {
 459                err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROMCTL, &value);
 460                if (err)
 461                        return err;
 462                if (value & SSB_PCMCIA_SPROMCTL_DONE)
 463                        return 0;
 464                udelay(10);
 465        }
 466
 467        return -ETIMEDOUT;
 468}
 469
 470/* offset is the 16bit word offset */
 471static int ssb_pcmcia_sprom_read(struct ssb_bus *bus, u16 offset, u16 *value)
 472{
 473        int err;
 474        u8 lo, hi;
 475
 476        offset *= 2; /* Make byte offset */
 477
 478        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,
 479                                   (offset & 0x00FF));
 480        if (err)
 481                return err;
 482        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,
 483                                   (offset & 0xFF00) >> 8);
 484        if (err)
 485                return err;
 486        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_READ);
 487        if (err)
 488                return err;
 489        err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATALO, &lo);
 490        if (err)
 491                return err;
 492        err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATAHI, &hi);
 493        if (err)
 494                return err;
 495        *value = (lo | (((u16)hi) << 8));
 496
 497        return 0;
 498}
 499
 500/* offset is the 16bit word offset */
 501static int ssb_pcmcia_sprom_write(struct ssb_bus *bus, u16 offset, u16 value)
 502{
 503        int err;
 504
 505        offset *= 2; /* Make byte offset */
 506
 507        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,
 508                                   (offset & 0x00FF));
 509        if (err)
 510                return err;
 511        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,
 512                                   (offset & 0xFF00) >> 8);
 513        if (err)
 514                return err;
 515        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATALO,
 516                                   (value & 0x00FF));
 517        if (err)
 518                return err;
 519        err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATAHI,
 520                                   (value & 0xFF00) >> 8);
 521        if (err)
 522                return err;
 523        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITE);
 524        if (err)
 525                return err;
 526        msleep(20);
 527
 528        return 0;
 529}
 530
 531/* Read the SPROM image. bufsize is in 16bit words. */
 532static int ssb_pcmcia_sprom_read_all(struct ssb_bus *bus, u16 *sprom)
 533{
 534        int err, i;
 535
 536        for (i = 0; i < SSB_PCMCIA_SPROM_SIZE; i++) {
 537                err = ssb_pcmcia_sprom_read(bus, i, &sprom[i]);
 538                if (err)
 539                        return err;
 540        }
 541
 542        return 0;
 543}
 544
 545/* Write the SPROM image. size is in 16bit words. */
 546static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
 547{
 548        int i, err;
 549        bool failed = 0;
 550        size_t size = SSB_PCMCIA_SPROM_SIZE;
 551
 552        ssb_printk(KERN_NOTICE PFX
 553                   "Writing SPROM. Do NOT turn off the power! "
 554                   "Please stand by...\n");
 555        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);
 556        if (err) {
 557                ssb_printk(KERN_NOTICE PFX
 558                           "Could not enable SPROM write access.\n");
 559                return -EBUSY;
 560        }
 561        ssb_printk(KERN_NOTICE PFX "[ 0%%");
 562        msleep(500);
 563        for (i = 0; i < size; i++) {
 564                if (i == size / 4)
 565                        ssb_printk("25%%");
 566                else if (i == size / 2)
 567                        ssb_printk("50%%");
 568                else if (i == (size * 3) / 4)
 569                        ssb_printk("75%%");
 570                else if (i % 2)
 571                        ssb_printk(".");
 572                err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
 573                if (err) {
 574                        ssb_printk(KERN_NOTICE PFX
 575                                   "Failed to write to SPROM.\n");
 576                        failed = 1;
 577                        break;
 578                }
 579        }
 580        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
 581        if (err) {
 582                ssb_printk(KERN_NOTICE PFX
 583                           "Could not disable SPROM write access.\n");
 584                failed = 1;
 585        }
 586        msleep(500);
 587        if (!failed) {
 588                ssb_printk("100%% ]\n");
 589                ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
 590        }
 591
 592        return failed ? -EBUSY : 0;
 593}
 594
 595static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size)
 596{
 597        //TODO
 598        return 0;
 599}
 600
 601#define GOTO_ERROR_ON(condition, description) do {      \
 602        if (unlikely(condition)) {                      \
 603                error_description = description;        \
 604                goto error;                             \
 605        }                                               \
 606  } while (0)
 607
 608static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
 609                        tuple_t *tuple,
 610                        void *priv)
 611{
 612        struct ssb_sprom *sprom = priv;
 613
 614        if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
 615                return -EINVAL;
 616        if (tuple->TupleDataLen != ETH_ALEN + 2)
 617                return -EINVAL;
 618        if (tuple->TupleData[1] != ETH_ALEN)
 619                return -EINVAL;
 620        memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN);
 621        return 0;
 622};
 623
 624static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
 625                                        tuple_t *tuple,
 626                                        void *priv)
 627{
 628        struct ssb_init_invariants *iv = priv;
 629        struct ssb_sprom *sprom = &iv->sprom;
 630        struct ssb_boardinfo *bi = &iv->boardinfo;
 631        const char *error_description;
 632
 633        GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1");
 634        switch (tuple->TupleData[0]) {
 635        case SSB_PCMCIA_CIS_ID:
 636                GOTO_ERROR_ON((tuple->TupleDataLen != 5) &&
 637                              (tuple->TupleDataLen != 7),
 638                              "id tpl size");
 639                bi->vendor = tuple->TupleData[1] |
 640                        ((u16)tuple->TupleData[2] << 8);
 641                break;
 642        case SSB_PCMCIA_CIS_BOARDREV:
 643                GOTO_ERROR_ON(tuple->TupleDataLen != 2,
 644                        "boardrev tpl size");
 645                sprom->board_rev = tuple->TupleData[1];
 646                break;
 647        case SSB_PCMCIA_CIS_PA:
 648                GOTO_ERROR_ON((tuple->TupleDataLen != 9) &&
 649                        (tuple->TupleDataLen != 10),
 650                        "pa tpl size");
 651                sprom->pa0b0 = tuple->TupleData[1] |
 652                        ((u16)tuple->TupleData[2] << 8);
 653                sprom->pa0b1 = tuple->TupleData[3] |
 654                        ((u16)tuple->TupleData[4] << 8);
 655                sprom->pa0b2 = tuple->TupleData[5] |
 656                        ((u16)tuple->TupleData[6] << 8);
 657                sprom->itssi_a = tuple->TupleData[7];
 658                sprom->itssi_bg = tuple->TupleData[7];
 659                sprom->maxpwr_a = tuple->TupleData[8];
 660                sprom->maxpwr_bg = tuple->TupleData[8];
 661                break;
 662        case SSB_PCMCIA_CIS_OEMNAME:
 663                /* We ignore this. */
 664                break;
 665        case SSB_PCMCIA_CIS_CCODE:
 666                GOTO_ERROR_ON(tuple->TupleDataLen != 2,
 667                        "ccode tpl size");
 668                sprom->country_code = tuple->TupleData[1];
 669                break;
 670        case SSB_PCMCIA_CIS_ANTENNA:
 671                GOTO_ERROR_ON(tuple->TupleDataLen != 2,
 672                        "ant tpl size");
 673                sprom->ant_available_a = tuple->TupleData[1];
 674                sprom->ant_available_bg = tuple->TupleData[1];
 675                break;
 676        case SSB_PCMCIA_CIS_ANTGAIN:
 677                GOTO_ERROR_ON(tuple->TupleDataLen != 2,
 678                        "antg tpl size");
 679                sprom->antenna_gain.a0 = tuple->TupleData[1];
 680                sprom->antenna_gain.a1 = tuple->TupleData[1];
 681                sprom->antenna_gain.a2 = tuple->TupleData[1];
 682                sprom->antenna_gain.a3 = tuple->TupleData[1];
 683                break;
 684        case SSB_PCMCIA_CIS_BFLAGS:
 685                GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&
 686                        (tuple->TupleDataLen != 5),
 687                        "bfl tpl size");
 688                sprom->boardflags_lo = tuple->TupleData[1] |
 689                        ((u16)tuple->TupleData[2] << 8);
 690                break;
 691        case SSB_PCMCIA_CIS_LEDS:
 692                GOTO_ERROR_ON(tuple->TupleDataLen != 5,
 693                        "leds tpl size");
 694                sprom->gpio0 = tuple->TupleData[1];
 695                sprom->gpio1 = tuple->TupleData[2];
 696                sprom->gpio2 = tuple->TupleData[3];
 697                sprom->gpio3 = tuple->TupleData[4];
 698                break;
 699        }
 700        return -ENOSPC; /* continue with next entry */
 701
 702error:
 703        ssb_printk(KERN_ERR PFX
 704                   "PCMCIA: Failed to fetch device invariants: %s\n",
 705                   error_description);
 706        return -ENODEV;
 707}
 708
 709
 710int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 711                              struct ssb_init_invariants *iv)
 712{
 713        struct ssb_sprom *sprom = &iv->sprom;
 714        int res;
 715
 716        memset(sprom, 0xFF, sizeof(*sprom));
 717        sprom->revision = 1;
 718        sprom->boardflags_lo = 0;
 719        sprom->boardflags_hi = 0;
 720
 721        /* First fetch the MAC address. */
 722        res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
 723                                ssb_pcmcia_get_mac, sprom);
 724        if (res != 0) {
 725                ssb_printk(KERN_ERR PFX
 726                        "PCMCIA: Failed to fetch MAC address\n");
 727                return -ENODEV;
 728        }
 729
 730        /* Fetch the vendor specific tuples. */
 731        res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
 732                                ssb_pcmcia_do_get_invariants, iv);
 733        if ((res == 0) || (res == -ENOSPC))
 734                return 0;
 735
 736        ssb_printk(KERN_ERR PFX
 737                        "PCMCIA: Failed to fetch device invariants\n");
 738        return -ENODEV;
 739}
 740
 741static ssize_t ssb_pcmcia_attr_sprom_show(struct device *pcmciadev,
 742                                          struct device_attribute *attr,
 743                                          char *buf)
 744{
 745        struct pcmcia_device *pdev =
 746                container_of(pcmciadev, struct pcmcia_device, dev);
 747        struct ssb_bus *bus;
 748
 749        bus = ssb_pcmcia_dev_to_bus(pdev);
 750        if (!bus)
 751                return -ENODEV;
 752
 753        return ssb_attr_sprom_show(bus, buf,
 754                                   ssb_pcmcia_sprom_read_all);
 755}
 756
 757static ssize_t ssb_pcmcia_attr_sprom_store(struct device *pcmciadev,
 758                                           struct device_attribute *attr,
 759                                           const char *buf, size_t count)
 760{
 761        struct pcmcia_device *pdev =
 762                container_of(pcmciadev, struct pcmcia_device, dev);
 763        struct ssb_bus *bus;
 764
 765        bus = ssb_pcmcia_dev_to_bus(pdev);
 766        if (!bus)
 767                return -ENODEV;
 768
 769        return ssb_attr_sprom_store(bus, buf, count,
 770                                    ssb_pcmcia_sprom_check_crc,
 771                                    ssb_pcmcia_sprom_write_all);
 772}
 773
 774static DEVICE_ATTR(ssb_sprom, 0600,
 775                   ssb_pcmcia_attr_sprom_show,
 776                   ssb_pcmcia_attr_sprom_store);
 777
 778static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor)
 779{
 780        u8 val;
 781        int err;
 782
 783        err = ssb_pcmcia_cfg_read(bus, cor, &val);
 784        if (err)
 785                return err;
 786        val &= ~COR_SOFT_RESET;
 787        val |= COR_FUNC_ENA | COR_IREQ_ENA | COR_LEVEL_REQ;
 788        err = ssb_pcmcia_cfg_write(bus, cor, val);
 789        if (err)
 790                return err;
 791        msleep(40);
 792
 793        return 0;
 794}
 795
 796/* Initialize the PCMCIA hardware. This is called on Init and Resume. */
 797int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)
 798{
 799        int err;
 800
 801        if (bus->bustype != SSB_BUSTYPE_PCMCIA)
 802                return 0;
 803
 804        /* Switch segment to a known state and sync
 805         * bus->mapped_pcmcia_seg with hardware state. */
 806        ssb_pcmcia_switch_segment(bus, 0);
 807        /* Init the COR register. */
 808        err = ssb_pcmcia_cor_setup(bus, CISREG_COR);
 809        if (err)
 810                return err;
 811        /* Some cards also need this register to get poked. */
 812        err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);
 813        if (err)
 814                return err;
 815
 816        return 0;
 817}
 818
 819void ssb_pcmcia_exit(struct ssb_bus *bus)
 820{
 821        if (bus->bustype != SSB_BUSTYPE_PCMCIA)
 822                return;
 823
 824        device_remove_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);
 825}
 826
 827int ssb_pcmcia_init(struct ssb_bus *bus)
 828{
 829        int err;
 830
 831        if (bus->bustype != SSB_BUSTYPE_PCMCIA)
 832                return 0;
 833
 834        err = ssb_pcmcia_hardware_setup(bus);
 835        if (err)
 836                goto error;
 837
 838        bus->sprom_size = SSB_PCMCIA_SPROM_SIZE;
 839        mutex_init(&bus->sprom_mutex);
 840        err = device_create_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);
 841        if (err)
 842                goto error;
 843
 844        return 0;
 845error:
 846        ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n");
 847        return err;
 848}
 849
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.