161e115a5SMichael Buesch /* 261e115a5SMichael Buesch * Sonics Silicon Backplane 361e115a5SMichael Buesch * PCMCIA-Hostbus related functions 461e115a5SMichael Buesch * 561e115a5SMichael Buesch * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 6eb032b98SMichael Büsch * Copyright 2007-2008 Michael Buesch <m@bues.ch> 761e115a5SMichael Buesch * 861e115a5SMichael Buesch * Licensed under the GNU/GPL. See COPYING for details. 961e115a5SMichael Buesch */ 1061e115a5SMichael Buesch 11b8b6069cSMichael Büsch #include "ssb_private.h" 12b8b6069cSMichael Büsch 1361e115a5SMichael Buesch #include <linux/ssb/ssb.h> 1461e115a5SMichael Buesch #include <linux/delay.h> 15409f2435SAl Viro #include <linux/io.h> 16e7ec2e32SMichael Buesch #include <linux/etherdevice.h> 1761e115a5SMichael Buesch 1861e115a5SMichael Buesch #include <pcmcia/cistpl.h> 1961e115a5SMichael Buesch #include <pcmcia/ciscode.h> 2061e115a5SMichael Buesch #include <pcmcia/ds.h> 2161e115a5SMichael Buesch #include <pcmcia/cisreg.h> 2261e115a5SMichael Buesch 2361e115a5SMichael Buesch 2461e115a5SMichael Buesch /* Define the following to 1 to enable a printk on each coreswitch. */ 2561e115a5SMichael Buesch #define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0 2661e115a5SMichael Buesch 2761e115a5SMichael Buesch 28e7ec2e32SMichael Buesch /* PCMCIA configuration registers */ 29e7ec2e32SMichael Buesch #define SSB_PCMCIA_ADDRESS0 0x2E 30e7ec2e32SMichael Buesch #define SSB_PCMCIA_ADDRESS1 0x30 31e7ec2e32SMichael Buesch #define SSB_PCMCIA_ADDRESS2 0x32 32e7ec2e32SMichael Buesch #define SSB_PCMCIA_MEMSEG 0x34 33e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL 0x36 34e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL_IDLE 0 35e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL_WRITE 1 36e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL_READ 2 37e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL_WRITEEN 4 38e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL_WRITEDIS 7 39e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROMCTL_DONE 8 40e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROM_DATALO 0x38 41e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROM_DATAHI 0x3A 42e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROM_ADDRLO 0x3C 43e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROM_ADDRHI 0x3E 44e7ec2e32SMichael Buesch 45e7ec2e32SMichael Buesch /* Hardware invariants CIS tuples */ 46e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS 0x80 47e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_ID 0x01 48e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_BOARDREV 0x02 49e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA 0x03 50e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_PA0B0_LO 0 51e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_PA0B0_HI 1 52e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_PA0B1_LO 2 53e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_PA0B1_HI 3 54e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_PA0B2_LO 4 55e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_PA0B2_HI 5 56e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_ITSSI 6 57e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_PA_MAXPOW 7 58e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_OEMNAME 0x04 59e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_CCODE 0x05 60e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_ANTENNA 0x06 61e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_ANTGAIN 0x07 62e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_BFLAGS 0x08 63e7ec2e32SMichael Buesch #define SSB_PCMCIA_CIS_LEDS 0x09 64e7ec2e32SMichael Buesch 65e7ec2e32SMichael Buesch /* PCMCIA SPROM size. */ 66e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROM_SIZE 256 67e7ec2e32SMichael Buesch #define SSB_PCMCIA_SPROM_SIZE_BYTES (SSB_PCMCIA_SPROM_SIZE * sizeof(u16)) 68e7ec2e32SMichael Buesch 69e7ec2e32SMichael Buesch 70e7ec2e32SMichael Buesch /* Write to a PCMCIA configuration register. */ 71e7ec2e32SMichael Buesch static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value) 72e7ec2e32SMichael Buesch { 73e7ec2e32SMichael Buesch int res; 74e7ec2e32SMichael Buesch 751d5cc192SDominik Brodowski res = pcmcia_write_config_byte(bus->host_pcmcia, offset, value); 764c89e88bSDominik Brodowski if (unlikely(res != 0)) 77e7ec2e32SMichael Buesch return -EBUSY; 78e7ec2e32SMichael Buesch 79e7ec2e32SMichael Buesch return 0; 80e7ec2e32SMichael Buesch } 81e7ec2e32SMichael Buesch 82e7ec2e32SMichael Buesch /* Read from a PCMCIA configuration register. */ 83e7ec2e32SMichael Buesch static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value) 84e7ec2e32SMichael Buesch { 85e7ec2e32SMichael Buesch int res; 86e7ec2e32SMichael Buesch 871d5cc192SDominik Brodowski res = pcmcia_read_config_byte(bus->host_pcmcia, offset, value); 884c89e88bSDominik Brodowski if (unlikely(res != 0)) 89e7ec2e32SMichael Buesch return -EBUSY; 90e7ec2e32SMichael Buesch 91e7ec2e32SMichael Buesch return 0; 92e7ec2e32SMichael Buesch } 93e7ec2e32SMichael Buesch 9461e115a5SMichael Buesch int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, 9561e115a5SMichael Buesch u8 coreidx) 9661e115a5SMichael Buesch { 9761e115a5SMichael Buesch int err; 9861e115a5SMichael Buesch int attempts = 0; 9961e115a5SMichael Buesch u32 cur_core; 10061e115a5SMichael Buesch u32 addr; 10161e115a5SMichael Buesch u32 read_addr; 102e7ec2e32SMichael Buesch u8 val; 10361e115a5SMichael Buesch 10461e115a5SMichael Buesch addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; 10561e115a5SMichael Buesch while (1) { 106e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS0, 107e7ec2e32SMichael Buesch (addr & 0x0000F000) >> 12); 108e7ec2e32SMichael Buesch if (err) 10961e115a5SMichael Buesch goto error; 110e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS1, 111e7ec2e32SMichael Buesch (addr & 0x00FF0000) >> 16); 112e7ec2e32SMichael Buesch if (err) 11361e115a5SMichael Buesch goto error; 114e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS2, 115e7ec2e32SMichael Buesch (addr & 0xFF000000) >> 24); 116e7ec2e32SMichael Buesch if (err) 11761e115a5SMichael Buesch goto error; 11861e115a5SMichael Buesch 11961e115a5SMichael Buesch read_addr = 0; 12061e115a5SMichael Buesch 121e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS0, &val); 122e7ec2e32SMichael Buesch if (err) 12361e115a5SMichael Buesch goto error; 124e7ec2e32SMichael Buesch read_addr |= ((u32)(val & 0x0F)) << 12; 125e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS1, &val); 126e7ec2e32SMichael Buesch if (err) 12761e115a5SMichael Buesch goto error; 128e7ec2e32SMichael Buesch read_addr |= ((u32)val) << 16; 129e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS2, &val); 130e7ec2e32SMichael Buesch if (err) 13161e115a5SMichael Buesch goto error; 132e7ec2e32SMichael Buesch read_addr |= ((u32)val) << 24; 13361e115a5SMichael Buesch 13461e115a5SMichael Buesch cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE; 13561e115a5SMichael Buesch if (cur_core == coreidx) 13661e115a5SMichael Buesch break; 13761e115a5SMichael Buesch 138e7ec2e32SMichael Buesch err = -ETIMEDOUT; 13961e115a5SMichael Buesch if (attempts++ > SSB_BAR0_MAX_RETRIES) 14061e115a5SMichael Buesch goto error; 14161e115a5SMichael Buesch udelay(10); 14261e115a5SMichael Buesch } 14361e115a5SMichael Buesch 14461e115a5SMichael Buesch return 0; 14561e115a5SMichael Buesch error: 146b8b6069cSMichael Büsch pr_err("Failed to switch to core %u\n", coreidx); 147e7ec2e32SMichael Buesch return err; 14861e115a5SMichael Buesch } 14961e115a5SMichael Buesch 150cf75496bSRafał Miłecki static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev) 15161e115a5SMichael Buesch { 15261e115a5SMichael Buesch int err; 15361e115a5SMichael Buesch 15461e115a5SMichael Buesch #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 155b8b6069cSMichael Büsch pr_info("Switching to %s core, index %d\n", 156b8b6069cSMichael Büsch ssb_core_name(dev->id.coreid), dev->core_index); 15761e115a5SMichael Buesch #endif 15861e115a5SMichael Buesch 15961e115a5SMichael Buesch err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); 16061e115a5SMichael Buesch if (!err) 16161e115a5SMichael Buesch bus->mapped_device = dev; 16261e115a5SMichael Buesch 16361e115a5SMichael Buesch return err; 16461e115a5SMichael Buesch } 16561e115a5SMichael Buesch 16661e115a5SMichael Buesch int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) 16761e115a5SMichael Buesch { 16861e115a5SMichael Buesch int attempts = 0; 169e7ec2e32SMichael Buesch int err; 170e7ec2e32SMichael Buesch u8 val; 17161e115a5SMichael Buesch 172209b4375SMichael Büsch WARN_ON((seg != 0) && (seg != 1)); 17361e115a5SMichael Buesch while (1) { 174e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_MEMSEG, seg); 175e7ec2e32SMichael Buesch if (err) 17661e115a5SMichael Buesch goto error; 177e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_MEMSEG, &val); 178e7ec2e32SMichael Buesch if (err) 17961e115a5SMichael Buesch goto error; 180e7ec2e32SMichael Buesch if (val == seg) 18161e115a5SMichael Buesch break; 18261e115a5SMichael Buesch 183e7ec2e32SMichael Buesch err = -ETIMEDOUT; 18461e115a5SMichael Buesch if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES)) 18561e115a5SMichael Buesch goto error; 18661e115a5SMichael Buesch udelay(10); 18761e115a5SMichael Buesch } 18861e115a5SMichael Buesch bus->mapped_pcmcia_seg = seg; 189993e1c78SMichael Buesch 190993e1c78SMichael Buesch return 0; 19161e115a5SMichael Buesch error: 192b8b6069cSMichael Büsch pr_err("Failed to switch pcmcia segment\n"); 193e7ec2e32SMichael Buesch return err; 19461e115a5SMichael Buesch } 19561e115a5SMichael Buesch 19660d78c44SMichael Buesch static int select_core_and_segment(struct ssb_device *dev, 19761e115a5SMichael Buesch u16 *offset) 19861e115a5SMichael Buesch { 19960d78c44SMichael Buesch struct ssb_bus *bus = dev->bus; 20061e115a5SMichael Buesch int err; 20160d78c44SMichael Buesch u8 need_segment; 20260d78c44SMichael Buesch 20360d78c44SMichael Buesch if (*offset >= 0x800) { 20460d78c44SMichael Buesch *offset -= 0x800; 20560d78c44SMichael Buesch need_segment = 1; 20660d78c44SMichael Buesch } else 20760d78c44SMichael Buesch need_segment = 0; 20861e115a5SMichael Buesch 20961e115a5SMichael Buesch if (unlikely(dev != bus->mapped_device)) { 21061e115a5SMichael Buesch err = ssb_pcmcia_switch_core(bus, dev); 21161e115a5SMichael Buesch if (unlikely(err)) 21261e115a5SMichael Buesch return err; 21361e115a5SMichael Buesch } 21460d78c44SMichael Buesch if (unlikely(need_segment != bus->mapped_pcmcia_seg)) { 21560d78c44SMichael Buesch err = ssb_pcmcia_switch_segment(bus, need_segment); 21661e115a5SMichael Buesch if (unlikely(err)) 21761e115a5SMichael Buesch return err; 21861e115a5SMichael Buesch } 21961e115a5SMichael Buesch 22061e115a5SMichael Buesch return 0; 22161e115a5SMichael Buesch } 22261e115a5SMichael Buesch 223ffc7689dSMichael Buesch static u8 ssb_pcmcia_read8(struct ssb_device *dev, u16 offset) 224ffc7689dSMichael Buesch { 225ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 226ffc7689dSMichael Buesch unsigned long flags; 227ffc7689dSMichael Buesch int err; 228ffc7689dSMichael Buesch u8 value = 0xFF; 229ffc7689dSMichael Buesch 230ffc7689dSMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 231ffc7689dSMichael Buesch err = select_core_and_segment(dev, &offset); 232ffc7689dSMichael Buesch if (likely(!err)) 233ffc7689dSMichael Buesch value = readb(bus->mmio + offset); 234ffc7689dSMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 235ffc7689dSMichael Buesch 236ffc7689dSMichael Buesch return value; 237ffc7689dSMichael Buesch } 238ffc7689dSMichael Buesch 23961e115a5SMichael Buesch static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) 24061e115a5SMichael Buesch { 24161e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 242993e1c78SMichael Buesch unsigned long flags; 243993e1c78SMichael Buesch int err; 244993e1c78SMichael Buesch u16 value = 0xFFFF; 24561e115a5SMichael Buesch 246993e1c78SMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 247993e1c78SMichael Buesch err = select_core_and_segment(dev, &offset); 248993e1c78SMichael Buesch if (likely(!err)) 249993e1c78SMichael Buesch value = readw(bus->mmio + offset); 250993e1c78SMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 25161e115a5SMichael Buesch 252993e1c78SMichael Buesch return value; 25361e115a5SMichael Buesch } 25461e115a5SMichael Buesch 25561e115a5SMichael Buesch static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) 25661e115a5SMichael Buesch { 25761e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 258993e1c78SMichael Buesch unsigned long flags; 259993e1c78SMichael Buesch int err; 260993e1c78SMichael Buesch u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF; 26161e115a5SMichael Buesch 262993e1c78SMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 263993e1c78SMichael Buesch err = select_core_and_segment(dev, &offset); 264993e1c78SMichael Buesch if (likely(!err)) { 26560d78c44SMichael Buesch lo = readw(bus->mmio + offset); 26660d78c44SMichael Buesch hi = readw(bus->mmio + offset + 2); 267993e1c78SMichael Buesch } 268993e1c78SMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 26961e115a5SMichael Buesch 27060d78c44SMichael Buesch return (lo | (hi << 16)); 27161e115a5SMichael Buesch } 27261e115a5SMichael Buesch 273d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 274d625a29bSMichael Buesch static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer, 275d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 276d625a29bSMichael Buesch { 277d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 278d625a29bSMichael Buesch unsigned long flags; 279d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 280d625a29bSMichael Buesch int err; 281d625a29bSMichael Buesch 282d625a29bSMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 283d625a29bSMichael Buesch err = select_core_and_segment(dev, &offset); 284d625a29bSMichael Buesch if (unlikely(err)) { 285d625a29bSMichael Buesch memset(buffer, 0xFF, count); 286d625a29bSMichael Buesch goto unlock; 287d625a29bSMichael Buesch } 288d625a29bSMichael Buesch switch (reg_width) { 289d625a29bSMichael Buesch case sizeof(u8): { 290d625a29bSMichael Buesch u8 *buf = buffer; 291d625a29bSMichael Buesch 292d625a29bSMichael Buesch while (count) { 293d625a29bSMichael Buesch *buf = __raw_readb(addr); 294d625a29bSMichael Buesch buf++; 295d625a29bSMichael Buesch count--; 296d625a29bSMichael Buesch } 297d625a29bSMichael Buesch break; 298d625a29bSMichael Buesch } 299d625a29bSMichael Buesch case sizeof(u16): { 300d625a29bSMichael Buesch __le16 *buf = buffer; 301d625a29bSMichael Buesch 302209b4375SMichael Büsch WARN_ON(count & 1); 303d625a29bSMichael Buesch while (count) { 304d625a29bSMichael Buesch *buf = (__force __le16)__raw_readw(addr); 305d625a29bSMichael Buesch buf++; 306d625a29bSMichael Buesch count -= 2; 307d625a29bSMichael Buesch } 308d625a29bSMichael Buesch break; 309d625a29bSMichael Buesch } 310d625a29bSMichael Buesch case sizeof(u32): { 311d625a29bSMichael Buesch __le16 *buf = buffer; 312d625a29bSMichael Buesch 313209b4375SMichael Büsch WARN_ON(count & 3); 314d625a29bSMichael Buesch while (count) { 315d625a29bSMichael Buesch *buf = (__force __le16)__raw_readw(addr); 316d625a29bSMichael Buesch buf++; 317d625a29bSMichael Buesch *buf = (__force __le16)__raw_readw(addr + 2); 318d625a29bSMichael Buesch buf++; 319d625a29bSMichael Buesch count -= 4; 320d625a29bSMichael Buesch } 321d625a29bSMichael Buesch break; 322d625a29bSMichael Buesch } 323d625a29bSMichael Buesch default: 324209b4375SMichael Büsch WARN_ON(1); 325d625a29bSMichael Buesch } 326d625a29bSMichael Buesch unlock: 327d625a29bSMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 328d625a29bSMichael Buesch } 329d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 330d625a29bSMichael Buesch 331ffc7689dSMichael Buesch static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) 332ffc7689dSMichael Buesch { 333ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 334ffc7689dSMichael Buesch unsigned long flags; 335ffc7689dSMichael Buesch int err; 336ffc7689dSMichael Buesch 337ffc7689dSMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 338ffc7689dSMichael Buesch err = select_core_and_segment(dev, &offset); 339ffc7689dSMichael Buesch if (likely(!err)) 340ffc7689dSMichael Buesch writeb(value, bus->mmio + offset); 341ffc7689dSMichael Buesch mmiowb(); 342ffc7689dSMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 343ffc7689dSMichael Buesch } 344ffc7689dSMichael Buesch 34561e115a5SMichael Buesch static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) 34661e115a5SMichael Buesch { 34761e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 348993e1c78SMichael Buesch unsigned long flags; 349993e1c78SMichael Buesch int err; 35061e115a5SMichael Buesch 351993e1c78SMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 352993e1c78SMichael Buesch err = select_core_and_segment(dev, &offset); 353993e1c78SMichael Buesch if (likely(!err)) 35461e115a5SMichael Buesch writew(value, bus->mmio + offset); 355993e1c78SMichael Buesch mmiowb(); 356993e1c78SMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 35761e115a5SMichael Buesch } 35861e115a5SMichael Buesch 35961e115a5SMichael Buesch static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) 36061e115a5SMichael Buesch { 36161e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 362993e1c78SMichael Buesch unsigned long flags; 363993e1c78SMichael Buesch int err; 36461e115a5SMichael Buesch 365993e1c78SMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 366993e1c78SMichael Buesch err = select_core_and_segment(dev, &offset); 367993e1c78SMichael Buesch if (likely(!err)) { 368993e1c78SMichael Buesch writew((value & 0x0000FFFF), bus->mmio + offset); 369993e1c78SMichael Buesch writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2); 370993e1c78SMichael Buesch } 371993e1c78SMichael Buesch mmiowb(); 372993e1c78SMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 37361e115a5SMichael Buesch } 37461e115a5SMichael Buesch 375d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 376d625a29bSMichael Buesch static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer, 377d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 378d625a29bSMichael Buesch { 379d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 380d625a29bSMichael Buesch unsigned long flags; 381d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 382d625a29bSMichael Buesch int err; 383d625a29bSMichael Buesch 384d625a29bSMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 385d625a29bSMichael Buesch err = select_core_and_segment(dev, &offset); 386d625a29bSMichael Buesch if (unlikely(err)) 387d625a29bSMichael Buesch goto unlock; 388d625a29bSMichael Buesch switch (reg_width) { 389d625a29bSMichael Buesch case sizeof(u8): { 390d625a29bSMichael Buesch const u8 *buf = buffer; 391d625a29bSMichael Buesch 392d625a29bSMichael Buesch while (count) { 393d625a29bSMichael Buesch __raw_writeb(*buf, addr); 394d625a29bSMichael Buesch buf++; 395d625a29bSMichael Buesch count--; 396d625a29bSMichael Buesch } 397d625a29bSMichael Buesch break; 398d625a29bSMichael Buesch } 399d625a29bSMichael Buesch case sizeof(u16): { 400d625a29bSMichael Buesch const __le16 *buf = buffer; 401d625a29bSMichael Buesch 402209b4375SMichael Büsch WARN_ON(count & 1); 403d625a29bSMichael Buesch while (count) { 404d625a29bSMichael Buesch __raw_writew((__force u16)(*buf), addr); 405d625a29bSMichael Buesch buf++; 406d625a29bSMichael Buesch count -= 2; 407d625a29bSMichael Buesch } 408d625a29bSMichael Buesch break; 409d625a29bSMichael Buesch } 410d625a29bSMichael Buesch case sizeof(u32): { 411d625a29bSMichael Buesch const __le16 *buf = buffer; 412d625a29bSMichael Buesch 413209b4375SMichael Büsch WARN_ON(count & 3); 414d625a29bSMichael Buesch while (count) { 415d625a29bSMichael Buesch __raw_writew((__force u16)(*buf), addr); 416d625a29bSMichael Buesch buf++; 417d625a29bSMichael Buesch __raw_writew((__force u16)(*buf), addr + 2); 418d625a29bSMichael Buesch buf++; 419d625a29bSMichael Buesch count -= 4; 420d625a29bSMichael Buesch } 421d625a29bSMichael Buesch break; 422d625a29bSMichael Buesch } 423d625a29bSMichael Buesch default: 424209b4375SMichael Büsch WARN_ON(1); 425d625a29bSMichael Buesch } 426d625a29bSMichael Buesch unlock: 427d625a29bSMichael Buesch mmiowb(); 428d625a29bSMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 429d625a29bSMichael Buesch } 430d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 431d625a29bSMichael Buesch 43261e115a5SMichael Buesch /* Not "static", as it's used in main.c */ 43361e115a5SMichael Buesch const struct ssb_bus_ops ssb_pcmcia_ops = { 434ffc7689dSMichael Buesch .read8 = ssb_pcmcia_read8, 43561e115a5SMichael Buesch .read16 = ssb_pcmcia_read16, 43661e115a5SMichael Buesch .read32 = ssb_pcmcia_read32, 437ffc7689dSMichael Buesch .write8 = ssb_pcmcia_write8, 43861e115a5SMichael Buesch .write16 = ssb_pcmcia_write16, 43961e115a5SMichael Buesch .write32 = ssb_pcmcia_write32, 440d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 441d625a29bSMichael Buesch .block_read = ssb_pcmcia_block_read, 442d625a29bSMichael Buesch .block_write = ssb_pcmcia_block_write, 443d625a29bSMichael Buesch #endif 44461e115a5SMichael Buesch }; 44561e115a5SMichael Buesch 446e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) 447e7ec2e32SMichael Buesch { 448e7ec2e32SMichael Buesch unsigned int i; 449e7ec2e32SMichael Buesch int err; 450e7ec2e32SMichael Buesch u8 value; 451e7ec2e32SMichael Buesch 452e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROMCTL, command); 453e7ec2e32SMichael Buesch if (err) 454e7ec2e32SMichael Buesch return err; 455e7ec2e32SMichael Buesch for (i = 0; i < 1000; i++) { 456e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROMCTL, &value); 457e7ec2e32SMichael Buesch if (err) 458e7ec2e32SMichael Buesch return err; 459e7ec2e32SMichael Buesch if (value & SSB_PCMCIA_SPROMCTL_DONE) 460e7ec2e32SMichael Buesch return 0; 461e7ec2e32SMichael Buesch udelay(10); 462e7ec2e32SMichael Buesch } 463e7ec2e32SMichael Buesch 464e7ec2e32SMichael Buesch return -ETIMEDOUT; 465e7ec2e32SMichael Buesch } 466e7ec2e32SMichael Buesch 467e7ec2e32SMichael Buesch /* offset is the 16bit word offset */ 468e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_read(struct ssb_bus *bus, u16 offset, u16 *value) 469e7ec2e32SMichael Buesch { 470e7ec2e32SMichael Buesch int err; 471e7ec2e32SMichael Buesch u8 lo, hi; 472e7ec2e32SMichael Buesch 473e7ec2e32SMichael Buesch offset *= 2; /* Make byte offset */ 474e7ec2e32SMichael Buesch 475e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO, 476e7ec2e32SMichael Buesch (offset & 0x00FF)); 477e7ec2e32SMichael Buesch if (err) 478e7ec2e32SMichael Buesch return err; 479e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI, 480e7ec2e32SMichael Buesch (offset & 0xFF00) >> 8); 481e7ec2e32SMichael Buesch if (err) 482e7ec2e32SMichael Buesch return err; 483e7ec2e32SMichael Buesch err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_READ); 484e7ec2e32SMichael Buesch if (err) 485e7ec2e32SMichael Buesch return err; 486e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATALO, &lo); 487e7ec2e32SMichael Buesch if (err) 488e7ec2e32SMichael Buesch return err; 489e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATAHI, &hi); 490e7ec2e32SMichael Buesch if (err) 491e7ec2e32SMichael Buesch return err; 492e7ec2e32SMichael Buesch *value = (lo | (((u16)hi) << 8)); 493e7ec2e32SMichael Buesch 494e7ec2e32SMichael Buesch return 0; 495e7ec2e32SMichael Buesch } 496e7ec2e32SMichael Buesch 497e7ec2e32SMichael Buesch /* offset is the 16bit word offset */ 498e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_write(struct ssb_bus *bus, u16 offset, u16 value) 499e7ec2e32SMichael Buesch { 500e7ec2e32SMichael Buesch int err; 501e7ec2e32SMichael Buesch 502e7ec2e32SMichael Buesch offset *= 2; /* Make byte offset */ 503e7ec2e32SMichael Buesch 504e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO, 505e7ec2e32SMichael Buesch (offset & 0x00FF)); 506e7ec2e32SMichael Buesch if (err) 507e7ec2e32SMichael Buesch return err; 508e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI, 509e7ec2e32SMichael Buesch (offset & 0xFF00) >> 8); 510e7ec2e32SMichael Buesch if (err) 511e7ec2e32SMichael Buesch return err; 512e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATALO, 513e7ec2e32SMichael Buesch (value & 0x00FF)); 514e7ec2e32SMichael Buesch if (err) 515e7ec2e32SMichael Buesch return err; 516e7ec2e32SMichael Buesch err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATAHI, 517e7ec2e32SMichael Buesch (value & 0xFF00) >> 8); 518e7ec2e32SMichael Buesch if (err) 519e7ec2e32SMichael Buesch return err; 520e7ec2e32SMichael Buesch err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITE); 521e7ec2e32SMichael Buesch if (err) 522e7ec2e32SMichael Buesch return err; 523e7ec2e32SMichael Buesch msleep(20); 524e7ec2e32SMichael Buesch 525e7ec2e32SMichael Buesch return 0; 526e7ec2e32SMichael Buesch } 527e7ec2e32SMichael Buesch 528e7ec2e32SMichael Buesch /* Read the SPROM image. bufsize is in 16bit words. */ 529e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_read_all(struct ssb_bus *bus, u16 *sprom) 530e7ec2e32SMichael Buesch { 531e7ec2e32SMichael Buesch int err, i; 532e7ec2e32SMichael Buesch 533e7ec2e32SMichael Buesch for (i = 0; i < SSB_PCMCIA_SPROM_SIZE; i++) { 534e7ec2e32SMichael Buesch err = ssb_pcmcia_sprom_read(bus, i, &sprom[i]); 535e7ec2e32SMichael Buesch if (err) 536e7ec2e32SMichael Buesch return err; 537e7ec2e32SMichael Buesch } 538e7ec2e32SMichael Buesch 539e7ec2e32SMichael Buesch return 0; 540e7ec2e32SMichael Buesch } 541e7ec2e32SMichael Buesch 542e7ec2e32SMichael Buesch /* Write the SPROM image. size is in 16bit words. */ 543e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom) 544e7ec2e32SMichael Buesch { 545e7ec2e32SMichael Buesch int i, err; 546e7ec2e32SMichael Buesch bool failed = 0; 547e7ec2e32SMichael Buesch size_t size = SSB_PCMCIA_SPROM_SIZE; 548e7ec2e32SMichael Buesch 549b8b6069cSMichael Büsch pr_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n"); 550e7ec2e32SMichael Buesch err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN); 551e7ec2e32SMichael Buesch if (err) { 552b8b6069cSMichael Büsch pr_notice("Could not enable SPROM write access\n"); 553e7ec2e32SMichael Buesch return -EBUSY; 554e7ec2e32SMichael Buesch } 555b8b6069cSMichael Büsch pr_notice("[ 0%%"); 556e7ec2e32SMichael Buesch msleep(500); 557e7ec2e32SMichael Buesch for (i = 0; i < size; i++) { 558e7ec2e32SMichael Buesch if (i == size / 4) 559b8b6069cSMichael Büsch pr_cont("25%%"); 560e7ec2e32SMichael Buesch else if (i == size / 2) 561b8b6069cSMichael Büsch pr_cont("50%%"); 562e7ec2e32SMichael Buesch else if (i == (size * 3) / 4) 563b8b6069cSMichael Büsch pr_cont("75%%"); 564e7ec2e32SMichael Buesch else if (i % 2) 565b8b6069cSMichael Büsch pr_cont("."); 566e7ec2e32SMichael Buesch err = ssb_pcmcia_sprom_write(bus, i, sprom[i]); 567e7ec2e32SMichael Buesch if (err) { 568b8b6069cSMichael Büsch pr_notice("Failed to write to SPROM\n"); 569e7ec2e32SMichael Buesch failed = 1; 570e7ec2e32SMichael Buesch break; 571e7ec2e32SMichael Buesch } 572e7ec2e32SMichael Buesch } 573e7ec2e32SMichael Buesch err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS); 574e7ec2e32SMichael Buesch if (err) { 575b8b6069cSMichael Büsch pr_notice("Could not disable SPROM write access\n"); 576e7ec2e32SMichael Buesch failed = 1; 577e7ec2e32SMichael Buesch } 578e7ec2e32SMichael Buesch msleep(500); 579e7ec2e32SMichael Buesch if (!failed) { 580b8b6069cSMichael Büsch pr_cont("100%% ]\n"); 581b8b6069cSMichael Büsch pr_notice("SPROM written\n"); 582e7ec2e32SMichael Buesch } 583e7ec2e32SMichael Buesch 584e7ec2e32SMichael Buesch return failed ? -EBUSY : 0; 585e7ec2e32SMichael Buesch } 586e7ec2e32SMichael Buesch 587e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size) 588e7ec2e32SMichael Buesch { 589e7ec2e32SMichael Buesch //TODO 590e7ec2e32SMichael Buesch return 0; 591e7ec2e32SMichael Buesch } 592e7ec2e32SMichael Buesch 593e7ec2e32SMichael Buesch #define GOTO_ERROR_ON(condition, description) do { \ 594e7ec2e32SMichael Buesch if (unlikely(condition)) { \ 595e7ec2e32SMichael Buesch error_description = description; \ 596e7ec2e32SMichael Buesch goto error; \ 597e7ec2e32SMichael Buesch } \ 598e7ec2e32SMichael Buesch } while (0) 599e7ec2e32SMichael Buesch 60037ace3d4SDominik Brodowski static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev, 60137ace3d4SDominik Brodowski tuple_t *tuple, 60237ace3d4SDominik Brodowski void *priv) 60361e115a5SMichael Buesch { 60437ace3d4SDominik Brodowski struct ssb_sprom *sprom = priv; 60537ace3d4SDominik Brodowski 60637ace3d4SDominik Brodowski if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID) 60737ace3d4SDominik Brodowski return -EINVAL; 60837ace3d4SDominik Brodowski if (tuple->TupleDataLen != ETH_ALEN + 2) 60937ace3d4SDominik Brodowski return -EINVAL; 61037ace3d4SDominik Brodowski if (tuple->TupleData[1] != ETH_ALEN) 61137ace3d4SDominik Brodowski return -EINVAL; 61237ace3d4SDominik Brodowski memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN); 61337ace3d4SDominik Brodowski return 0; 61437ace3d4SDominik Brodowski }; 61537ace3d4SDominik Brodowski 61637ace3d4SDominik Brodowski static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev, 61737ace3d4SDominik Brodowski tuple_t *tuple, 61837ace3d4SDominik Brodowski void *priv) 61937ace3d4SDominik Brodowski { 62037ace3d4SDominik Brodowski struct ssb_init_invariants *iv = priv; 621e7ec2e32SMichael Buesch struct ssb_sprom *sprom = &iv->sprom; 622e7ec2e32SMichael Buesch struct ssb_boardinfo *bi = &iv->boardinfo; 623e7ec2e32SMichael Buesch const char *error_description; 624e7ec2e32SMichael Buesch 62537ace3d4SDominik Brodowski GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1"); 62637ace3d4SDominik Brodowski switch (tuple->TupleData[0]) { 62737ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_ID: 62837ace3d4SDominik Brodowski GOTO_ERROR_ON((tuple->TupleDataLen != 5) && 62937ace3d4SDominik Brodowski (tuple->TupleDataLen != 7), 63037ace3d4SDominik Brodowski "id tpl size"); 63137ace3d4SDominik Brodowski bi->vendor = tuple->TupleData[1] | 63237ace3d4SDominik Brodowski ((u16)tuple->TupleData[2] << 8); 63337ace3d4SDominik Brodowski break; 63437ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_BOARDREV: 63537ace3d4SDominik Brodowski GOTO_ERROR_ON(tuple->TupleDataLen != 2, 63637ace3d4SDominik Brodowski "boardrev tpl size"); 63737ace3d4SDominik Brodowski sprom->board_rev = tuple->TupleData[1]; 63837ace3d4SDominik Brodowski break; 63937ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_PA: 64037ace3d4SDominik Brodowski GOTO_ERROR_ON((tuple->TupleDataLen != 9) && 64137ace3d4SDominik Brodowski (tuple->TupleDataLen != 10), 64237ace3d4SDominik Brodowski "pa tpl size"); 64337ace3d4SDominik Brodowski sprom->pa0b0 = tuple->TupleData[1] | 64437ace3d4SDominik Brodowski ((u16)tuple->TupleData[2] << 8); 64537ace3d4SDominik Brodowski sprom->pa0b1 = tuple->TupleData[3] | 64637ace3d4SDominik Brodowski ((u16)tuple->TupleData[4] << 8); 64737ace3d4SDominik Brodowski sprom->pa0b2 = tuple->TupleData[5] | 64837ace3d4SDominik Brodowski ((u16)tuple->TupleData[6] << 8); 64937ace3d4SDominik Brodowski sprom->itssi_a = tuple->TupleData[7]; 65037ace3d4SDominik Brodowski sprom->itssi_bg = tuple->TupleData[7]; 65137ace3d4SDominik Brodowski sprom->maxpwr_a = tuple->TupleData[8]; 65237ace3d4SDominik Brodowski sprom->maxpwr_bg = tuple->TupleData[8]; 65337ace3d4SDominik Brodowski break; 65437ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_OEMNAME: 65537ace3d4SDominik Brodowski /* We ignore this. */ 65637ace3d4SDominik Brodowski break; 65737ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_CCODE: 65837ace3d4SDominik Brodowski GOTO_ERROR_ON(tuple->TupleDataLen != 2, 65937ace3d4SDominik Brodowski "ccode tpl size"); 66037ace3d4SDominik Brodowski sprom->country_code = tuple->TupleData[1]; 66137ace3d4SDominik Brodowski break; 66237ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_ANTENNA: 66337ace3d4SDominik Brodowski GOTO_ERROR_ON(tuple->TupleDataLen != 2, 66437ace3d4SDominik Brodowski "ant tpl size"); 66537ace3d4SDominik Brodowski sprom->ant_available_a = tuple->TupleData[1]; 66637ace3d4SDominik Brodowski sprom->ant_available_bg = tuple->TupleData[1]; 66737ace3d4SDominik Brodowski break; 66837ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_ANTGAIN: 66937ace3d4SDominik Brodowski GOTO_ERROR_ON(tuple->TupleDataLen != 2, 67037ace3d4SDominik Brodowski "antg tpl size"); 671f8f8a660SHauke Mehrtens sprom->antenna_gain.a0 = tuple->TupleData[1]; 672f8f8a660SHauke Mehrtens sprom->antenna_gain.a1 = tuple->TupleData[1]; 673f8f8a660SHauke Mehrtens sprom->antenna_gain.a2 = tuple->TupleData[1]; 674f8f8a660SHauke Mehrtens sprom->antenna_gain.a3 = tuple->TupleData[1]; 67537ace3d4SDominik Brodowski break; 67637ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_BFLAGS: 67737ace3d4SDominik Brodowski GOTO_ERROR_ON((tuple->TupleDataLen != 3) && 67837ace3d4SDominik Brodowski (tuple->TupleDataLen != 5), 67937ace3d4SDominik Brodowski "bfl tpl size"); 68037ace3d4SDominik Brodowski sprom->boardflags_lo = tuple->TupleData[1] | 68137ace3d4SDominik Brodowski ((u16)tuple->TupleData[2] << 8); 68237ace3d4SDominik Brodowski break; 68337ace3d4SDominik Brodowski case SSB_PCMCIA_CIS_LEDS: 68437ace3d4SDominik Brodowski GOTO_ERROR_ON(tuple->TupleDataLen != 5, 68537ace3d4SDominik Brodowski "leds tpl size"); 68637ace3d4SDominik Brodowski sprom->gpio0 = tuple->TupleData[1]; 68737ace3d4SDominik Brodowski sprom->gpio1 = tuple->TupleData[2]; 68837ace3d4SDominik Brodowski sprom->gpio2 = tuple->TupleData[3]; 68937ace3d4SDominik Brodowski sprom->gpio3 = tuple->TupleData[4]; 69037ace3d4SDominik Brodowski break; 69137ace3d4SDominik Brodowski } 69237ace3d4SDominik Brodowski return -ENOSPC; /* continue with next entry */ 69337ace3d4SDominik Brodowski 69437ace3d4SDominik Brodowski error: 695b8b6069cSMichael Büsch pr_err("PCMCIA: Failed to fetch device invariants: %s\n", 69637ace3d4SDominik Brodowski error_description); 69737ace3d4SDominik Brodowski return -ENODEV; 69837ace3d4SDominik Brodowski } 69937ace3d4SDominik Brodowski 70037ace3d4SDominik Brodowski 70137ace3d4SDominik Brodowski int ssb_pcmcia_get_invariants(struct ssb_bus *bus, 70237ace3d4SDominik Brodowski struct ssb_init_invariants *iv) 70337ace3d4SDominik Brodowski { 70437ace3d4SDominik Brodowski struct ssb_sprom *sprom = &iv->sprom; 70537ace3d4SDominik Brodowski int res; 70637ace3d4SDominik Brodowski 707e7ec2e32SMichael Buesch memset(sprom, 0xFF, sizeof(*sprom)); 708e7ec2e32SMichael Buesch sprom->revision = 1; 709e7ec2e32SMichael Buesch sprom->boardflags_lo = 0; 710e7ec2e32SMichael Buesch sprom->boardflags_hi = 0; 711e7ec2e32SMichael Buesch 712e7ec2e32SMichael Buesch /* First fetch the MAC address. */ 71337ace3d4SDominik Brodowski res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE, 71437ace3d4SDominik Brodowski ssb_pcmcia_get_mac, sprom); 71537ace3d4SDominik Brodowski if (res != 0) { 716b8b6069cSMichael Büsch pr_err("PCMCIA: Failed to fetch MAC address\n"); 71737ace3d4SDominik Brodowski return -ENODEV; 718e7ec2e32SMichael Buesch } 719e7ec2e32SMichael Buesch 720e7ec2e32SMichael Buesch /* Fetch the vendor specific tuples. */ 72137ace3d4SDominik Brodowski res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS, 722dd3cb633SMichael Büsch ssb_pcmcia_do_get_invariants, iv); 72337ace3d4SDominik Brodowski if ((res == 0) || (res == -ENOSPC)) 72461e115a5SMichael Buesch return 0; 72537ace3d4SDominik Brodowski 726b8b6069cSMichael Büsch pr_err("PCMCIA: Failed to fetch device invariants\n"); 727e7ec2e32SMichael Buesch return -ENODEV; 728e7ec2e32SMichael Buesch } 729e7ec2e32SMichael Buesch 730e7ec2e32SMichael Buesch static ssize_t ssb_pcmcia_attr_sprom_show(struct device *pcmciadev, 731e7ec2e32SMichael Buesch struct device_attribute *attr, 732e7ec2e32SMichael Buesch char *buf) 733e7ec2e32SMichael Buesch { 734e7ec2e32SMichael Buesch struct pcmcia_device *pdev = 735e7ec2e32SMichael Buesch container_of(pcmciadev, struct pcmcia_device, dev); 736e7ec2e32SMichael Buesch struct ssb_bus *bus; 737e7ec2e32SMichael Buesch 738e7ec2e32SMichael Buesch bus = ssb_pcmcia_dev_to_bus(pdev); 739e7ec2e32SMichael Buesch if (!bus) 740e7ec2e32SMichael Buesch return -ENODEV; 741e7ec2e32SMichael Buesch 742e7ec2e32SMichael Buesch return ssb_attr_sprom_show(bus, buf, 743e7ec2e32SMichael Buesch ssb_pcmcia_sprom_read_all); 744e7ec2e32SMichael Buesch } 745e7ec2e32SMichael Buesch 746e7ec2e32SMichael Buesch static ssize_t ssb_pcmcia_attr_sprom_store(struct device *pcmciadev, 747e7ec2e32SMichael Buesch struct device_attribute *attr, 748e7ec2e32SMichael Buesch const char *buf, size_t count) 749e7ec2e32SMichael Buesch { 750e7ec2e32SMichael Buesch struct pcmcia_device *pdev = 751e7ec2e32SMichael Buesch container_of(pcmciadev, struct pcmcia_device, dev); 752e7ec2e32SMichael Buesch struct ssb_bus *bus; 753e7ec2e32SMichael Buesch 754e7ec2e32SMichael Buesch bus = ssb_pcmcia_dev_to_bus(pdev); 755e7ec2e32SMichael Buesch if (!bus) 756e7ec2e32SMichael Buesch return -ENODEV; 757e7ec2e32SMichael Buesch 758e7ec2e32SMichael Buesch return ssb_attr_sprom_store(bus, buf, count, 759e7ec2e32SMichael Buesch ssb_pcmcia_sprom_check_crc, 760e7ec2e32SMichael Buesch ssb_pcmcia_sprom_write_all); 761e7ec2e32SMichael Buesch } 762e7ec2e32SMichael Buesch 763e7ec2e32SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600, 764e7ec2e32SMichael Buesch ssb_pcmcia_attr_sprom_show, 765e7ec2e32SMichael Buesch ssb_pcmcia_attr_sprom_store); 766e7ec2e32SMichael Buesch 7679788ba75SMichael Buesch static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor) 7689788ba75SMichael Buesch { 7699788ba75SMichael Buesch u8 val; 7709788ba75SMichael Buesch int err; 7719788ba75SMichael Buesch 7729788ba75SMichael Buesch err = ssb_pcmcia_cfg_read(bus, cor, &val); 7739788ba75SMichael Buesch if (err) 7749788ba75SMichael Buesch return err; 7759788ba75SMichael Buesch val &= ~COR_SOFT_RESET; 7769788ba75SMichael Buesch val |= COR_FUNC_ENA | COR_IREQ_ENA | COR_LEVEL_REQ; 7779788ba75SMichael Buesch err = ssb_pcmcia_cfg_write(bus, cor, val); 7789788ba75SMichael Buesch if (err) 7799788ba75SMichael Buesch return err; 7809788ba75SMichael Buesch msleep(40); 7819788ba75SMichael Buesch 7829788ba75SMichael Buesch return 0; 7839788ba75SMichael Buesch } 7849788ba75SMichael Buesch 7858fe2b65aSMichael Buesch /* Initialize the PCMCIA hardware. This is called on Init and Resume. */ 7868fe2b65aSMichael Buesch int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) 7878fe2b65aSMichael Buesch { 7888fe2b65aSMichael Buesch int err; 7898fe2b65aSMichael Buesch 7908fe2b65aSMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCMCIA) 7918fe2b65aSMichael Buesch return 0; 7928fe2b65aSMichael Buesch 7938fe2b65aSMichael Buesch /* Switch segment to a known state and sync 7948fe2b65aSMichael Buesch * bus->mapped_pcmcia_seg with hardware state. */ 7958fe2b65aSMichael Buesch ssb_pcmcia_switch_segment(bus, 0); 7968fe2b65aSMichael Buesch /* Init the COR register. */ 7978fe2b65aSMichael Buesch err = ssb_pcmcia_cor_setup(bus, CISREG_COR); 7988fe2b65aSMichael Buesch if (err) 7998fe2b65aSMichael Buesch return err; 8008fe2b65aSMichael Buesch /* Some cards also need this register to get poked. */ 8018fe2b65aSMichael Buesch err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); 8028fe2b65aSMichael Buesch if (err) 8038fe2b65aSMichael Buesch return err; 8048fe2b65aSMichael Buesch 8058fe2b65aSMichael Buesch return 0; 8068fe2b65aSMichael Buesch } 8078fe2b65aSMichael Buesch 808e7ec2e32SMichael Buesch void ssb_pcmcia_exit(struct ssb_bus *bus) 809e7ec2e32SMichael Buesch { 810e7ec2e32SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCMCIA) 811e7ec2e32SMichael Buesch return; 812e7ec2e32SMichael Buesch 813e7ec2e32SMichael Buesch device_remove_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom); 81461e115a5SMichael Buesch } 81561e115a5SMichael Buesch 81661e115a5SMichael Buesch int ssb_pcmcia_init(struct ssb_bus *bus) 81761e115a5SMichael Buesch { 81861e115a5SMichael Buesch int err; 81961e115a5SMichael Buesch 82061e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCMCIA) 82161e115a5SMichael Buesch return 0; 82261e115a5SMichael Buesch 8238fe2b65aSMichael Buesch err = ssb_pcmcia_hardware_setup(bus); 824e7ec2e32SMichael Buesch if (err) 825e7ec2e32SMichael Buesch goto error; 826e7ec2e32SMichael Buesch 827e7ec2e32SMichael Buesch bus->sprom_size = SSB_PCMCIA_SPROM_SIZE; 828e7ec2e32SMichael Buesch mutex_init(&bus->sprom_mutex); 829e7ec2e32SMichael Buesch err = device_create_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom); 830e7ec2e32SMichael Buesch if (err) 83161e115a5SMichael Buesch goto error; 83261e115a5SMichael Buesch 83361e115a5SMichael Buesch return 0; 83461e115a5SMichael Buesch error: 835b8b6069cSMichael Büsch pr_err("Failed to initialize PCMCIA host device\n"); 836e7ec2e32SMichael Buesch return err; 83761e115a5SMichael Buesch } 838