xref: /openbmc/linux/drivers/ssb/pcmcia.c (revision 573f1af8)
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. */
ssb_pcmcia_cfg_write(struct ssb_bus * bus,u8 offset,u8 value)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. */
ssb_pcmcia_cfg_read(struct ssb_bus * bus,u8 offset,u8 * value)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 
ssb_pcmcia_switch_coreidx(struct ssb_bus * bus,u8 coreidx)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 
ssb_pcmcia_switch_core(struct ssb_bus * bus,struct ssb_device * dev)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 
ssb_pcmcia_switch_segment(struct ssb_bus * bus,u8 seg)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 
select_core_and_segment(struct ssb_device * dev,u16 * offset)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 
ssb_pcmcia_read8(struct ssb_device * dev,u16 offset)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 
ssb_pcmcia_read16(struct ssb_device * dev,u16 offset)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 
ssb_pcmcia_read32(struct ssb_device * dev,u16 offset)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
ssb_pcmcia_block_read(struct ssb_device * dev,void * buffer,size_t count,u16 offset,u8 reg_width)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 
ssb_pcmcia_write8(struct ssb_device * dev,u16 offset,u8 value)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 	spin_unlock_irqrestore(&bus->bar_lock, flags);
342ffc7689dSMichael Buesch }
343ffc7689dSMichael Buesch 
ssb_pcmcia_write16(struct ssb_device * dev,u16 offset,u16 value)34461e115a5SMichael Buesch static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
34561e115a5SMichael Buesch {
34661e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
347993e1c78SMichael Buesch 	unsigned long flags;
348993e1c78SMichael Buesch 	int err;
34961e115a5SMichael Buesch 
350993e1c78SMichael Buesch 	spin_lock_irqsave(&bus->bar_lock, flags);
351993e1c78SMichael Buesch 	err = select_core_and_segment(dev, &offset);
352993e1c78SMichael Buesch 	if (likely(!err))
35361e115a5SMichael Buesch 		writew(value, bus->mmio + offset);
354993e1c78SMichael Buesch 	spin_unlock_irqrestore(&bus->bar_lock, flags);
35561e115a5SMichael Buesch }
35661e115a5SMichael Buesch 
ssb_pcmcia_write32(struct ssb_device * dev,u16 offset,u32 value)35761e115a5SMichael Buesch static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
35861e115a5SMichael Buesch {
35961e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
360993e1c78SMichael Buesch 	unsigned long flags;
361993e1c78SMichael Buesch 	int err;
36261e115a5SMichael Buesch 
363993e1c78SMichael Buesch 	spin_lock_irqsave(&bus->bar_lock, flags);
364993e1c78SMichael Buesch 	err = select_core_and_segment(dev, &offset);
365993e1c78SMichael Buesch 	if (likely(!err)) {
366993e1c78SMichael Buesch 		writew((value & 0x0000FFFF), bus->mmio + offset);
367993e1c78SMichael Buesch 		writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
368993e1c78SMichael Buesch 	}
369993e1c78SMichael Buesch 	spin_unlock_irqrestore(&bus->bar_lock, flags);
37061e115a5SMichael Buesch }
37161e115a5SMichael Buesch 
372d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
ssb_pcmcia_block_write(struct ssb_device * dev,const void * buffer,size_t count,u16 offset,u8 reg_width)373d625a29bSMichael Buesch static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer,
374d625a29bSMichael Buesch 				   size_t count, u16 offset, u8 reg_width)
375d625a29bSMichael Buesch {
376d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
377d625a29bSMichael Buesch 	unsigned long flags;
378d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
379d625a29bSMichael Buesch 	int err;
380d625a29bSMichael Buesch 
381d625a29bSMichael Buesch 	spin_lock_irqsave(&bus->bar_lock, flags);
382d625a29bSMichael Buesch 	err = select_core_and_segment(dev, &offset);
383d625a29bSMichael Buesch 	if (unlikely(err))
384d625a29bSMichael Buesch 		goto unlock;
385d625a29bSMichael Buesch 	switch (reg_width) {
386d625a29bSMichael Buesch 	case sizeof(u8): {
387d625a29bSMichael Buesch 		const u8 *buf = buffer;
388d625a29bSMichael Buesch 
389d625a29bSMichael Buesch 		while (count) {
390d625a29bSMichael Buesch 			__raw_writeb(*buf, addr);
391d625a29bSMichael Buesch 			buf++;
392d625a29bSMichael Buesch 			count--;
393d625a29bSMichael Buesch 		}
394d625a29bSMichael Buesch 		break;
395d625a29bSMichael Buesch 	}
396d625a29bSMichael Buesch 	case sizeof(u16): {
397d625a29bSMichael Buesch 		const __le16 *buf = buffer;
398d625a29bSMichael Buesch 
399209b4375SMichael Büsch 		WARN_ON(count & 1);
400d625a29bSMichael Buesch 		while (count) {
401d625a29bSMichael Buesch 			__raw_writew((__force u16)(*buf), addr);
402d625a29bSMichael Buesch 			buf++;
403d625a29bSMichael Buesch 			count -= 2;
404d625a29bSMichael Buesch 		}
405d625a29bSMichael Buesch 		break;
406d625a29bSMichael Buesch 	}
407d625a29bSMichael Buesch 	case sizeof(u32): {
408d625a29bSMichael Buesch 		const __le16 *buf = buffer;
409d625a29bSMichael Buesch 
410209b4375SMichael Büsch 		WARN_ON(count & 3);
411d625a29bSMichael Buesch 		while (count) {
412d625a29bSMichael Buesch 			__raw_writew((__force u16)(*buf), addr);
413d625a29bSMichael Buesch 			buf++;
414d625a29bSMichael Buesch 			__raw_writew((__force u16)(*buf), addr + 2);
415d625a29bSMichael Buesch 			buf++;
416d625a29bSMichael Buesch 			count -= 4;
417d625a29bSMichael Buesch 		}
418d625a29bSMichael Buesch 		break;
419d625a29bSMichael Buesch 	}
420d625a29bSMichael Buesch 	default:
421209b4375SMichael Büsch 		WARN_ON(1);
422d625a29bSMichael Buesch 	}
423d625a29bSMichael Buesch unlock:
424d625a29bSMichael Buesch 	spin_unlock_irqrestore(&bus->bar_lock, flags);
425d625a29bSMichael Buesch }
426d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
427d625a29bSMichael Buesch 
42861e115a5SMichael Buesch /* Not "static", as it's used in main.c */
42961e115a5SMichael Buesch const struct ssb_bus_ops ssb_pcmcia_ops = {
430ffc7689dSMichael Buesch 	.read8		= ssb_pcmcia_read8,
43161e115a5SMichael Buesch 	.read16		= ssb_pcmcia_read16,
43261e115a5SMichael Buesch 	.read32		= ssb_pcmcia_read32,
433ffc7689dSMichael Buesch 	.write8		= ssb_pcmcia_write8,
43461e115a5SMichael Buesch 	.write16	= ssb_pcmcia_write16,
43561e115a5SMichael Buesch 	.write32	= ssb_pcmcia_write32,
436d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
437d625a29bSMichael Buesch 	.block_read	= ssb_pcmcia_block_read,
438d625a29bSMichael Buesch 	.block_write	= ssb_pcmcia_block_write,
439d625a29bSMichael Buesch #endif
44061e115a5SMichael Buesch };
44161e115a5SMichael Buesch 
ssb_pcmcia_sprom_command(struct ssb_bus * bus,u8 command)442e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command)
443e7ec2e32SMichael Buesch {
444e7ec2e32SMichael Buesch 	unsigned int i;
445e7ec2e32SMichael Buesch 	int err;
446e7ec2e32SMichael Buesch 	u8 value;
447e7ec2e32SMichael Buesch 
448e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROMCTL, command);
449e7ec2e32SMichael Buesch 	if (err)
450e7ec2e32SMichael Buesch 		return err;
451e7ec2e32SMichael Buesch 	for (i = 0; i < 1000; i++) {
452e7ec2e32SMichael Buesch 		err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROMCTL, &value);
453e7ec2e32SMichael Buesch 		if (err)
454e7ec2e32SMichael Buesch 			return err;
455e7ec2e32SMichael Buesch 		if (value & SSB_PCMCIA_SPROMCTL_DONE)
456e7ec2e32SMichael Buesch 			return 0;
457e7ec2e32SMichael Buesch 		udelay(10);
458e7ec2e32SMichael Buesch 	}
459e7ec2e32SMichael Buesch 
460e7ec2e32SMichael Buesch 	return -ETIMEDOUT;
461e7ec2e32SMichael Buesch }
462e7ec2e32SMichael Buesch 
463e7ec2e32SMichael Buesch /* offset is the 16bit word offset */
ssb_pcmcia_sprom_read(struct ssb_bus * bus,u16 offset,u16 * value)464e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_read(struct ssb_bus *bus, u16 offset, u16 *value)
465e7ec2e32SMichael Buesch {
466e7ec2e32SMichael Buesch 	int err;
467e7ec2e32SMichael Buesch 	u8 lo, hi;
468e7ec2e32SMichael Buesch 
469e7ec2e32SMichael Buesch 	offset *= 2; /* Make byte offset */
470e7ec2e32SMichael Buesch 
471e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,
472e7ec2e32SMichael Buesch 				   (offset & 0x00FF));
473e7ec2e32SMichael Buesch 	if (err)
474e7ec2e32SMichael Buesch 		return err;
475e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,
476e7ec2e32SMichael Buesch 				   (offset & 0xFF00) >> 8);
477e7ec2e32SMichael Buesch 	if (err)
478e7ec2e32SMichael Buesch 		return err;
479e7ec2e32SMichael Buesch 	err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_READ);
480e7ec2e32SMichael Buesch 	if (err)
481e7ec2e32SMichael Buesch 		return err;
482e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATALO, &lo);
483e7ec2e32SMichael Buesch 	if (err)
484e7ec2e32SMichael Buesch 		return err;
485e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATAHI, &hi);
486e7ec2e32SMichael Buesch 	if (err)
487e7ec2e32SMichael Buesch 		return err;
488e7ec2e32SMichael Buesch 	*value = (lo | (((u16)hi) << 8));
489e7ec2e32SMichael Buesch 
490e7ec2e32SMichael Buesch 	return 0;
491e7ec2e32SMichael Buesch }
492e7ec2e32SMichael Buesch 
493e7ec2e32SMichael Buesch /* offset is the 16bit word offset */
ssb_pcmcia_sprom_write(struct ssb_bus * bus,u16 offset,u16 value)494e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_write(struct ssb_bus *bus, u16 offset, u16 value)
495e7ec2e32SMichael Buesch {
496e7ec2e32SMichael Buesch 	int err;
497e7ec2e32SMichael Buesch 
498e7ec2e32SMichael Buesch 	offset *= 2; /* Make byte offset */
499e7ec2e32SMichael Buesch 
500e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,
501e7ec2e32SMichael Buesch 				   (offset & 0x00FF));
502e7ec2e32SMichael Buesch 	if (err)
503e7ec2e32SMichael Buesch 		return err;
504e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,
505e7ec2e32SMichael Buesch 				   (offset & 0xFF00) >> 8);
506e7ec2e32SMichael Buesch 	if (err)
507e7ec2e32SMichael Buesch 		return err;
508e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATALO,
509e7ec2e32SMichael Buesch 				   (value & 0x00FF));
510e7ec2e32SMichael Buesch 	if (err)
511e7ec2e32SMichael Buesch 		return err;
512e7ec2e32SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATAHI,
513e7ec2e32SMichael Buesch 				   (value & 0xFF00) >> 8);
514e7ec2e32SMichael Buesch 	if (err)
515e7ec2e32SMichael Buesch 		return err;
516e7ec2e32SMichael Buesch 	err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITE);
517e7ec2e32SMichael Buesch 	if (err)
518e7ec2e32SMichael Buesch 		return err;
519e7ec2e32SMichael Buesch 	msleep(20);
520e7ec2e32SMichael Buesch 
521e7ec2e32SMichael Buesch 	return 0;
522e7ec2e32SMichael Buesch }
523e7ec2e32SMichael Buesch 
524e7ec2e32SMichael Buesch /* Read the SPROM image. bufsize is in 16bit words. */
ssb_pcmcia_sprom_read_all(struct ssb_bus * bus,u16 * sprom)525e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_read_all(struct ssb_bus *bus, u16 *sprom)
526e7ec2e32SMichael Buesch {
527e7ec2e32SMichael Buesch 	int err, i;
528e7ec2e32SMichael Buesch 
529e7ec2e32SMichael Buesch 	for (i = 0; i < SSB_PCMCIA_SPROM_SIZE; i++) {
530e7ec2e32SMichael Buesch 		err = ssb_pcmcia_sprom_read(bus, i, &sprom[i]);
531e7ec2e32SMichael Buesch 		if (err)
532e7ec2e32SMichael Buesch 			return err;
533e7ec2e32SMichael Buesch 	}
534e7ec2e32SMichael Buesch 
535e7ec2e32SMichael Buesch 	return 0;
536e7ec2e32SMichael Buesch }
537e7ec2e32SMichael Buesch 
538e7ec2e32SMichael Buesch /* Write the SPROM image. size is in 16bit words. */
ssb_pcmcia_sprom_write_all(struct ssb_bus * bus,const u16 * sprom)539e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
540e7ec2e32SMichael Buesch {
541e7ec2e32SMichael Buesch 	int i, err;
542e7ec2e32SMichael Buesch 	bool failed = 0;
543e7ec2e32SMichael Buesch 	size_t size = SSB_PCMCIA_SPROM_SIZE;
544e7ec2e32SMichael Buesch 
545b8b6069cSMichael Büsch 	pr_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
546e7ec2e32SMichael Buesch 	err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);
547e7ec2e32SMichael Buesch 	if (err) {
548b8b6069cSMichael Büsch 		pr_notice("Could not enable SPROM write access\n");
549e7ec2e32SMichael Buesch 		return -EBUSY;
550e7ec2e32SMichael Buesch 	}
551b8b6069cSMichael Büsch 	pr_notice("[ 0%%");
552e7ec2e32SMichael Buesch 	msleep(500);
553e7ec2e32SMichael Buesch 	for (i = 0; i < size; i++) {
554e7ec2e32SMichael Buesch 		if (i == size / 4)
555b8b6069cSMichael Büsch 			pr_cont("25%%");
556e7ec2e32SMichael Buesch 		else if (i == size / 2)
557b8b6069cSMichael Büsch 			pr_cont("50%%");
558e7ec2e32SMichael Buesch 		else if (i == (size * 3) / 4)
559b8b6069cSMichael Büsch 			pr_cont("75%%");
560e7ec2e32SMichael Buesch 		else if (i % 2)
561b8b6069cSMichael Büsch 			pr_cont(".");
562e7ec2e32SMichael Buesch 		err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
563e7ec2e32SMichael Buesch 		if (err) {
564b8b6069cSMichael Büsch 			pr_notice("Failed to write to SPROM\n");
565e7ec2e32SMichael Buesch 			failed = 1;
566e7ec2e32SMichael Buesch 			break;
567e7ec2e32SMichael Buesch 		}
568e7ec2e32SMichael Buesch 	}
569e7ec2e32SMichael Buesch 	err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
570e7ec2e32SMichael Buesch 	if (err) {
571b8b6069cSMichael Büsch 		pr_notice("Could not disable SPROM write access\n");
572e7ec2e32SMichael Buesch 		failed = 1;
573e7ec2e32SMichael Buesch 	}
574e7ec2e32SMichael Buesch 	msleep(500);
575e7ec2e32SMichael Buesch 	if (!failed) {
576b8b6069cSMichael Büsch 		pr_cont("100%% ]\n");
577b8b6069cSMichael Büsch 		pr_notice("SPROM written\n");
578e7ec2e32SMichael Buesch 	}
579e7ec2e32SMichael Buesch 
580e7ec2e32SMichael Buesch 	return failed ? -EBUSY : 0;
581e7ec2e32SMichael Buesch }
582e7ec2e32SMichael Buesch 
ssb_pcmcia_sprom_check_crc(const u16 * sprom,size_t size)583e7ec2e32SMichael Buesch static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size)
584e7ec2e32SMichael Buesch {
585e7ec2e32SMichael Buesch 	//TODO
586e7ec2e32SMichael Buesch 	return 0;
587e7ec2e32SMichael Buesch }
588e7ec2e32SMichael Buesch 
589e7ec2e32SMichael Buesch #define GOTO_ERROR_ON(condition, description) do {	\
590e7ec2e32SMichael Buesch 	if (unlikely(condition)) {			\
591e7ec2e32SMichael Buesch 		error_description = description;	\
592e7ec2e32SMichael Buesch 		goto error;				\
593e7ec2e32SMichael Buesch 	}						\
594e7ec2e32SMichael Buesch   } while (0)
595e7ec2e32SMichael Buesch 
ssb_pcmcia_get_mac(struct pcmcia_device * p_dev,tuple_t * tuple,void * priv)59637ace3d4SDominik Brodowski static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
59737ace3d4SDominik Brodowski 			tuple_t *tuple,
59837ace3d4SDominik Brodowski 			void *priv)
59961e115a5SMichael Buesch {
60037ace3d4SDominik Brodowski 	struct ssb_sprom *sprom = priv;
60137ace3d4SDominik Brodowski 
60237ace3d4SDominik Brodowski 	if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
60337ace3d4SDominik Brodowski 		return -EINVAL;
60437ace3d4SDominik Brodowski 	if (tuple->TupleDataLen != ETH_ALEN + 2)
60537ace3d4SDominik Brodowski 		return -EINVAL;
60637ace3d4SDominik Brodowski 	if (tuple->TupleData[1] != ETH_ALEN)
60737ace3d4SDominik Brodowski 		return -EINVAL;
60837ace3d4SDominik Brodowski 	memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN);
60937ace3d4SDominik Brodowski 	return 0;
61037ace3d4SDominik Brodowski };
61137ace3d4SDominik Brodowski 
ssb_pcmcia_do_get_invariants(struct pcmcia_device * p_dev,tuple_t * tuple,void * priv)61237ace3d4SDominik Brodowski static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
61337ace3d4SDominik Brodowski 					tuple_t *tuple,
61437ace3d4SDominik Brodowski 					void *priv)
61537ace3d4SDominik Brodowski {
61637ace3d4SDominik Brodowski 	struct ssb_init_invariants *iv = priv;
617e7ec2e32SMichael Buesch 	struct ssb_sprom *sprom = &iv->sprom;
618e7ec2e32SMichael Buesch 	struct ssb_boardinfo *bi = &iv->boardinfo;
619e7ec2e32SMichael Buesch 	const char *error_description;
620e7ec2e32SMichael Buesch 
62137ace3d4SDominik Brodowski 	GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1");
62237ace3d4SDominik Brodowski 	switch (tuple->TupleData[0]) {
62337ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_ID:
62437ace3d4SDominik Brodowski 		GOTO_ERROR_ON((tuple->TupleDataLen != 5) &&
62537ace3d4SDominik Brodowski 			      (tuple->TupleDataLen != 7),
62637ace3d4SDominik Brodowski 			      "id tpl size");
62737ace3d4SDominik Brodowski 		bi->vendor = tuple->TupleData[1] |
62837ace3d4SDominik Brodowski 			((u16)tuple->TupleData[2] << 8);
62937ace3d4SDominik Brodowski 		break;
63037ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_BOARDREV:
63137ace3d4SDominik Brodowski 		GOTO_ERROR_ON(tuple->TupleDataLen != 2,
63237ace3d4SDominik Brodowski 			"boardrev tpl size");
63337ace3d4SDominik Brodowski 		sprom->board_rev = tuple->TupleData[1];
63437ace3d4SDominik Brodowski 		break;
63537ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_PA:
63637ace3d4SDominik Brodowski 		GOTO_ERROR_ON((tuple->TupleDataLen != 9) &&
63737ace3d4SDominik Brodowski 			(tuple->TupleDataLen != 10),
63837ace3d4SDominik Brodowski 			"pa tpl size");
63937ace3d4SDominik Brodowski 		sprom->pa0b0 = tuple->TupleData[1] |
64037ace3d4SDominik Brodowski 			((u16)tuple->TupleData[2] << 8);
64137ace3d4SDominik Brodowski 		sprom->pa0b1 = tuple->TupleData[3] |
64237ace3d4SDominik Brodowski 			((u16)tuple->TupleData[4] << 8);
64337ace3d4SDominik Brodowski 		sprom->pa0b2 = tuple->TupleData[5] |
64437ace3d4SDominik Brodowski 			((u16)tuple->TupleData[6] << 8);
64537ace3d4SDominik Brodowski 		sprom->itssi_a = tuple->TupleData[7];
64637ace3d4SDominik Brodowski 		sprom->itssi_bg = tuple->TupleData[7];
64737ace3d4SDominik Brodowski 		sprom->maxpwr_a = tuple->TupleData[8];
64837ace3d4SDominik Brodowski 		sprom->maxpwr_bg = tuple->TupleData[8];
64937ace3d4SDominik Brodowski 		break;
65037ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_OEMNAME:
65137ace3d4SDominik Brodowski 		/* We ignore this. */
65237ace3d4SDominik Brodowski 		break;
65337ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_CCODE:
65437ace3d4SDominik Brodowski 		GOTO_ERROR_ON(tuple->TupleDataLen != 2,
65537ace3d4SDominik Brodowski 			"ccode tpl size");
65637ace3d4SDominik Brodowski 		sprom->country_code = tuple->TupleData[1];
65737ace3d4SDominik Brodowski 		break;
65837ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_ANTENNA:
65937ace3d4SDominik Brodowski 		GOTO_ERROR_ON(tuple->TupleDataLen != 2,
66037ace3d4SDominik Brodowski 			"ant tpl size");
66137ace3d4SDominik Brodowski 		sprom->ant_available_a = tuple->TupleData[1];
66237ace3d4SDominik Brodowski 		sprom->ant_available_bg = tuple->TupleData[1];
66337ace3d4SDominik Brodowski 		break;
66437ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_ANTGAIN:
66537ace3d4SDominik Brodowski 		GOTO_ERROR_ON(tuple->TupleDataLen != 2,
66637ace3d4SDominik Brodowski 			"antg tpl size");
667f8f8a660SHauke Mehrtens 		sprom->antenna_gain.a0 = tuple->TupleData[1];
668f8f8a660SHauke Mehrtens 		sprom->antenna_gain.a1 = tuple->TupleData[1];
669f8f8a660SHauke Mehrtens 		sprom->antenna_gain.a2 = tuple->TupleData[1];
670f8f8a660SHauke Mehrtens 		sprom->antenna_gain.a3 = tuple->TupleData[1];
67137ace3d4SDominik Brodowski 		break;
67237ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_BFLAGS:
67337ace3d4SDominik Brodowski 		GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&
67437ace3d4SDominik Brodowski 			(tuple->TupleDataLen != 5),
67537ace3d4SDominik Brodowski 			"bfl tpl size");
67637ace3d4SDominik Brodowski 		sprom->boardflags_lo = tuple->TupleData[1] |
67737ace3d4SDominik Brodowski 			((u16)tuple->TupleData[2] << 8);
67837ace3d4SDominik Brodowski 		break;
67937ace3d4SDominik Brodowski 	case SSB_PCMCIA_CIS_LEDS:
68037ace3d4SDominik Brodowski 		GOTO_ERROR_ON(tuple->TupleDataLen != 5,
68137ace3d4SDominik Brodowski 			"leds tpl size");
68237ace3d4SDominik Brodowski 		sprom->gpio0 = tuple->TupleData[1];
68337ace3d4SDominik Brodowski 		sprom->gpio1 = tuple->TupleData[2];
68437ace3d4SDominik Brodowski 		sprom->gpio2 = tuple->TupleData[3];
68537ace3d4SDominik Brodowski 		sprom->gpio3 = tuple->TupleData[4];
68637ace3d4SDominik Brodowski 		break;
68737ace3d4SDominik Brodowski 	}
68837ace3d4SDominik Brodowski 	return -ENOSPC; /* continue with next entry */
68937ace3d4SDominik Brodowski 
69037ace3d4SDominik Brodowski error:
691b8b6069cSMichael Büsch 	pr_err("PCMCIA: Failed to fetch device invariants: %s\n",
69237ace3d4SDominik Brodowski 	       error_description);
69337ace3d4SDominik Brodowski 	return -ENODEV;
69437ace3d4SDominik Brodowski }
69537ace3d4SDominik Brodowski 
69637ace3d4SDominik Brodowski 
ssb_pcmcia_get_invariants(struct ssb_bus * bus,struct ssb_init_invariants * iv)69737ace3d4SDominik Brodowski int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
69837ace3d4SDominik Brodowski 			      struct ssb_init_invariants *iv)
69937ace3d4SDominik Brodowski {
70037ace3d4SDominik Brodowski 	struct ssb_sprom *sprom = &iv->sprom;
70137ace3d4SDominik Brodowski 	int res;
70237ace3d4SDominik Brodowski 
703e7ec2e32SMichael Buesch 	memset(sprom, 0xFF, sizeof(*sprom));
704e7ec2e32SMichael Buesch 	sprom->revision = 1;
705e7ec2e32SMichael Buesch 	sprom->boardflags_lo = 0;
706e7ec2e32SMichael Buesch 	sprom->boardflags_hi = 0;
707e7ec2e32SMichael Buesch 
708e7ec2e32SMichael Buesch 	/* First fetch the MAC address. */
70937ace3d4SDominik Brodowski 	res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
71037ace3d4SDominik Brodowski 				ssb_pcmcia_get_mac, sprom);
71137ace3d4SDominik Brodowski 	if (res != 0) {
712b8b6069cSMichael Büsch 		pr_err("PCMCIA: Failed to fetch MAC address\n");
71337ace3d4SDominik Brodowski 		return -ENODEV;
714e7ec2e32SMichael Buesch 	}
715e7ec2e32SMichael Buesch 
716e7ec2e32SMichael Buesch 	/* Fetch the vendor specific tuples. */
71737ace3d4SDominik Brodowski 	res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
718dd3cb633SMichael Büsch 				ssb_pcmcia_do_get_invariants, iv);
71937ace3d4SDominik Brodowski 	if ((res == 0) || (res == -ENOSPC))
72061e115a5SMichael Buesch 		return 0;
72137ace3d4SDominik Brodowski 
722b8b6069cSMichael Büsch 	pr_err("PCMCIA: Failed to fetch device invariants\n");
723e7ec2e32SMichael Buesch 	return -ENODEV;
724e7ec2e32SMichael Buesch }
725e7ec2e32SMichael Buesch 
ssb_sprom_show(struct device * pcmciadev,struct device_attribute * attr,char * buf)726*573f1af8SZhen Lei static ssize_t ssb_sprom_show(struct device *pcmciadev,
727e7ec2e32SMichael Buesch 			      struct device_attribute *attr,
728e7ec2e32SMichael Buesch 			      char *buf)
729e7ec2e32SMichael Buesch {
730e7ec2e32SMichael Buesch 	struct pcmcia_device *pdev =
731e7ec2e32SMichael Buesch 		container_of(pcmciadev, struct pcmcia_device, dev);
732e7ec2e32SMichael Buesch 	struct ssb_bus *bus;
733e7ec2e32SMichael Buesch 
734e7ec2e32SMichael Buesch 	bus = ssb_pcmcia_dev_to_bus(pdev);
735e7ec2e32SMichael Buesch 	if (!bus)
736e7ec2e32SMichael Buesch 		return -ENODEV;
737e7ec2e32SMichael Buesch 
738e7ec2e32SMichael Buesch 	return ssb_attr_sprom_show(bus, buf,
739e7ec2e32SMichael Buesch 				   ssb_pcmcia_sprom_read_all);
740e7ec2e32SMichael Buesch }
741e7ec2e32SMichael Buesch 
ssb_sprom_store(struct device * pcmciadev,struct device_attribute * attr,const char * buf,size_t count)742*573f1af8SZhen Lei static ssize_t ssb_sprom_store(struct device *pcmciadev,
743e7ec2e32SMichael Buesch 			       struct device_attribute *attr,
744e7ec2e32SMichael Buesch 			       const char *buf, size_t count)
745e7ec2e32SMichael Buesch {
746e7ec2e32SMichael Buesch 	struct pcmcia_device *pdev =
747e7ec2e32SMichael Buesch 		container_of(pcmciadev, struct pcmcia_device, dev);
748e7ec2e32SMichael Buesch 	struct ssb_bus *bus;
749e7ec2e32SMichael Buesch 
750e7ec2e32SMichael Buesch 	bus = ssb_pcmcia_dev_to_bus(pdev);
751e7ec2e32SMichael Buesch 	if (!bus)
752e7ec2e32SMichael Buesch 		return -ENODEV;
753e7ec2e32SMichael Buesch 
754e7ec2e32SMichael Buesch 	return ssb_attr_sprom_store(bus, buf, count,
755e7ec2e32SMichael Buesch 				    ssb_pcmcia_sprom_check_crc,
756e7ec2e32SMichael Buesch 				    ssb_pcmcia_sprom_write_all);
757e7ec2e32SMichael Buesch }
758e7ec2e32SMichael Buesch 
759*573f1af8SZhen Lei static DEVICE_ATTR_ADMIN_RW(ssb_sprom);
760e7ec2e32SMichael Buesch 
ssb_pcmcia_cor_setup(struct ssb_bus * bus,u8 cor)7619788ba75SMichael Buesch static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor)
7629788ba75SMichael Buesch {
7639788ba75SMichael Buesch 	u8 val;
7649788ba75SMichael Buesch 	int err;
7659788ba75SMichael Buesch 
7669788ba75SMichael Buesch 	err = ssb_pcmcia_cfg_read(bus, cor, &val);
7679788ba75SMichael Buesch 	if (err)
7689788ba75SMichael Buesch 		return err;
7699788ba75SMichael Buesch 	val &= ~COR_SOFT_RESET;
7709788ba75SMichael Buesch 	val |= COR_FUNC_ENA | COR_IREQ_ENA | COR_LEVEL_REQ;
7719788ba75SMichael Buesch 	err = ssb_pcmcia_cfg_write(bus, cor, val);
7729788ba75SMichael Buesch 	if (err)
7739788ba75SMichael Buesch 		return err;
7749788ba75SMichael Buesch 	msleep(40);
7759788ba75SMichael Buesch 
7769788ba75SMichael Buesch 	return 0;
7779788ba75SMichael Buesch }
7789788ba75SMichael Buesch 
7798fe2b65aSMichael Buesch /* Initialize the PCMCIA hardware. This is called on Init and Resume. */
ssb_pcmcia_hardware_setup(struct ssb_bus * bus)7808fe2b65aSMichael Buesch int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)
7818fe2b65aSMichael Buesch {
7828fe2b65aSMichael Buesch 	int err;
7838fe2b65aSMichael Buesch 
7848fe2b65aSMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
7858fe2b65aSMichael Buesch 		return 0;
7868fe2b65aSMichael Buesch 
7878fe2b65aSMichael Buesch 	/* Switch segment to a known state and sync
7888fe2b65aSMichael Buesch 	 * bus->mapped_pcmcia_seg with hardware state. */
7898fe2b65aSMichael Buesch 	ssb_pcmcia_switch_segment(bus, 0);
7908fe2b65aSMichael Buesch 	/* Init the COR register. */
7918fe2b65aSMichael Buesch 	err = ssb_pcmcia_cor_setup(bus, CISREG_COR);
7928fe2b65aSMichael Buesch 	if (err)
7938fe2b65aSMichael Buesch 		return err;
7948fe2b65aSMichael Buesch 	/* Some cards also need this register to get poked. */
7958fe2b65aSMichael Buesch 	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);
7968fe2b65aSMichael Buesch 	if (err)
7978fe2b65aSMichael Buesch 		return err;
7988fe2b65aSMichael Buesch 
7998fe2b65aSMichael Buesch 	return 0;
8008fe2b65aSMichael Buesch }
8018fe2b65aSMichael Buesch 
ssb_pcmcia_exit(struct ssb_bus * bus)802e7ec2e32SMichael Buesch void ssb_pcmcia_exit(struct ssb_bus *bus)
803e7ec2e32SMichael Buesch {
804e7ec2e32SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
805e7ec2e32SMichael Buesch 		return;
806e7ec2e32SMichael Buesch 
807e7ec2e32SMichael Buesch 	device_remove_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);
80861e115a5SMichael Buesch }
80961e115a5SMichael Buesch 
ssb_pcmcia_init(struct ssb_bus * bus)81061e115a5SMichael Buesch int ssb_pcmcia_init(struct ssb_bus *bus)
81161e115a5SMichael Buesch {
81261e115a5SMichael Buesch 	int err;
81361e115a5SMichael Buesch 
81461e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
81561e115a5SMichael Buesch 		return 0;
81661e115a5SMichael Buesch 
8178fe2b65aSMichael Buesch 	err = ssb_pcmcia_hardware_setup(bus);
818e7ec2e32SMichael Buesch 	if (err)
819e7ec2e32SMichael Buesch 		goto error;
820e7ec2e32SMichael Buesch 
821e7ec2e32SMichael Buesch 	bus->sprom_size = SSB_PCMCIA_SPROM_SIZE;
822e7ec2e32SMichael Buesch 	mutex_init(&bus->sprom_mutex);
823e7ec2e32SMichael Buesch 	err = device_create_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);
824e7ec2e32SMichael Buesch 	if (err)
82561e115a5SMichael Buesch 		goto error;
82661e115a5SMichael Buesch 
82761e115a5SMichael Buesch 	return 0;
82861e115a5SMichael Buesch error:
829b8b6069cSMichael Büsch 	pr_err("Failed to initialize PCMCIA host device\n");
830e7ec2e32SMichael Buesch 	return err;
83161e115a5SMichael Buesch }
832